Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy Evaluation: Why can't I use plot(..., xlim = c(0,1), ylim = xlim)?

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
  • Does anybody know why?
  • Is there a way to still achieve this?
like image 527
Henrik Avatar asked May 22 '14 22:05

Henrik


2 Answers

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
like image 154
Josh O'Brien Avatar answered Nov 17 '22 12:11

Josh O'Brien


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))
like image 39
merlin2011 Avatar answered Nov 17 '22 12:11

merlin2011