Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing expressions to curve() within a function

Tags:

r

A colleague asked me this, and I have struggled with it.

Suppose I want to define a function that takes an expression (let's say x^2 for concreteness) as an argument and passes that argument to curve().

If I want to do this the easy way, I just run

curve(x^2,from=0,to=3)

and it works fine.

Suppose I try to set up a wrapper function (let's say there are other things I want to do inside the wrapper in addition to plotting the curve):

f <- function(g) {
    curve(g,from=0,to=3)
}

This works if I pass a function:

f(function(x) x^2)

it fails if I try to pass x^2, when R tries to evaluate the expression:

f(x^2)
## Error in eval(expr, envir, enclos) (from #2) : object 'x' not found

I can try to forestall this by using substitute within the function:

f0 <- function(g) {
    str(substitute(g))
    curve(substitute(g),from=0,to=3)
}
f0(x^2)
## language x^2
## Error in curve(substitute(g), from = 0, to = 3) (from #3) : 
##  'expr' must be a function, or a call or an expression containing 'x'

OK, that suggests maybe I should try

f <- function(g) {
    h <- as.expression(substitute(g))
    str(h)
    curve(as.expression(substitute(g)),from=0,to=3)
}
f(x^2)
##  expression(x^2)
## Error in curve(as.expression(substitute(g)), from = 0, to = 3) (from #4) : 
##  'expr' must be a function, or a call or an expression containing 'x'

For what it's worth,

  • this fails differently with curve(h,...) ("function h not found")
  • it fails in the same way if as.call() is substituted for as.expression()
  • curve() doesn't work on expressions in any case:

curve(expression(x^2),from=0,to=1)
## Error in curve(expression(x^2), from = 0, to = 1) : 
##   'expr' did not evaluate to an object of length 'n'

If I try debugging curve() to see what's happening, we have:

sexpr <- substitute(expr)
...
if (!((is.call(sexpr) || is.expression(sexpr)) && xname %in% 
    all.vars(sexpr))) 
    stop(...)

Here sexpr is substitute(g), which fails the xname %in% all.vars(sexpr) test ...

Any ideas about how to handle this?

like image 730
Ben Bolker Avatar asked Dec 30 '14 23:12

Ben Bolker


1 Answers

I didn't mean to ask-and-then-answer, but I figured out the (an?) answer with a little bit more poking around -- it occurred to me that I hadn't tried eval yet. eval(curve(substitute(g),from=0,to=3)) does not work, but this does:

f1 <- function(g) {
     eval(substitute(curve(g,from=0,to=3)))
}
f1(x^2)

update: @RichardScriven suggests that do.call() might work too -- and it does!

f2 <- function(g) {
    do.call(curve,list(substitute(g),from=0,to=3))
}
f2(x^2)

Further explication is welcome!

like image 200
Ben Bolker Avatar answered Oct 01 '22 08:10

Ben Bolker