One of R
's greatest feature is lazy evaluation. This leads to the often encountered style that one can use an arguments as the value of another arguments. For example, in Hadley's great book on Advanced R you see this example:
g <- function(a = 1, b = a * 2) {
c(a, b)
}
g()
#> [1] 1 2
g(10)
#> [1] 10 20
Now, I would like to do the same for plot with xlim
and ylim
, however, it is not working:
> plot(1, 1, ylim = c(0,1), xlim = ylim)
Error in plot.default(1, 1, ylim = c(0, 1), xlim = ylim) :
object 'ylim' not found
> plot(1, 1, xlim = c(0,1), ylim = xlim)
Error in plot.default(1, 1, xlim = c(0, 1), ylim = xlim) :
object 'xlim' not found
Quoting from the good manual:
4.3.3 Argument evaluation
One of the most important things to know about the evaluation of arguments to a function is that supplied arguments and default arguments are treated differently. The supplied arguments to a function are evaluated in the evaluation frame of the calling function. The default arguments to a function are evaluated in the evaluation frame of the function.
To see what that means in practice, create a function in which one argument's default value is a function of another argument's value:
f <- function(x=4, y=x^2) {
y
}
When called with y
's default value, R looks to evaluate y
in the evaluation frame of the function call, i.e. in the same environment in which the entire body of the function gets evaluated -- a place where x
had very well better (and of course does) exist:
f()
# [1] 16
When called with a supplied value of y
, R looks in the evaluation frame of the calling function (here the global environment), finds no x
, and lets you know so in its error message:
f(y=x^2)
# Error in f(y = x^2) : object 'x' not found
There is a scoping issue here. In the statement plot(1, 1, ylim = c(0,1), xlim = ylim)
, the name ylim
is only available as the name of a parameter and is not available to the caller in general.
For a variable to be used on the right hand side of the assignment, it must be available in the calling scope.
The reason your first example works is because you are writing default arguments into your function definition, which does have access to all the parameters.
One possible workaround, which only makes sense if this is the same default you want in a lot of cases, is to wrap the plot function in a new function that has this behavior.
myplot <- function(x, y, ylim, xlim = ylim,...) {
plot(x,y, ylim = ylim, xlim = xlim,...)
}
myplot(1,1, ylim=c(0,1))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With