如何使用省略号参数(...)来覆盖硬编码的函数参数?

5
我正在尝试创建一个绘图函数,它具有一组默认值,并且可以通过在省略号(...)参数中使用plot函数接受的任何参数来灵活更改这些值。例如:
PlotIt <- function(x, y, ...) {
  plot(x, y, type = "l", asp = 1, ...)
}

x <- 1:10
y <- 10:1

PlotIt(x = x, y = y)
# Returns a plot
PlotIt(x = x, y = y, asp = NA)
# Error in plot.default(x, y, type = "l", asp = 1, ...) : 
#  formal argument "asp" matched by multiple actual arguments

错误是因为我试图将 asp 参数传递两次到 plot 中。到目前为止,我最好的笨拙尝试是编写 if-else 语句来考虑这一点(该方法已从 此处 修改)。
PlotIt2 <- function(x, y, ...) {

  mc <- match.call(expand.dots = FALSE)

  if(names(mc$...) %in% "asp") {
  plot(x, y, type = "l", ...)  
  } else {
  plot(x, y, type = "l", asp = 1, ...)  
  }

}

PlotIt2(x = x, y = y, asp = NA)
# works

为了针对可以通过 ... 参数设置的所有可能参数执行此操作,我需要编写一个很长的 if-else 语句。有没有更优雅的方法来实现这个功能?
该问题与 this one 相关,不同之处在于我想要自动覆盖由 ... 参数设置的所有参数。
2个回答

4

如果您只想使用基本R语言,则可以将所有内容放入列表中,根据参数名称删除重复项(确保默认值在最后,这样如果它们出现在...中,它们就会被删除):

PlotIt <- function(x, y, ...) {
  arguments <- list(
    x = x,
    y = y,
    ...,
    type = "l",
    asp = 1
  )

  arguments <- arguments[!duplicated(names(arguments))]

  do.call("plot", arguments)
}

如果您不介意依赖rlang,您也可以使用.homonyms来获得相同的功能(并检查绘图的标签以获取轴标签,在基本R和rlang版本之间会有所不同):
PlotIt <- function(x, y, ...) {
  require("rlang")
  arguments <- rlang::dots_list(
    rlang::expr(x),
    rlang::expr(y),
    ...,
    type = "l",
    asp = 1,
    .homonyms = "first"
  )

  call <- rlang::call2("plot", !!!arguments)
  eval(call)
}

你能否在这个例子中使用match.call()来解决这里描述的问题?我正在尝试学习match.call(),但我更喜欢你的方法,它更直观。 - user63230
1
@user63230 嗯,Mikko 在他的问题中尝试的是我能想到的,我不确定如何改进。 - Alexis

0

不要在绘图函数中硬编码你的参数,而是在函数的参数中设置一个默认值,该默认值与之前硬编码的值相等。为了方便起见,使用与绘图参数相同的名称:

PlotIt <- function(x, y, asp = 1, ...) {
  plot(x, y, type = "l", asp = asp, ...)
}

因为你将默认参数定义为asp = 1,所以你可以选择
x <- 1:10; y <- 10:1
PlotIt(x = x, y = y) # not enter the parameter
PlotIt(x = x, y = y, asp = NA) # or enter the parameter

并且它会按预期工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接