有没有办法在R中的函数中使用两个'...'语句? [英] Is there a way to use two '...' statements in a function in R?
问题描述
我想写一个调用 plot()
和 legend()
的函数,它会是理想的如果用户可以指定一些额外的参数,然后传递给 plot()
或 legend()
。我知道我可以使用 ...
来实现这个功能:
<$ (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
是唯一的,而不是图的一部分和/或par:
legend.args< - 名字(形式(图例))
plot.args< - c (名称(形式(plot.default)),名称(par()))
dput(legend.args [!(legend.args%in%plot.args)])
$ b这里我使用
接下来,我必须处理重叠参数(通过dput()
,因为plot.args< - c(names(formals(plot.default)),names(par()))
总是调用一个我不想要的新空图。因此,我在以下函数中使用了dput
的输出。dput(largs.all [(%pargs.all中的largs.all%)])
)获取它们。对于某些人来说,这是微不足道的(例如,x
,y
)其他人会被传递给两个函数(例如PCH
)。但是,在我真正的应用程序中,我甚至使用了其他策略(例如,adj
不同的变量名称,但在本例中未实现)。
最后,必须以两种方式更改
do.call
函数。首先,什么部分(即称为函数)需要是一个字符(即'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所有< - c(leg.args.unique,col,lty,lwd,pch,bty,bg,cex,adj,xpd)
点< - list(...)
do.call('plot',c(list(x = x,y = x),dots [!(名称(点)%in%leg (''legend',c(list(bottomleft,bar),dots [names(dots)%in%leg.args.all]))
do.call
$ b foo.plot(1,1,pch = 4,title =legendary,ylim = c(0,5))
在这个例子中,
pch
传递给plot
和legend
,title
d到legend
和ylim
仅限于plot
。
更新2基于Gavin Simpson的评论(另请参阅Vitoshka的回答) strong>
(i)这是正确的。
(ii)它总是一个角色。但是如果你有一个和函数同名的变量,那么你需要引用do.call
中的函数名称:
$ b (plot == TRUE)do.call(plot,list(x = x,y) = y))
min.plot(1,1)
do.call中的错误(plot,list(x = x,y = y)):
'what'must'a字符串或函数
c(x = 1,y = 1,list())
,它工作正常。然而,我真正做了什么(不是在我给出的例子中,而是在我的实际函数中)如下: c(x = 1,y = 1,xlim = c(0,2),list (x = 1,y = 1,xlim = c(0,bla ='foo'))
请把它和 2)),list(bla ='foo'))
在第一种情况下,列表包含两个元素 xlim
, xlim1
和 xlim2
(每个标量),在后一种情况下,列表只有 xlim
(这是长度为2的向量,这是我想要的)。
所以,你的观点对我的例子来说是正确的。但是,对于我的真实功能(有很多变量),我遇到了这些问题,并希望在这里记录它们。
一种自动方式:
<$ p $ (x,y,...){
lnames< - 名字(形式(图例))
名称< - c(名称(形式(plot.default)),名称(par()))
dots< - list(...)
do.call('plot',c(list(x = x ,'y = x),点[名称(点)%in%pnames]))
do.call('legend',c(bottomleft,bar,pch = 1,dots [names(dots )%in%lnames]))
}
pch必须从lnames过滤到避免在用户提供'pch'的情况下在图例
调用中重复,但您明白了。
由Carl W编辑2012年1月:do.call仅适用于引号中的函数,就像Henrik的更新中一样。我在这里编辑它以避免将来的混淆。
I want to write a function that calls both plot()
and legend()
and it would be ideal if the user could specify a number of additional arguments that are then passed through to either plot()
or legend()
. I know I can achieve this for one of the two functions using ...
:
foo.plot <- function(x,y,...) {
plot(x,y,...)
legend("bottomleft", "bar", pch=1)
}
foo.plot(1,1, xaxt = "n")
This passes xaxt = "n"
to plot. But is there a way for example to pass e.g. title = "legend"
to the legend()
call without prespecifying the arguments in the function header?
Update from the accepted answer: I thought that VitoshKa's way was the most elegant to accomplish what I wanted. However, there were some minor issues that I had to get around with until it worked as I wanted.
At first, I checked which of the parameters I want to pass to legend
and which to plot
. First step to this end was to see which arguments of legend
are unique to legend
and not part of plot and/or par:
legend.args <- names(formals(legend))
plot.args <- c(names(formals(plot.default)), names(par()))
dput(legend.args[!(legend.args %in% plot.args)])
I use dput()
here, because the line plot.args <- c(names(formals(plot.default)), names(par()))
always calls a new empty plot which I did not want. So, I used the output of dput
in the following function.
Next, I had to deal with the overlapping arguments (get them via dput(largs.all[(largs.all %in% pargs.all)])
). For some this was trivial (e.g., x
, y
) others get passed to both functions (e.g., pch
). But, in my real application I even use other strategies (e.g., different variable names for adj
, but not implemented in this example).
Finally, the do.call
function had to be changed in two ways. First, the what part (i.e., called functions) needs to be a character (i.e., 'plot'
instead of plot
). And the argument list must be constructed slightly different.
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))
In this example, pch
is passed to both plot
and legend
, title
is only passed to legend
, and ylim
only to plot
.
Update 2 based on a comment by Gavin Simpson (see also the comments at Vitoshka's answer):
(i) That's correct.
(ii) It can always be a character. But if you have a variable with the same name as the function, then you need to quote the function name in 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) You can use c(x = 1, y = 1, list())
and it works fine. However, what I really did (not in the example I gave but in my real function) is the following: c(x = 1, y = 1, xlim = c(0, 2), list(bla='foo'))
Please compare this with: c(list(x = 1, y = 1, xlim = c(0, 2)), list(bla='foo'))
In the first case, the list contains two elements xlim
, xlim1
and xlim2
(each a scalar), in the latter case the list has only xlim
(which is vector of length 2, which is what I wanted).
So, you are right in all your points for my example. But, for my real function (with a lot more variables), I encountered these problems and wanted to document them here. Sorry for being imprecise.
An automatic way:
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 must be filtered from the lnames to avoid duplication in the legend
call in case the user supplies 'pch', but you got the idea.
Edited Jan 2012 by Carl W: "do.call" only works with the functions in quotes, as in the updates by Henrik. I edited it here to avoid future confusion.
这篇关于有没有办法在R中的函数中使用两个'...'语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!