传递参数给ggplot

21
我想创建一个使用ggplot生成图形的函数。为了简单起见,典型的图形可能是:
ggplot(car, aes(x=speed, y=dist)) + geom_point() 

我想创建的函数类型是:

f <- function(DS, x, y) ggplot(DS, aes(x=x, y=y)) + geom_point()

然而,这并不起作用,因为x和y不是字符串。这个问题在之前的SO问题中已经被指出(例如,这个),但没有提供令人满意的答案。如何修改上面的函数使它适用于任意数据框?

4个回答

43

一种解决方案是将x和y作为数据框DS中列的字符串名称传递。

f <- function(DS, x, y) {    
  ggplot(DS, aes_string(x = x, y = y)) + geom_point()  
}

然后按以下方式调用函数:

f(cars, "speed", "dist")

然而,看起来你并不想要那个功能?你能提供为什么需要其他不同功能的示例吗?是因为你不想在同一个数据框中包含参数吗?


1
太好了。我之前根本不知道这个选项的存在。谢谢。 - gappy
1
知道了,忘记了,因为你的回答重新发现了它。+1 - Matt Bannert
为什么DS不需要“”,但x和y需要呢?你能解释一下吗? - Geekuna Matata
1
太好了!在看到这篇文章之前,我不知道有 aes_string 这个选项。 - BioCoder
从未听说过aes_string。谢谢你让我知道它。 - minion

8
我认为以下类型的代码是可能的,只构建组件。
require(ggplot2)

DS <- data.frame(speed=rnorm(10), dist=rnorm(10))

f <- function(DS, x, y, geom, opts=NULL) {
  aes <- eval(substitute(aes(x, y),
    list(x = substitute(x), y = substitute(y))))
  p <- ggplot(DS, aes) + geom + opts
}

p <- f(DS, speed, dist, geom_point())
p

然而,这似乎是一种复杂的方法。

6
更好的方法是跳过将内容转换为文本,而只构建 aes 组件:xName <- substitute(x); yName <- substitute(y); eval(substitute(aes(x, y), list(x = xName, y = yName))) - hadley
谢谢@hadley。我认为这种方法比我的更简单。 - Triad sou.

1
另一种选择是使用do.call。以下是可行代码的一行复制粘贴:
gg <- gg + geom_rect( do.call(aes, args=list(xmin=xValues-0.5, xmax=xValues+0.5, ymin=yValues, ymax=rep(Inf, length(yValues))) ), alpha=0.2, fill=colors )

1
我能想到的一种方法是使用match.call()来获取传递给自定义绘图函数的参数/参数中包含的变量名称,然后对它们使用eval()。这样,您就可以避免将它们作为引号传递给自定义函数(如果您不喜欢这样做)。
library(ggplot2)

fun <- function(df, x, y) {
    arg <- match.call()
    ggplot(df, aes(x = eval(arg$x), y = eval(arg$y))) + geom_point()
} 
fun(mpg, cty, hwy) # no need to pass the variables (column names) as quoted / as strings

enter image description here


谢谢。这对我很有帮助!你能解释一下match.call参数吗? - Luis
1
嗨@Luis。Hadley Wickham在他的《Advanced R》书中的Capturing the current call章节中写到了一些match.call()的用法。也许这可以提供更多细节帮助。 - Valentin_Ștefan

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