R: using ellipsis argument (...)
Asked Answered
T

1

12

I want to create a wrapper function replacing some of the default arguments.

Here the core of the problem I'm struggling with:

Error in localWindow(xlim, ylim, log, asp, ...) : 
  formal argument "cex" matched by multiple actual arguments

Now a bit of a context. Suppose I define a wrapper function for plot like this:

myplot <- function(x, ... ) {
    plot(x, cex= 1.5, ... )
}

If I call myplot( 1:10, cex= 2 ) I will get the above error. I know I can turn ... to a list

l <- list(...)

and then I could do

if( is.null( l[["cex"]] ) ) l[["cex"]] <- 2

However, how can I "insert" this list back to the ellipsis argument? Something like (I know this won't work):

... <- l

EDIT: I could use defaults in myplot definition (as suggested in the answer from @Thomas), but I don't want to: the function interface will become cluttered. I guess I could define a helper function like that:

 .myfunchelper <- function( x, cex= 2.0, ... ) {
   plot( x, cex= cex, ... )
 }

 myfunc <- function( x, ... ) {
    .myfunchelper( x, ... )
 }

But (i) it is less elegant and (ii) doesn't satisfy my curiosity.

Tristantristas answered 30/6, 2013 at 12:11 Comment(1)
Thank you, very important question, which I was now solving too! Incredible that I was just able to find it googling "R use argument in ... to override" :-)Membrane
T
17

AN ACTUAL ANSWER:

You can do this through a bit of trickery. First, define your function as before, but include a list with your default arguments inside the function. Then you can parse whatever arguments come in through ... as a list, replace the defaults with anything in ... and then pass the updated list of arguments through do.call.

myplot <- function(x, ...) {
    args1 <- list(cex=4, main="Default Title") # specify defaults here
    inargs <- list(...)
    args1[names(inargs)] <- inargs
    do.call(plot, c(list(x=x), args1))
}

myplot(x=1:3) # call with default arguments
myplot(x=1:3, cex=2, main="Replacement", xlab="Test xlab") # call with optional arguments

EARLIER COMMENTARY:

The problem here can be seen through a few example functions:

myplot1 <- function(x, ... ) {
    plot(x, cex= 1.5, ... )
}

myplot2 <- function(x, cex=3, ... ) {
    plot(x, cex=cex, ... )
}

myplot3 <- function(x, ... ) {
    plot(x, ... )
}

myplot1(1:3, cex=3) # spits your error
myplot2(1:3, cex=3) # works fine
myplot3(1:3, cex=3) # works fine

In myplot2, you specify a default value of cex but can change it. In myplot3, cex is simply passed through. If you run myplot2 with two cex arguments, you'll see what's happening with your function (myplot1):

myplot2(1:3, cex=3, cex=1.5) # same error as above

So, you're probably best to avoid setting any defaults in plot(), so then you can pass anything through the ... in myplot.

Timmy answered 30/6, 2013 at 12:15 Comment(4)
Yeah, but this is precisely what I want to avoid. The real problem is complex, and I don't want to put the defaults in the function call definition -- there are way too many arguments already.Tristantristas
I've updated based on answers from: #7028885Timmy
Very nice answer. I have encountered the same error. I solved my problem, changing the value of some parameters in the ellipse, based on your answer: param = list(...); cost = param[["cost"]]; gamma = param[["gamma"]]; # -> tune cost and gamma -> args1 <- list(cost=bestcost, gamma=bestgamma); param[names(args1)] <- args1; result = do.call(trainSVM, c(list(x = x, y = y), param));Fibrilliform
Great answer (thanks!), but much better to use args1 <- modifyList(args1, list(...)). Because args1[names(inargs)] <- inargs would not work if ... contains some additional arguments not present in the default args1.Membrane

© 2022 - 2024 — McMap. All rights reserved.