如何使用变量来指定ggplot中的列名

202

我有一个ggplot命令

ggplot( rates.by.groups, aes(x=name, y=rate, colour=majr, group=majr) )

在函数内部。但我希望能够使用函数的一个参数来选择要用作颜色和分组的列。即我想要类似于这样的东西

f <- function( column ) {
    ...
    ggplot( rates.by.groups, aes(x=name, y=rate, colour= ??? , group=??? ) )
}

所以ggplot中使用的列由参数确定。例如,对于f("majr"),我们得到了影响

ggplot( rates.by.groups, aes(x=name, y=rate, colour=majr, group=majr) )

但对于 f("gender"),我们得到了效果

  ggplot( rates.by.groups, aes(x=name, y=rate, colour=gender, group=gender) )

我尝试过以下几件事情:

ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ) )

未能起作用。也没有

e <- environment() 
ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ), environment=e )
6个回答

239

注意:本答案中的解决方案已经被“软弃用”。请参见下面使用.data[[的答案,这是当前首选方法。

您可以使用aes_string

f <- function( column ) {
    ...
    ggplot( rates.by.groups, aes_string(x="name", y="rate", colour= column,
                                        group=column ) )
}
只要您将该列作为字符串传递给函数(f("majr")而不是f(majr)),注意我们也将其他列"name""rate"更改为字符串。 如果出于任何原因您不想使用aes_string,您可以将其更改为(稍微繁琐一些的):
    ggplot( rates.by.groups, aes(x=name, y=rate, colour= get(column),
                                        group=get(column) ) )

值得一提的是,你不应该/不能使用aes_string(x = rates.by.groups$name...,而且你也不需要这样做,因为你已经传递了ggplot(data = rates.by.groups...参数。(这个问题中的问题) - smci
8
只是添加一条提示,指导人们查看Moody_Mudskipper的答案,以获取更新后的ggplot2版本3.0.0。 - Gregor Thomas
@buncis,那不是真的,引用“column_name”或“column”是行不通的。 - David Robinson
@DavidRobinson 对不起,我的错误,我没有看到代码被包装在带参数的函数中,我会删除我的评论。 - buncis
1
“cumbersome”? 在R中的非标准评估是我在编程语言中遇到的最繁琐的“特性”,真是令人发狂。 - jessexknight

106

来自 ggplot2 V3.0.0 的发布说明

aes() 现在支持准引用(quasiquotation),以便您可以使用 !!、!!! 和 :=。这取代了现在软弃用的 aes_() 和 aes_string()(但将长期存在)。

现在的惯用方式是,将变量包含的字符串转换为符号,使用 sym()(它与基本别名 as.name() / as.symbol() 几乎相同),然后使用 !! 来取消引用它。

模拟 OP 的数据,我们可以执行:

library(tidyverse)
rates.by.groups <- data.frame(
  name = LETTERS[1:3],
  rate = 1:3,
  mjr = LETTERS[c(4,4,5)],
  gender = c("M","F","F")
)

f <- function(column) {
  column <- sym(column)
  ggplot(rates.by.groups, 
         aes(x = name, 
             y = rate, 
             fill  = !!column, 
             group = !!column)) +
    geom_col()
}

f("gender")
f("mjr")
x <- "gender"
f(x)

如果我们更喜欢将原始名称传递给函数,则可以执行以下操作:

f2 <- function(column) {
  column <- ensym(column)
  ggplot(rates.by.groups, 
         aes(x = name, 
             y = rate, 
             fill  = !!column, 
             group = !!column)) +
    geom_col()
}

它将同时适用于名称(也称为符号)和字符串字面量。

f2(gender)
f2(mjr)
f2("gender")
f2("mjr")

关于ensym(),正如 Lionel 所说:

它旨在模拟参数语法,您可以在 LHS 中提供两个参数,例如 list(bare = 1, "quoted" = 2)


关于enquo()的注意事项:

enquo() 引用传递给参数的表达式(不一定是符号),它不像 ensym() 那样将字符串转换为符号,因此在这里可能不太适合,但我们可以通过以下方式进行操作:

f3 <- function(column) {
  column <- enquo(column)
  ggplot(rates.by.groups, 
         aes(x = name, 
             y = rate, 
             fill  = !!column, 
             group = !!column)) +
    geom_col()
}

f3(gender)
f2(mjr)

45
这个 tidyeval 真是让人头疼。aes() 的文档中提到了 enquo(),但实际使用并不奏效。而且谁之前听说过 ensym()?唉,真烦。 - CoderGuy123
@Moody_Mudskipper 对于 f2,所有四个示例都有效,将列名捕获到变量中也可以(即 aname <- "mjr"; f2(aname))。如果我添加使用 dplyr 操作数据框的代码,则会尝试使用变量名而不是变量名中的字符串来查找列。换句话说,如何使 rates.by.groups %>% group_by(!!column)... 起作用并仍然支持调用 f2 的三种方式? - steveb
1
"所以将列名捕获到变量中也是如此": 它不会失败,但不会返回相同的结果,ensym旨在处理提供为名称的参数,并容忍它们周围的引号。我认为您想将参数视为名称,并在找不到名称时回退到值。这实际上是select发生的事情,但不是group_by...可以通过黑客方式解决,但并不明显。如果这对您很重要,我认为它应该有自己的问题。 - moodymudskipper
@Moody_Mudskipper 谢谢。我同时使用了 selectgroup_by,所以可能是问题所在。我可以创建一个新的问题,但我需要想出一个简单的例子并检查它是否已经被回答。如果没有,我可以发布它。 - steveb
1
如何在“facet_grid”中使用“!!”?它可以与“facet_grid(cols = vars(!!column))”一起使用,但是在“facet_grid(~ !!column)”中会抛出错误。 - mRiddle

65
另一种选择(ggplot2 > 3.0.0)是使用整洁评估代词.datarates.by.groups数据框中切分所选变量/列。
请参见此答案
library(ggplot2)
theme_set(theme_classic(base_size = 14))

# created by @Moody_Mudskipper
rates.by.groups <- data.frame(
  name = LETTERS[1:3],
  rate = 1:3,
  mjr = LETTERS[c(4, 4, 5)],
  gender = c("M", "F", "F")
)

f1 <- function(df, column) {
  gg <- ggplot(df, 
         aes(x = name, 
             y = rate, 
             fill  = .data[[column]], 
             group = .data[[column]])) +
    geom_col() +
    labs(fill = column)
  return(gg)
}

plot_list <- lapply(list("gender", "mjr"), function(x){ f1(rates.by.groups, x) })
plot_list
#> [[1]]

#> 
#> [[2]]

# combine all plots
library(egg)
ggarrange(plots = plot_list,
          nrow = 2,
          labels = c('A)', 'B)'))

reprex包(v0.2.1.9000)于2019年04月04日创建


4
.data[[ ]]方法最好的一点就是它的通用性。谢谢。 - dave adelson
5
自 rlang 0.4.* 推出以来,我认为这是规范解决方案。在 ggplot2 的官方文档中也是如此提出的:https://ggplot2.tidyverse.org/articles/ggplot2-in-packages.html - fry

18
尝试使用aes_string替代aes

7
这是很好的建议,但你能告诉他们为什么吗?aes_string让你在非变量上使用"",而在变量上使用unquote。 aes_string(x =“foo”,y =“fee”,group = variable) - mtelesha
@mtelesha 可能是因为该变量的值为字符串。 - buncis

18

做两件事情

  1. 使用 sym() 将列名转换为符号
  2. 当您想要使用它时,在符号前加上 !!

示例

my_col <- sym("Petal.Length")

iris %>% 
  ggplot(aes(x = Sepal.Length, y = !!my_col)) +
  geom_point()

2
使用可以解决这个问题,但是在添加误差线时会遇到问题。以下是一个简单的解决方案。
#Identify your variables using the names of your columns indie your dataset
 xaxis   <- "Independent"   
 yaxis   <- "Dependent"
 sd      <- "error"

#Specify error bar range (in 'a-b' not 'a'-'b')
 range   <- c(yaxis, sd)                                #using c(X, y) allows use of quotation marks inside formula
 yerrbar <- aes_string(ymin=paste(range, collapse='-'), 
                       ymax=paste(range, collapse='+'))


#Build the plot
  ggplot(data=Dataset, aes_string(x=xaxis, y=yaxis)) +
    geom_errorbar(mapping=yerrbar, width=15, colour="#73777a", size = 0.5) +
    geom_point   (shape=21)

此外,您还可以使用以下代码在ggplot中添加facet:

facet_grid(formula(paste(Variable1, "~", Variable2)))

这个脚本是从原始帖子修改而来的:ggplot2 - 使用自定义函数绘制误差线


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