ggplot:aes vs aes_string,或者如何以编程方式指定列名?

blu*_*e10 9 plot r ggplot2

我们假设我们有以下数据框

data <- data.frame(time=1:10, y1=runif(10), y2=runif(10), y3=runif(10))
Run Code Online (Sandbox Code Playgroud)

我们想创建一个这样的情节:

p <- ggplot(data, aes(x=time))
p <- p + geom_line(aes(y=y1, colour="y1"))
p <- p + geom_line(aes(y=y2, colour="y2"))
p <- p + geom_line(aes(y=y3, colour="y3"))
plot(p)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

但是,如果我们有更多的"y"列,我们不知道它们的确切名称.这提出了一个问题:我们如何以编程方式迭代所有列,并将它们添加到绘图中?基本上目标是:

otherFeatures <- names(data)[-1]
for (f in otherFeatures) {
  # what goes here?
}
Run Code Online (Sandbox Code Playgroud)

尝试失败

到目前为止,我发现许多方法都行不通.例如(以下所有示例仅显示上面for循环中的代码行):

我的第一次尝试只是使用aes_string而不是aes为了通过循环变量指定列名f:

p <- p + geom_line(aes_string(y=f, colour=f))
Run Code Online (Sandbox Code Playgroud)

但这并没有给出相同的结果,因为现在colour不会是每行的固定颜色(aes_stringf在数据框环境中解释).因此,图例将变为颜色条,并且不包含不同的列名.我的下一个猜测是混合,aesaes_string试图设置colour为固定字符串:

p <- p + geom_line(aes_string(y=f), aes(colour=f))
Run Code Online (Sandbox Code Playgroud)

但这导致了Error: ggplot2 doesn't know how to deal with data of class uneval.我的下一次尝试是使用colour"绝对"(不在其中aes)这样:

p <- p + geom_line(aes_string(y=f), colour=f)
Run Code Online (Sandbox Code Playgroud)

但这给了Error: invalid color name 'y1'(我也不想手动选择一些正确的颜色名称).接下来的尝试只是回到aes复制手动方法:

p <- p + geom_line(aes(y=data[[f]], colour=f))
Run Code Online (Sandbox Code Playgroud)

这不会给出错误,但只会绘制最后一列.这是有道理的,因为aes可能会调用substitute,并且表达式将始终使用f循环中的最后一个值进行计算(rm f在调用之前plot(p)给出错误,表示评估循环之后发生).

重新解释一个问题:在for循环中从上面复制简单代码需要什么样的substitute/ eval/ quote魔术?

小智 5

这现在已经过时了,但万一其他人遇到它,我遇到了一个非常相似的问题,让我发疯。我找到的解决方案是传递aes_q()geom_line()使用as.name()选项。您可以在aes_q() 此处找到详细信息。下面是我解决这个问题的方法,虽然同样的原则应该在循环中工作。请注意,我geom_line()在这里添加了多个变量作为列表,这样可以更好地概括(包括一个变量)。

varnames <- c("y1", "y2", "y3")
add_lines <- lapply(varnames, function(i) geom_line(aes_q(y = as.name(i), colour = i)))

p <- ggplot(data, aes(x = time))
p <- p + add_lines
plot(p)
Run Code Online (Sandbox Code Playgroud)

希望有帮助!