有没有办法在R中的函数中使用两个'...'语句? [英] Is there a way to use two '...' statements in a function in R?

查看:82
本文介绍了有没有办法在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆