基于 "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)
,标签为 a
和 b
。但是,如果您使用 do.call
魔法,do.call(plot, list(x = a, y = b)
会扩展为 plot(x = 1:2, y = 3:4)
,因此标签为 1:2
和 3:4
。我建议使用带有 data
参数的公式方法,即对于您的示例:
do.call(what = "plot", args = list(formula = Sepal.Length ~ Sepal.Width,
data = I))
我在和 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)
,标签为 a
和 b
。但是,如果您使用 do.call
魔法,do.call(plot, list(x = a, y = b)
会扩展为 plot(x = 1:2, y = 3:4)
,因此标签为 1:2
和 3:4
。我建议使用带有 data
参数的公式方法,即对于您的示例:
do.call(what = "plot", args = list(formula = Sepal.Length ~ Sepal.Width,
data = I))