tags:

views:

86

answers:

1

I have the following code snippet:

require(lattice)
f.barchart <- function(...) {
    barchart(...,
        panel = function(x, y, ...) {
            panel.barchart(x, y, ...)
        }
    )
}

x <- data.frame(a = c(1,1,2,2), b = c(1,2,3,4), c = c(1,2,2,1))
f.barchart(a ~ b, data = x, groups = c)

Which results in the following error being thrown:

..3 used in an incorrect context, no ... to look in

When I use the following definition:

f.barchart <- function(...) {
    substitute(barchart(...,
        panel = function(x, y, ...) {
            panel.barchart(x, y, ...)
        }
    ))
}

I get:

barchart(a ~ b, data = x, groups = c,
    panel = function(x, y, ...) {
        panel.barchart(x, y, a ~ b, data = x, groups = c)
    })

I'm not sure if this is the cause of above error but this would mean that the ellipsis in panel.barchart gets wrongly expanded with the contents of the arguments given to f.barchart and not the panel function.

Is there a way to avoid this problem? How can I make the function work?

+3  A: 

As far as I understand, this happens not because of the nested ... but because of the first ... in barchart. So even this does not work:

f.barchart <- function(...) {
    barchart(...)
}

x <- data.frame(a = c(1,1,2,2), b = c(1,2,3,4), d = c(1,2,2,1))
print(f.barchart(a ~ b, data = x, groups = d))

I think this is because ... is a pairlist while barchart is expecting individual arguments. We need to unpack the pairlist, while making sure that we do not evaluate it too soon. The following is my solution:

f.barchart <- function(...) {
  cl<-match.call()
  cl$panel=function(x, y, ...) {
            panel.barchart(x, y, ...)
          }
  cl[[1]]=barchart
  eval(cl)
}

We capture the call to f.barchart using match.call which expands the dots, add the panel argument to the call, set the function to be called to barchart and then evaluate the call. Just as we added the panel argument, we could delete arguments which are used by f.barchart but which do not need to be passed to barchart.

Jyotirmoy Bhattacharya
Thanks a lot. There is only one minor modification I had to make: it seems necessary to use eval.parent instead of eval. My function now looks like this: f.barchart <- function(...) { cl <- f.merge.list(as.list(match.call()), list(MYOPTIONS)) cl[[1]] = barchart eval.parent(as.call(cl)) }Where f.merge.list is: f.merge.list <- function(a, b) { c(a, b[!names(b) %in% names(a)]) }
lith