**From the bottom of the heap » R**, and kindly contributed to R-bloggers)

Argument passing via `...`

is a great feature of the R language, allowing you to write wrappers around existing functions that do not need to list all the arguments of the wrapped function. `...`

is used extensively in S3 methods and in passing graphical parameters on to graphical functions. When writing you own plot methods, using `...`

allows the user of your function to pass arguments like `cex`

, `col`

, `lty`

, etc. on to the plotting function inside your method. You do, however, need to be careful in where you use `...`

and which functions you pass `...`

on to.

Consider the following object `FOO`

that is a data frame with our own class `"foo"`

FOO <- data.frame(x = 1:10, y = 1:10) rownames(FOO) <- LETTERS[1:10] class(FOO) <- "foo"

A simplified `plot()`

method to plot the `x`

and `y`

components of our object, displaying the data as points or text labels might be:

plot.foo <- function(X, type = c("points","text"), ...) { x <- X$x y <- X$y type <- match.arg(type) plot(x, type = "n", ...) if(type == "points") { points(x, y, ...) } else { text(x, y, labels = rownames(x), ...) } invisible(x) }

Note that we are passing `...`

on to each of `plot()`

, `points()`

, and `text()`

so our method is very simple. However, if we try to suppress the drawing of axes using the `axes`

argument of `plot.default()`

, our method will generate errors

> plot(FOO, axes = FALSE) Warning message: In plot.xy(xy.coords(x, y), type = type, ...) : "axes" is not a graphical parameter

Turning warnings into errors, we see that the call to `points()`

is where the warning originates (actually in `plot.xy()`

, frame 5, but `points()`

is the offending code in our method)

> options(warn = 2) ## turn warnings to errors > > plot(FOO, axes = FALSE) Error in plot.xy(xy.coords(x, y), type = type, ...) : (converted from warning) "axes" is not a graphical parameter > ## look at the call stack > traceback() 9: doWithOneRestart(return(expr), restart) 8: withOneRestart(expr, restarts[[1L]]) 7: withRestarts({ .Internal(.signalCondition(simpleWarning(msg, call), msg, call)) .Internal(.dfltWarn(msg, call)) }, muffleWarning = function() NULL) 6: .signalSimpleWarning("\"axes\" is not a graphical parameter", quote(plot.xy(xy.coords(x, y), type = type, ...))) 5: plot.xy(xy.coords(x, y), type = type, ...) 4: points.default(x, y, ...) 3: points(x, y, ...) 2: plot.foo(FOO, axes = FALSE) 1: plot(FOO, axes = FALSE)

The warning results from our function passing `axes = FALSE`

on to the lower-level plotting functions.

An obvious solution is to process `...`

and strip out any offending non-graphical parameters and then arrange for the calls to use the stripped out `...`

. Doing this is possible, but is very complicated. There is an alternative, simpler solution that is used in several base R functions and suggested to me by Brian Ripley (when I asked about doing this on R-Help for a function in the vegan package). The trick is to have a local, in-line wrapper around `points()`

of the following form:

lPoints <- function(..., log, axes, frame.plot, panel.first, panel.last) { points(...) }

Here we list all the arguments of `plot.default()`

we *don’t* want passed on to the low-level plotting calls, but importantly, they are listed *after* `...`

. The only code in the body of the local function is a call to the low-level graphics function we want to use. Importantly, of the arguments taken by `lPoints()`

only `...`

is passed on to the graphics function it wraps. Because the arguments from `plot.default()`

are named and come after `...`

in the definition of `lPoints()`

, any arguments passed to `lPoints()`

that fully match the named arguments are automatically stripped from the `...`

that is passed on to the wrapped function.

Using this trick, we can now write our `plot.foo()`

method like this:

plot.foo <- function(X, type = c("points","text"), ...) { lPoints <- function(..., log, axes, frame.plot, panel.first, panel.last) points(...) lText <- function(..., log, axes, frame.plot, panel.first, panel.last) text(...) x <- X$x y <- X$y type <- match.arg(type) plot(x, type = "n", ...) if(type == "points") { lPoints(x, y, ...) } else { lText(x, y, labels = rownames(x), ...) } invisible(x) }

Now we can pass arguments to both `plot.default()`

and `points()`

and `text()`

, and the call that raised the warning earlier, now works without complaint:

> plot(FOO, axes = FALSE) >

Remember to reset the warning level if you followed the code above

options(warn = 0)

**leave a comment**for the author, please follow the link and comment on his blog:

**From the bottom of the heap » R**.

R-bloggers.com offers

**daily e-mail updates**about R news and tutorials on topics such as: visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...