Simple question, I hope. I want to write a plotting function that has a default value for the y-axis label if the user doesn't specify. I'd also like to allow the ...
argument for other plotting parameters, and allow the user to set ylab
manually. But I can't figure out how to do this.
简单的问题,我希望。我想要编写一个绘图函数,如果用户没有指定,它对y轴标签具有默认值。我还想让……为其他绘图参数提供参数,并允许用户手动设置ylab。但我不知道怎么做。
# simple scatterplot function with a default ylab
scatter <- function(x,y, ...) {
plot(x, y, ylab="Default y-axis label", ...)
}
# generate data
x <- rnorm(100)
y <- x+rnorm(100)
# use the default
scatter(x,y)
# here I want to use my own label, but I get an error!
scatter(x, y, ylab="New y-axis label")
The error I get is:
我得到的错误是:
Error in plot.default(x, y, ylab = "Default y-axis label", ...) :
formal argument "ylab" matched by multiple actual arguments
I understand the problem, but I don't know the best way to fix it. Thanks for the help!
我理解这个问题,但我不知道解决它的最好方法。谢谢你的帮助!
EDIT: I realize I can do something like
编辑:我意识到我可以做一些类似的事情。
scatter <- function(x,y,ylab = "Default y-axis label", ...) {
plot(x, y, ylab= ylab, ...)
}
...but if I'm writing a package to submit to CRAN, and I have lots of default options I'd like to fiddle with, I don't want to have to document all these standard plotting arguments because they're used in my function definition.
…但是如果我要写一个提交给CRAN的包,并且我有很多默认的选项,我想要修改,我不想要记录所有这些标准的绘图参数,因为它们是在我的函数定义中使用的。
3 个解决方案
#1
8
Try doing this instead:
试试这样做:
scatter <- function(x,y,ylab = "Default y-axis label", ...) {
plot(x, y, ylab= ylab, ...)
}
Expanding slightly on Arun's answer, this is a sketch of one route to take if you have many arguments:
在阿伦的回答中稍微扩展一下,这是一条路线的草图,如果你有很多论点的话:
def_args <- list(ylab = "Default Label",xlab = "Default Label")
scatter <- function(x,y, ...) {
cl <- as.list(match.call())[-1L]
do.call("plot",c(cl,def_args[!names(def_args) %in% names(cl)]))
}
Some thought would be needed to decide how you want to handle partial matching of arguments (if at all). e.g. perhaps something like this:
需要一些想法来决定如何处理参数的部分匹配(如果有的话)。例如:
scatter <- function(x,y, ...) {
cl <- as.list(match.call())[-1L]
names(cl) <- match.arg(names(cl),
names(formals(plot.default)),several.ok = TRUE)
do.call("plot",c(cl,def_args[!names(def_args) %in% names(cl)]))
}
would handle partial matching of arguments.
将处理参数的部分匹配。
#2
5
One way using match.call
to check if ylab
has been specified as an argument:
使用匹配的一种方式。调用检查ylab是否已被指定为参数:
scatter <- function(x,y, ...) {
mcall = as.list(match.call())[-1L]
if (!"ylab" %in% names(mcall))
plot(x, y, ylab="Default y-axis label", ...)
else plot(x, y, ...)
}
As mentioned under comment list(...)
is a nicer way to get just the dots argument expanded than having to get all the formal arguments with match.call
.
正如在注释列表中所提到的(…)是一种更好的方法来得到点参数的扩展,而不是必须得到所有正式的参数。
You might also try using pmatch
instead of %in%
for partial matching of arguments.
您也可以尝试使用pmatch而不是%in%来进行部分匹配的参数。
#3
2
I use a function to build an argument list. In my case, I do not care about partially matching argument names, which is good because this won't support it.
我使用一个函数来建立一个参数列表。在我的例子中,我不关心部分匹配的参数名,这很好,因为这不会支持它。
# Create a list of input arguments.
# Allow arguments to be specified multiple times, first definition wins.
# The resulting list is intended to be passed to do.call().
make.args <- function(..., PRE.ARGS=list(), POST.ARGS=list()) {
a <- list()
l <- c(PRE.ARGS, list(...), POST.ARGS)
for (name in unique(names(l))) {
a[[name]] <- l[[name]] # First occurrence will be found.
}
return(a)
}
An example of its use:
它使用的一个例子:
plot.rate <- function(col, cond=NULL, ...) {
col <- paste(col, collapse=' + ')
f <- paste(col, '~ Rate')
if (!is.null(cond)) {
cond <- paste(cond, collapse=' + ')
f <- paste(f, cond, sep='|')
}
arg.list <- make.args(...
, x = as.formula(f)
, main=col
, grid=TRUE
, scales=list(x=list(alternating=1) # bottom(/left)
, y=list(alternating=3)) # both
, xlab='x RTM'
)
do.call(xyplot, arg.list)
}
#1
8
Try doing this instead:
试试这样做:
scatter <- function(x,y,ylab = "Default y-axis label", ...) {
plot(x, y, ylab= ylab, ...)
}
Expanding slightly on Arun's answer, this is a sketch of one route to take if you have many arguments:
在阿伦的回答中稍微扩展一下,这是一条路线的草图,如果你有很多论点的话:
def_args <- list(ylab = "Default Label",xlab = "Default Label")
scatter <- function(x,y, ...) {
cl <- as.list(match.call())[-1L]
do.call("plot",c(cl,def_args[!names(def_args) %in% names(cl)]))
}
Some thought would be needed to decide how you want to handle partial matching of arguments (if at all). e.g. perhaps something like this:
需要一些想法来决定如何处理参数的部分匹配(如果有的话)。例如:
scatter <- function(x,y, ...) {
cl <- as.list(match.call())[-1L]
names(cl) <- match.arg(names(cl),
names(formals(plot.default)),several.ok = TRUE)
do.call("plot",c(cl,def_args[!names(def_args) %in% names(cl)]))
}
would handle partial matching of arguments.
将处理参数的部分匹配。
#2
5
One way using match.call
to check if ylab
has been specified as an argument:
使用匹配的一种方式。调用检查ylab是否已被指定为参数:
scatter <- function(x,y, ...) {
mcall = as.list(match.call())[-1L]
if (!"ylab" %in% names(mcall))
plot(x, y, ylab="Default y-axis label", ...)
else plot(x, y, ...)
}
As mentioned under comment list(...)
is a nicer way to get just the dots argument expanded than having to get all the formal arguments with match.call
.
正如在注释列表中所提到的(…)是一种更好的方法来得到点参数的扩展,而不是必须得到所有正式的参数。
You might also try using pmatch
instead of %in%
for partial matching of arguments.
您也可以尝试使用pmatch而不是%in%来进行部分匹配的参数。
#3
2
I use a function to build an argument list. In my case, I do not care about partially matching argument names, which is good because this won't support it.
我使用一个函数来建立一个参数列表。在我的例子中,我不关心部分匹配的参数名,这很好,因为这不会支持它。
# Create a list of input arguments.
# Allow arguments to be specified multiple times, first definition wins.
# The resulting list is intended to be passed to do.call().
make.args <- function(..., PRE.ARGS=list(), POST.ARGS=list()) {
a <- list()
l <- c(PRE.ARGS, list(...), POST.ARGS)
for (name in unique(names(l))) {
a[[name]] <- l[[name]] # First occurrence will be found.
}
return(a)
}
An example of its use:
它使用的一个例子:
plot.rate <- function(col, cond=NULL, ...) {
col <- paste(col, collapse=' + ')
f <- paste(col, '~ Rate')
if (!is.null(cond)) {
cond <- paste(cond, collapse=' + ')
f <- paste(f, cond, sep='|')
}
arg.list <- make.args(...
, x = as.formula(f)
, main=col
, grid=TRUE
, scales=list(x=list(alternating=1) # bottom(/left)
, y=list(alternating=3)) # both
, xlab='x RTM'
)
do.call(xyplot, arg.list)
}