Jak używać zmiennej do określenia nazwy kolumny w ggplot

110

Mam polecenie ggplot

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

wewnątrz funkcji. Ale chciałbym móc użyć parametru funkcji, aby wybrać kolumnę, która ma być używana jako kolor i grupa. To znaczy, chciałbym coś takiego

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

Tak więc kolumna używana w ggplot jest określona przez parametr. Np. Dla f ("majr") otrzymujemy efekt

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

ale dla f („gender”) otrzymujemy efekt

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

Kilka rzeczy, których próbowałem:

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

nie działał. Ani też

e <- environment() 
ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ), environment=e )
Theodore Norvell
źródło

Odpowiedzi:

166

Możesz użyć aes_string:

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

tak długo, jak przekazujesz kolumnę do funkcji jako ciąg ( f("majr")zamiast f(majr)). Zauważ również, że zmieniliśmy inne kolumny "name"i "rate", aby były łańcuchami.

Jeśli z jakiegoś powodu wolisz nie używać aes_string, możesz zmienić to na (nieco bardziej uciążliwe):

    ggplot( rates.by.groups, aes(x=name, y=rate, colour= get(column),
                                        group=get(column) ) )
David Robinson
źródło
Warto powiedzieć, że nie powinieneś / nie możesz aes_string(x = rates.by.groups$name..., a zresztą nie musisz tego robić, skoro już zdałeś ggplot(data = rates.by.groups...argument. (Problem w tym pytaniu )
smci
5
Po prostu dodam notatkę wskazującą ludziom odpowiedź Moody_Mudskipper z aktualizacjami dla ggplot2 w wersji 3.0.0
Gregor Thomas
@buncis To nieprawda, cytowanie "column_name"lub "column"nie zadziała
David Robinson
@DavidRobinson przepraszam mój błąd, nie widzę kod jest owinięty na funkcji z parametrem będzie usunąć komentarz
buncis
"nieporęczny"? Niestandardowa ocena w R jest, jak na ironię, najbardziej uciążliwą „funkcją”, jaką kiedykolwiek spotkałem w języku programowania. Naprawdę szalone.
jessexknight
48

Z release notes z ggplot2 V3.0.0:

aes () obsługuje teraz quasi-cytat, więc możesz używać znaków !!, !!! i: =. Zastępuje to aes_ () i aes_string (), które są teraz nieaktualne (ale pozostaną dostępne przez długi czas).

Idiomatycznym sposobem byłoby teraz przekonwertowanie na symbol łańcucha, który zawiera zmienna, przy użyciu sym()(który jest prawie taki sam jak aliasy bazowe as.name()/ as.symbol()) i cofnięcie jego cytowania za pomocą!!

Symulując dane OP, które możemy zrobić:

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)

Gdybyśmy woleli podać nieprzetworzone nazwy funkcji, którą możemy wykonać:

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

Będzie działać z nazwami znanymi jako symbole ORAZ z literałami łańcuchowymi

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

Jak mówi Lionel ensym() :

ma na celu naśladowanie składni argumentów, w których można podać oba w LHS, np. lista (bare = 1, "quoted" = 2)


Uwaga dotycząca enquo()

enquo()cytuje wyrażenie (niekoniecznie symbol) podane do argumentu, nie konwertuje literału ciągu na symbol, ponieważ ensym()może być tutaj mniej dostosowane, ale możemy zrobić:

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
źródło
14
Te porządne rzeczy są takie irytujące. Dokumentacja aes()sama w sobie mówi, enquo()ale to nie działa. A kto o kim słyszał ensym()wcześniej? BIG
SIGH
@Moody_Mudskipper W przypadku f2wszystkich czterech przykładów działa, podobnie jak przechwytywanie nazwy kolumny w zmiennej (tj aname <- "mjr"; f2(aname).). Jeśli dodam kod do manipulowania ramką danych, używając dplyrgo, próbuje znaleźć kolumnę przy użyciu nazwy zmiennej, a nie ciągu w nazwie zmiennej. Innymi słowy, jak zabrać się rates.by.groups %>% group_by(!!column)...do pracy i nadal wspierać te trzy sposoby dzwonienia f2?
steveb
1
„tak samo jest w przypadku przechwytywania nazwy kolumny w zmiennej”: nie kończy się to niepowodzeniem, ale nie zwraca tego samego wyniku, ensymjest zaprojektowane tak, aby radzić sobie z argumentami podawanymi jako nazwy i tolerować cudzysłowy wokół nich. Uważam, że chciałbyś potraktować argument jako nazwę i wrócić do wartości, jeśli nazwa nie zostanie znaleziona. Tak właśnie dzieje się z select, ale nie z group_by… Jest możliwe, aby to obejść, ale nie jest to oczywiste. Jeśli jest to dla ciebie ważne, myślę, że zasługiwałoby na własne pytanie.
Moody_Mudskipper
@Moody_Mudskipper Thanks. Używałem obu selecti group_byprawdopodobnie to był problem. Mogę utworzyć nowe pytanie, ale muszę podać prosty przykład i sprawdzić, czy udzielono na nie odpowiedzi. Mogę to opublikować, jeśli nie.
steveb
1
Jak używać !! w przypadku facet_grid? Działa z, facet_grid(cols = vars(!!column))ale zgłasza błądfacet_grid(~ !!column)
mRiddle
15

Spróbuj użyć aes_stringzamiast aes.

MDe
źródło
5
To świetna rada, ale czy możesz im powiedzieć, dlaczego? aes_string sprawia, że ​​używasz "" dla zmiennych niezmiennych i używasz zmiennych bez cudzysłowów. aes_string (x = "foo", y = "fee", group = variable)
mtelesha,
@mtelesha może dlatego, że zmienna ma ciąg jako wartość
buncis
12

Inną opcją ( ggplot2 > 3.0.0) jest użycie uporządkowanego zaimka oceny, .dataaby wyciąć wybraną zmienną / kolumnę z rates.by.groupsramki danych.

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)'))

Utworzono 04.04.2019 przez pakiet reprex (v0.2.1.9000)

Tung
źródło
1

Użycie aes_stringrozwiązuje ten problem, ale napotyka problem podczas dodawania słupków błędów geom_errorbar. Poniżej proste rozwiązanie.

#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)

Bonus, możesz także dodać aspekty do swojego wykresu, używając tych linii wewnątrz ggplot:

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

Ten skrypt został zmodyfikowany na podstawie tego oryginalnego postu: ggplot2 - Paski błędów przy użyciu funkcji niestandardowej

Marty999
źródło
1

Oto niezwykle prosty przykład.

Po prostu zrób dwie rzeczy

  1. Zamień sznurek w symbol
  2. Dodaj, !!kiedy go używasz
select_col <- sym("Petal.Length")

iris %>% 
  ggplot(aes(x = Sepal.Length, y = !!select_col)) +
  geom_point()
stevec
źródło