【问题标题】:Default argument in R function (formal argument matched by multiple actual arguments)R函数中的默认参数(由多个实际参数匹配的形式参数)
【发布时间】:2014-07-18 07:07:51
【问题描述】:

简单的问题,我希望。如果用户未指定,我想编写一个绘图函数,该函数具有 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")

我得到的错误是:

Error in plot.default(x, y, ylab = "Default y-axis label", ...) : 
  formal argument "ylab" matched by multiple actual arguments 

我了解问题所在,但我不知道解决问题的最佳方法。感谢您的帮助!

编辑:我意识到我可以做类似的事情

scatter <- function(x,y,ylab = "Default y-axis label", ...) {
    plot(x, y, ylab= ylab, ...)
}

...但是如果我正在编写一个要提交给 CRAN 的包,并且我有很多默认选项我想摆弄,我不想记录所有这些标准绘图参数,因为它们'在我的函数定义中使用。

【问题讨论】:

    标签: r function argument-passing


    【解决方案1】:

    尝试这样做:

    scatter <- function(x,y,ylab = "Default y-axis label", ...) {
        plot(x, y, ylab= ylab, ...)
    }
    

    稍微扩展 Arun 的回答,如果您有很多论点,这是一条路线的草图:

    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)]))
    }
    

    需要一些想法来决定如何处理参数的部分匹配(如果有的话)。例如也许是这样的:

    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)]))
    }
    

    将处理参数的部分匹配。

    【讨论】:

    • 这行得通,但如果我正在编写一个包,这是我必须不必要地记录的另一个论点。我有很多这些默认的绘图参数,我想摆弄,但不想再次记录。
    • @StephenTurner 我需要几分钟来完成一个示例,但一种选择是根本不提供显式默认值,而是将所有内容打包在 ... 中,然后检查 @ 987654325@ 在scatter 内,然后根据用户传递的内容,构造对plot 的适当调用。
    • @StephenTurner 即 正是 Arun 刚刚提供的内容。
    • 谢谢 - 将看看这两个解决方案。你是对的,诀窍是处理指定和“默认”选项的多个排列。
    • 谢谢。使用do.call 和此处提供的参数列表完美地解决了这个问题。似乎有一种不那么糟糕的方法,但这很好用。
    【解决方案2】:

    一种使用match.call 来检查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, ...)
    }
    

    正如评论 list(...) 中提到的,与必须使用 match.call 获取所有形式参数相比,仅扩展点参数是一种更好的方法。

    您也可以尝试使用pmatch 而不是%in% 来部分匹配参数。

    【讨论】:

    • ... 在 fxn 中不是更容易被捕获为 args &lt;- list(...) 吗?
    • 没错。在 OP 的情况下,诀窍可能是扩展它以处理大量参数。我的想法是在列表中准备好一组默认参数,然后与... 进行“联合”,然后将其扔给do.call 或其他东西。
    【解决方案3】:

    我使用一个函数来构建一个参数列表。就我而言,我不关心部分匹配的参数名称,这很好,因为它不支持它。

    # 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)
    }
    

    其使用示例:

    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)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      相关资源
      最近更新 更多