How to change R plot default options - r

I'd like to change default plot option from type = "p" to type = "l" ; I mean I want it is like that at the beginning of each new session, without specifying it any more.
I've tried to put some piece of code in my Rprofile.site but unfortunately not the right one: firstly I wanted to use setDefaults but this package is deprecated; I also tried to set a hook but couldn't make it work.
Any ideas ?
thanks !

This could be done by adding to your Rprofile
formals(plot.default)$type <- "l"
But that would be highly discouraged, for the reasons Roland states in his comment. A better solution would be to place this in your Rprofile:
lplot <- function(x, y, type = "l", ...){
plot(x, y, type = type, ...)
}
This gives you the default you want, the ability to revert back to normal if wanted, and doesn't affect the existing plot function.
But this still comes with the downside of the lplot function seemingly appearing out of nowhere. Far better would be to put lplot in a package. Even if you load the package in the Rprofile, at least ?lplot will pull up something to indicate where it came from.

Related

Removing/de-registering a specific function from an R package

I may not be using the terminology correctly here so please forgive me...
I have a case of one package 'overwriting' a function with the same name loaded by another package and thus changing the behavior (breaking) of a function.
The specific case:
X <- data.frame ( y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100) )
library(CausalImpact)
a <- CausalImpact::CausalImpact( X, c(1,75), c(76, 100) ) # works
library(bfast) # imports quantmod which loads crappy version of as.zoo.data.frame
b <- CausalImpact::CausalImpact( X, c(1,75), c(76, 100) ) # Error
I know the error comes from two versions of the function as.zoo.data.frame.
The problematic version is imported by bfast from the package 'quantmod' (see https://github.com/joshuaulrich/quantmod/issues/168). Unfortunately their hotfix did not prevent this error. Super annoying.
I can hack around this specific problem, but I was wondering if there is a general way to like 'de-register' this function variant from the search path. Neither detach nor unloadNamespace remove the offending function (same behavior after). An explanation and similar problem is discussed here and here, but I wasn't able to find a general solution. For instance I'd rather just remove this function than clone and re-write CausalImpact to deal with this behavior.
From R 3.6.0 onwards, there is a new option called "conflicts.policy" to handle this within an established framework. For small issues like this, you can use the new arguments to library(). If you aren't yet to 3.6, the easiest solution might be to explicitly namespace CausalImpact when you need it, i.e. CausalImpact::CausalImpact. That's a mouthful, so you could do causal_impact <- CausalImpact::CausalImpact and use that alias.
# only attach select
library(dplyr, include.only = "select")
# exclude slice/arrange from being attached.
library(dplyr, exclude = c("slice", "arrange"))
library(bfast, exclude = "CausalImpact") should solve your problem.
Attach means that they are available for use without explicit prefixing with their package. In either of these cases, something like dplyr::slice would work just fine.
For more information, you can see ?library. Also, the R-Core member Luke Tierney wrote a blog explaining how the conflicts.policy works. You can find that here
Here's an answer that works, but is less preferable than de-registering a S3 method because it involves replacing the registered version in the S3 Methods table with the desired method:
library(CausalImpact)
library(bfast)
assignInNamespace("as.zoo.data.frame", zoo:::as.zoo.data.frame, ns = asNamespace("zoo"))
based partially on #smingerson's suggestion in the comments

Editing a function in R using trace?

I noticed there is a bug in a function from a package I want to use. An issue has been made on GitHub, but the creator hasn't adressed this yet, and I need the function as soon as possible.
Therefore I want to edit the code. Apparently this is possible by editing the source, repacking and installing the entire package, I can rewrite the function and reassign the namespace, but also possibly by just editing the function in the current session using trace().
I already found out I can do:
as.list(body(package:::function_inside_function))
The line I want to edit is located in the second step of the function.
Specifically, it is this line in the code I need to edit. I have to change ignore.case to ignore.case=TRUE. An example in case the link dies:
functionx(){if{...} else if(grepl("miRNA", data.type, ignore.case)) {...}}
I haven't really found a practical example on how to proceed from here, so can anyone show me an example of how to do this, or lead me to a practical example of using trace? Or perhaps reassigning the function to the namespace?
For your specific case, you could probably indeed work around it using trace.
From the link you provide I don't know why you speak of a function inside a function, but this should work:
# example
trace("grepl", tracer = quote(ignore.case <- TRUE))
grepl("hi", "Hi")
## Tracing grepl("hi", "Hi") on entry
## [1] TRUE
# your case (I assume)
trace("readTranscriptomeProfiling", tracer = quote(ignore.case <- TRUE))
Note that this would be more complicated if the argument ignore.case that you want to fix wasn't already at the right position in the call.
I faced a similar problem once and solved it using assignInNamespace(). I don't have your package installed so I cannot be sure this will work for you, but I think it should. You would proceed as follows:
Make the version of the function you want, as edited:
# I would just copy the function off github and change the offending line
readTranscripttomeProfiling <- function() {"Insert code here"}
# Get the problematic version of the function out of the package namespace
tmpfun <- get("readTranscripttomeProfiling",
envir = asNamespace("TCGAbiolinks"))
# Make sure the new function has the environment of the old
# function (there are possibly easier ways to do this -- I like
# to get the old function out of the namespace to be sure I can do
# it and am accessing what I want to access)
environment(readTranscripttomeProfiling) <- environment(tmpfun)
# Replace the old version of the function in the package namespace
# with your new version
assignInNamespace("readTranscripttomeProfiling",
readTranscripttomeProfiling, ns = "TCGAbiolinks")
I found this solution in another StackOverflow response, but cannot seem to find the original at the moment.

Modifying an R package function for current R session; assignInNamespace not behaving like fixInNamespace?

I would like to be able to modify a hidden function inside an R package in an "automated" way, like using fixInNamespace, but where I can write the code in advance, and not in an "edit" window which fixInNamespace does. I think assignInNamespace could do the job, but currently it's not working. Here's an example of the problem.
require(quantmod)
getSymbols("AAPL")
chartSeries(AAPL) # Works fine up to here.
Now say I want to yaxis ticks to be drawn on the left side of the plot, instead of the right. This can be done by modifying the source code in the quantmod package. The relevant code for modifying the plot layout is in a hidden quantmod function called chartSeries.chob.
This could be done by doing this:
fixInNamespace("chartSeries.chob", ns = "quantmod")
and in the edit window, manually modify line 117 from axis(4) to axis(2), click OK, and again run chartSeries(AAPL) (now the y axis labels will plot on the left side of the plot). Everything is good, the plot is generated as expected, no problems.
But ... now suppose I want to modify chartSeries.chob in advance (in an automated way), presumably by sourcing a modified version of the chartSeries.chob function, without using the edit window. I might want modify dozens of lines in the function for example, and opening the edit window each time for a new R session is not practical.
How can I do this?
Right now I am doing this, which is not working:
assignInNamespace("chartSeries.chob", value = chartSeries.chob2, ns = "quantmod")
where I source from the console a full copy of chartSeries.chob with the modified code on line 117.
chartSeries.chob2 <- function (x)
{
old.par <- par(c("pty", "mar", "xpd", "bg", "xaxs", "las",
"col.axis", "fg"))
on.exit(par(old.par))
....
[Edit On 117:] axis(2)
...
}
When I run from the console:
chartSeries(AAPL)
or
quantmod:::chartSeries(AAPL)
I get errors -- the calls to other functions in quantmod from within the chartSeries.chob function are not found, presumably because the edited chartSeries.chob function is not in the quantmod namespace?
I notice that when typing quantmod:::chartSeries.chob from the console after the assignInNamespace command, there is no environment: namespace:quantmod at the end of the function definition.
But if I do the fixInNamespace modification approach, when I type quantmod:::chartSeries.chob, then I do see environment: namespace:quantmod appended to the end of the function definition.
Since fixInNamespace calls assignInNamespace you should be able to get it to work, the problem is probably that the environment is not the same and possibly some other attributes. If you change those to match then I would expect it to work better, possibly using code like:
tmpfun <- get("chartSeries.chob", envir = asNamespace("quantmod"))
environment(chartSeries.chob2) <- environment(tmpfun)
attributes(chartSeries.chob2) <- attributes(tmpfun) # don't know if this is really needed
assignInNamespace("chartSeries.chob", chartseries.chob2, ns="quantmod")
Another option for some changes would be to use the trace function. This would make temporary changes and would be fine for inserting code, but I don't know if it would be reasonable for deleting commands or modifying in place (specifying an editor that changed the code rather than letting you change it might make this possible).

Changing defaults in a function inside a locked package [duplicate]

This question already has answers here:
Setting Function Defaults R on a Project Specific Basis
(2 answers)
Closed 9 years ago.
I am developing my first package and it is aimed at users who are new to R, so I am trying to minimize the amount of R skills required to use the package. As a result I want a function that changes defaults in other functions within my package. But I get the following error "cannot add bindings to a locked environment", which means the environment of the package is locked and I am not allowed to change the default values of its functions.
Here is an example that throws a similar error:
library(ggplot2)
assign(formals(geom_point)$position, "somethingelse", pos="package:ggplot2")
When I try assignInNamespace i get:
Error in bindingIsLocked(x, ns) : no binding for "identity"
assignInNamespace(formals(geom_point)$position,"somethingelse", pos = "package:ggplot2")
Here is an example of what I hope to achieve.
default <- function(x=c("A", "B", "C")){
x
}
default()
change.default <- function(x){
formals(default)$x <<- x # Notice the global assign
}
change.default(1:3)
default()
I am aware that this is far from the recommended approach, but I am willing to cut corners to improve the learning curve of the package. Is there a way to achieve this?
This question has been marked as a duplicate of Setting Function Defaults R on a Project Specific Basis. This is a different situation as this question concerns how to allow the user in a interactive session to change the defaults of a function - not how to actually do it. The old question could not have been solved with the options() function and it is therefore a different question.
I think the colloquial way to achieve what you want is via option and packages in fact do so, e.g., lattice (although they use special options) or ascii.
Furthermore, this is also done so in base R, e.g., the famous and notorious default for stringsAsFactors.
If you look at ?read.table or ?data.frame you get: stringsAsFactors = default.stringsAsFactors(). Inspecting this reveals:
> default.stringsAsFactors
function ()
{
val <- getOption("stringsAsFactors")
if (is.null(val))
val <- TRUE
if (!is.logical(val) || is.na(val) || length(val) != 1L)
stop("options(\"stringsAsFactors\") not set to TRUE or FALSE")
val
}
<bytecode: 0x000000000b068478>
<environment: namespace:base>
The relevant part here is getOption("stringsAsFactors") which produces:
> getOption("stringsAsFactors")
[1] TRUE
Changing it is achieved like this:
> options(stringsAsFactors = FALSE)
> getOption("stringsAsFactors")
[1] FALSE
To do what you want your package would need to set an option, and the function take it's values form the options. Another function could then change the options:
options(foo=c("A", "B", "C"))
default <- function(x=getOption("foo")){
x
}
default()
change.default <- function(x){
options(foo=x)
}
change.default(1:3)
default()
If you want your package to set the options when loaded, you need to create a .onAttach or .onLoad function in zzz.R. My afex package e.g., does this and changes the default contrasts. In your case it could look like the following:
.onAttach <- function(libname, pkgname) {
options(foo=c("A", "B", "C"))
}
ascii does it via .onLoad (I don't remember what is the exact difference, but Writing R Extensions will help).
Preferably, a function has the following things:
Input arguments
A function body which does something with those arguments
Output arguments
So in your situation where you want to change something about the behavior of a function, changing the input arguments in the best way to go. See for example my answer to another post.
You could also use an option to save some global settings (e.g. which font to use, which PATH the packages you use are stored), see the answer of #James in the question I linked above. But use these things sparingly as it makes the code hard to read. I would primarily use them read only, i.e. set them once (either by the package or the user) and not allow functions to change them.
The unreadability stems from the fact that the behavior of the function is not solely determined locally (i.e. by the code directly working with it), but also by settings far away. This makes it hard to determine what a function does by purely looking at the code calling it, but you have to dig through much more code to fully understand what is going on. In addition, what if other functions change those options, making it even harder to predict what a given function will do as it depends on the history of functions. And here comes my earlier recommendation for read-only options back into play, if these are read only, some of the problems about readability are lessened.

Access (exporting) function from namespace

I know something similar has been asked before here on SO, but the solution given there doesn't seem to apply in my case.
I'm trying to follow convention in creating a package by referring to functions exported from other namespaces and avoiding use of require() within a function.
I'm basically trying to prevent a function taking too long to run. For example,
fun <- function(i){
require(R.utils)
setTimeLimit(elapsed=10, transient=TRUE) # prevent taking more than 10secs
return(i^i)
}
>fun(10)
Works fine, but if I try:
require(R.utils)
fun <- function(i){
R.utils:::setTimeLimit(elapsed=10, transient=TRUE) # prevent taking more than 10secs
return(i^i)
}
>fun(10)
I get:
Error in get(name, envir = asNamespace(pkg), inherits = FALSE) :
object 'setTimeLimit' not found
Changing ::: to :: doesn't change this behavior.
I'm open to any simpler methods to achieving the same objective.
Also is it really so bad to have require() calls inside a function?
Many thanks!
EDIT:
If import works then great, thanks. Still in development so wanted to make sure it would be OK.
EDIT:
Apologies, it's there in base. Not sure how I missed this; I was originally using R.utils::evalWithTimeout and must have assumed both were in the same package. *looks sheepish*
I'm just posting this to prevent the question from showing up as unanswered, but will be glad to accept another...
isTRUE("setTimeLimit" %in% ls(getNamespace("base"), all.names=TRUE))

Resources