Как использовать переменную для указания имени столбца в ggplot

110

У меня есть команда 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 («пол») мы получаем эффект

  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 )
Теодор Норвелл
источник

Ответы:

166

Вы можете использовать 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
5
Просто добавляю примечание, чтобы указать людям на ответ Moody_Mudskipper с обновлениями для ggplot2 версии 3.0.0
Грегор Томас
@buncis Это неправда, цитирование "column_name"или "column"не сработает
Дэвид Робинсон
@DavidRobinson, извините за ошибку, я не вижу, что код заключен в функцию с параметром, я удалю свой комментарий
buncis
"громоздкий"? По иронии судьбы нестандартные вычисления в R - это самая громоздкая «функция», с которой я когда-либо сталкивался в языке программирования. Действительно сводит с ума.
jessexknight,
48

Из выпуска нот в ggplot2 V3.0.0:

aes () теперь поддерживает квазиквотирование, поэтому вы можете использовать !!, !!! и: =. Это заменяет 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():

он предназначен для имитации синтаксиса аргументов, где вы можете указать оба значения в 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)
Moody_Mudskipper
источник
14
Этот тидевал так раздражает. Документация aes()сама по себе говорит об этом, enquo()но это не работает. А кто слышал ensym()раньше? BIG SIGH
CoderGuy123 04
@Moody_Mudskipper Ибо f2все четыре примера работают, как и захват имени столбца в переменной (т.е. aname <- "mjr"; f2(aname)). Если я добавлю код для управления фреймом данных с dplyrего помощью, он попытается найти столбец, используя имя переменной, а не строку в имени переменной. Другими словами, как мне приступить rates.by.groups %>% group_by(!!column)...к работе и по-прежнему поддерживать три способа звонка f2?
steveb
1
«так же и захват имени столбца в переменной»: он не дает сбоев, но не возвращает тот же результат, ensymпредназначен для работы с аргументами, предоставленными как имена, и допускает кавычки вокруг них. Я считаю, что вы хотели бы рассматривать аргумент как имя и использовать значение, если имя не найдено. На самом деле это то, что происходит с select, но не с group_by... Можно обойти это, но не очевидно. Если для вас это важно, я думаю, это заслуживает отдельного вопроса.
Moody_Mudskipper
@Moody_Mudskipper Спасибо. Я использую как selectи group_byтак , что, скорее всего , вопрос. Я могу создать новый вопрос, но мне нужно придумать простой пример и проверить, есть ли на него ответ. Если нет, могу выложить.
стивеб
1
Как пользоваться !! в случае facet_grid? Он работает, facet_grid(cols = vars(!!column))но выдает ошибку сfacet_grid(~ !!column)
mRiddle
15

Попробуйте использовать aes_string вместо aes.

MDe
источник
5
Это отличный совет, но можете ли вы сказать им, почему? aes_string заставляет вас использовать "" для непеременных и использовать переменные без кавычек. aes_string (x = "foo", y = "fee", group = variable)
mtelesha
@mtelesha, возможно, потому, что в переменной есть строка в качестве значения
buncis
12

Другой вариант ( ggplot2 > 3.0.0) - использовать аккуратное оценочное местоимение, .dataчтобы вырезать выбранную переменную / столбец из rates.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)'))

Создано 04.04.2019 пакетом REPEX (v0.2.1.9000)

Тунг
источник
1

Использование aes_stringдействительно решает эту проблему, но сталкивается с проблемой при добавлении полос погрешностей geom_errorbar. Ниже представлено простое решение.

#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_grid(formula(paste(Variable1, "~", Variable2)))

Этот сценарий был изменен из исходного сообщения: ggplot2 - панели ошибок с использованием пользовательской функции

Marty999
источник
1

Вот очень простой пример.

Просто сделай две вещи

  1. Превратите строку в символ
  2. Добавляйте, !!когда используете
select_col <- sym("Petal.Length")

iris %>% 
  ggplot(aes(x = Sepal.Length, y = !!select_col)) +
  geom_point()
Стивек
источник