有没有办法在R中的函数中使用两个“…”语句?

我想写一个调用plot()legend()的函数,如果用户可以指定一些额外的参数,然后传递给plot()legend() ,这将是理想的。 我知道我可以实现这两个function之一使用...

 foo.plot <- function(x,y,...) { plot(x,y,...) legend("bottomleft", "bar", pch=1) } foo.plot(1,1, xaxt = "n") 

这通过xaxt = "n"来绘制。 但是有没有办法例如传递title = "legend"legend()调用,而不需要预先指定函数头中的参数?


从接受的答案更新:我认为,VitoshKa的方式是最高雅的完成我想要的。 然而,我还有一些小问题需要解决,直到按照我的意愿工作。

起初,我检查了哪些参数要传递给legend ,哪些要plot 。 为此,第一步是查看legend哪些参数是legend唯一的,而不是图和/或参数的一部分:

 legend.args <- names(formals(legend)) plot.args <- c(names(formals(plot.default)), names(par())) dput(legend.args[!(legend.args %in% plot.args)]) 

我在这里使用dput() ,因为plot.args <- c(names(formals(plot.default)), names(par()))总是调用一个我不想要的新的空图。 所以,我在下面的函数中使用了dput的输出。

接下来,我必须处理重叠的参数(通过dput(largs.all[(largs.all %in% pargs.all)]) )获取它们。 对于一些这是微不足道的(例如, xy )其他人得到传递给两个函数(例如, pch )。 但是,在我的真实应用程序中,我甚至使用其他策略(例如,不同的variables名称为adj ,但在本例中没有实现)。

最后, do.call函数必须以两种方式进行更改。 首先,什么部分(即所谓的function)需要是一个angular色(即'plot'而不是plot )。 而参数列表必须构造稍微不同。

 foo.plot <- function(x,y,...) { leg.args.unique <- c("legend", "fill", "border", "angle", "density", "box.lwd", "box.lty", "box.col", "pt.bg", "pt.cex", "pt.lwd", "xjust", "yjust", "x.intersp", "y.intersp", "text.width", "text.col", "merge", "trace", "plot", "ncol", "horiz", "title", "inset", "title.col", "title.adj") leg.args.all <- c(leg.args.unique, "col", "lty", "lwd", "pch", "bty", "bg", "cex", "adj", "xpd") dots <- list(...) do.call('plot', c(list(x = x, y = x), dots[!(names(dots) %in% leg.args.unique)])) do.call('legend', c(list("bottomleft", "bar"), dots[names(dots) %in% leg.args.all])) } foo.plot(1,1,pch = 4, title = "legendary", ylim = c(0, 5)) 

在这个例子中, pch传递给plotlegendtitle只传递给legend ,而ylim只传递给plot


更新2根据Gavin Simpson的评论(另见Vitoshka的回答):
(i)这是正确的。
(二)它可以永远是一个字符。 但是如果你有一个和函数同名的variables,那么你需要引用do.call的函数名:

 min.plot <- function(x,y,plot=TRUE) if(plot == TRUE) do.call(plot, list(x = x, y = y)) min.plot(1,1) Error in do.call(plot, list(x = x, y = y)) : 'what' must be a character string or a function 

(iii)你可以使用c(x = 1, y = 1, list()) ,它工作正常。 但是,我真正做的(不是在我给出的例子中,而是在我的实际函数中)如下: c(x = 1, y = 1, xlim = c(0, 2), list(bla='foo'))
请将它与下列内容进行比较: c(list(x = 1, y = 1, xlim = c(0, 2)), list(bla='foo'))
在第一种情况下,列表包含两个元素xlimxlim1xlim2 (每个标量),在后一种情况下,列表只有xlim (这是长度为2的向量,这是我想要的)。

所以,你们对我的榜样是正确的。 但是,对于我的实际function(有更多的variables),我遇到了这些问题,并希望在这里logging它们。 抱歉不准确。

一种自动方式:

 foo.plot <- function(x,y,...) { lnames <- names(formals(legend)) pnames <- c(names(formals(plot.default)), names(par())) dots <- list(...) do.call('plot', c(list(x = x, y = x), dots[names(dots) %in% pnames])) do.call('legend', c("bottomleft", "bar", pch = 1, dots[names(dots) %in% lnames])) } 

在用户提供“pch”的情况下,必须从lnames中过滤pch以避免legend调用中的重复,但是你明白了。 Carl W 2012年1月编辑:“do.call”仅适用于引号中的函数,就像Henrik的更新一样。 我在这里编辑它,以避免将来的混乱。

这些事情变得棘手,没有在你的函数中指定额外的参数是不容易的解决scheme。 如果你在plotlegend调用中遇到了legend特定参数,你最终会得到警告。 例如,用:

 foo.plot <- function(x,y,...) { plot(x,y,...) legend("bottomleft", "bar", pch = 1, ...) } 

您会收到以下警告:

 > foo.plot(1, 1, xjust = 0.5) Warning messages: 1: In plot.window(...) : "xjust" is not a graphical parameter 2: In plot.xy(xy, type, ...) : "xjust" is not a graphical parameter 3: In axis(side = side, at = at, labels = labels, ...) : "xjust" is not a graphical parameter 4: In axis(side = side, at = at, labels = labels, ...) : "xjust" is not a graphical parameter 5: In box(...) : "xjust" is not a graphical parameter 6: In title(...) : "xjust" is not a graphical parameter 

有问题绕过这个问题,请参阅plot.default和它的本地函数定义为函数,如axisbox等函数包装,你会像localPlot()包装,内联函数和调用,而不是直接plot()直接。

 bar.plot <- function(x, y, pch = 1, ...) { localPlot <- function(..., legend, fill, border, angle, density, xjust, yjust, x.intersp, y.intersp, text.width, text.col, merge, trace, plot = TRUE, ncol, horiz, title, inset, title.col, box.lwd, box.lty, box.col, pt.bg, pt.cex, pt.lwd) plot(...) localPlot(x, y, pch = pch, ...) legend(x = "bottomleft", legend = "bar", pch = pch, ...) } 

(相当为什么'plot'参数需要一个默认是超出我的,但它不会工作,没有给它默认的TRUE 。)

现在这个工作没有任何警告:

 bar.plot(1, 1, xjust = 0.5, title = "foobar", pch = 3) 

如何处理像bty这样的graphics参数将取决于你 – bty将影响btytypes和图例框types。 还要注意,我处理'pch'不同,因为如果有人在bar.plot()调用中使用了这个参数,那么你将会在图例中使用不同的字符,并且会得到一个关于'pch'匹配两次。

正如你所看到的,这开始变得非常棘手。


Joris的答案提供了一个有趣的解决scheme,我lme()这样的函数中的控制列表参数。 这里是我的版本的Joris的答案实现这个控制列表想法的想法:

 la.args <- function(x = "bottomleft", legend = "bar", pch = 1, ...) c(list(x = x, legend = legend, pch = pch), list(...)) foo.plot <- function(x,y, legend.args = la.args(), ...) { plot(x, y, ...) do.call(legend, legend.args) } 

就像这样,使用Jori的第二个示例调用,适当修改:

 foo.plot(1,1, xaxt = "n", legend.args=la.args(bg = "yellow", title = "legend")) 

在设置la.args()函数时,你可以像你想的那样完整 – 在这里我只设置Joris设置的参数的默认值,并且连接其他的参数。 如果la.args()包含所有具有默认值的图例参数,会更容易。

一种方法是使用参数列表和do.call结合使用。 这不是最美丽的解决scheme,但它确实有效。

 foo.plot <- function(x,y,legend.args,...) { la <- list( x="bottomleft", legend="bar", pch=1 ) if (!missing(legend.args)) la <- c(la,legend.args) plot(x,y,...) do.call(legend,la) } foo.plot(1,1, xaxt = "n") foo.plot(1,1, xaxt = "n",legend.args=list(bg="yellow",title="legend")) 

一个缺点是你不能在legend.args列表中指定例如pch = 2。 你可以用一些if子句来解决这个问题,我会把它留给你,以便进一步调整它。


编辑:看到加文辛普森的答案更好的版本这个想法。