I'm trying to modify the dots (...) inside a custom function. Here's a simplified example of my plot2
function, which displays a plot onscreen with type="p"
(the default) and saves an svg with type="l"
. The problem surfaces when one of the ...
plot options is already in the function. In this example, "type"
is matched by multiple actual arguments.
plot2 <-function(...){
plot(...) #visible on screen
svg("c:/temp/out.svg") #saved to file
plot(...,type="l")
dev.off()
}
#This works
plot2(1:10)
#This does not work because type is redefined
plot2(1:10, type="o")
I have tried to put the dots in a list
inside the function and modify it, but plot
does not accept a list as an input.
#Does not work
plot2 <-function(...){
plot(...)
dots <<-list(...)
print(dots)
if("type" %in% names(dots)) dots$type="l"
print(dots)
svg("c:/temp/out.svg")
plot(dots)
dev.off()
}
plot2(1:10, type="o")
Error in xy.coords(x, y, xlabel, ylabel, log) :
'x' is a list, but does not have components 'x' and 'y'
In cases where you want to forward a modified version of ...
, you need to do two things:
do.call
.This works as follows:
plot2 = function (...) {
# capture:
dots = list(...)
# modify:
dots$type = 'l'
# forward call:
do.call(plot, dots)
}
In general, do.call(f, list(‹…›))
is equivalent to f(‹…›)
.
For what you want, there is a simpler (and better) way, and you do not need to touch to ...
. By explicitly defining the arguments that need a special treatment, you take them out of the catch all ...
. This is also a sane approach that is more explicit about what the function does (in its formal arguments). Here is how to do it:
plot2 <- function(x, type = "p", ...) {
plot(x, type = type, ...) #visible on screen
svg("out.svg") #saved to file
plot(x, ..., type = "l")
dev.off()
}
plot2(1:10)
plot2(1:10, type = "o")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With