基于 "plot" 理解 do.call 语义

Understanding do.call semantics based on "plot"

我在和 do.call 开玩笑。

I = iris
do.call(what = "plot", args = c(I$Sepal.Length ~ I$Sepal.Width))
# This seems fine

p = list(x = I$Sepal.Length, y = I$Sepal.Width)
do.call(what = "plot", args = p)
# This looks weird

p1 = list(x = I$Sepal.Length, y = I$Sepal.Width, xlab = "")
do.call(what = "plot", args = p1)
# A bit less weird


p2 = list(x = I$Sepal.Length, y = I$Sepal.Width, xlab = "", ylab = "")
do.call(what = "plot", args = p2)
# And this gives the same as the first do.call

那么为什么我必须提供轴标签来抑制我在使用 do.call 时得到的所有数字?

您看到的是 R 在无法从参数中获取任何其他命名信息时放在轴标签上的内容。如果你这样做:

plot(x=c(1,2,3,4,5,6,7,8),y=c(1,2,3,4,3,2,3,4))

那么绘图必须使用矢量值作为轴标签。

使用do.call时,参数列表中的名称与调用函数的参数名称相匹配。所以轴标签没有名称,只有值。那时,数据来自 I$Sepal.width 的事实早已不复存在,它只是一个值向量。

首先你需要明白plot是一个S3 generic,它根据第一个参数调用方法。如果你这样做 plot(y ~ x) 这个方法是 plot.formula 并且轴标签是从公式中推断出来的。如果你这样做 plot(x, y)(注意 x 和 y 的不同顺序),方法是 plot.default 并且轴标签是从作为参数传递的符号中推断出来的。

现在,如果您执行 a <- 1:2; y <- 3:4; plot(x = a, y = b),标签为 ab。但是,如果您使用 do.call 魔法,do.call(plot, list(x = a, y = b) 会扩展为 plot(x = 1:2, y = 3:4),因此标签为 1:23:4。我建议使用带有 data 参数的公式方法,即对于您的示例:

do.call(what = "plot", args = list(formula = Sepal.Length ~ Sepal.Width,
                                   data = I))