Comment utiliser une variable pour spécifier le nom de la colonne dans ggplot

107

J'ai une commande ggplot

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

à l'intérieur d'une fonction. Mais j'aimerais pouvoir utiliser un paramètre de la fonction pour choisir la colonne à utiliser comme couleur et groupe. Ie je voudrais quelque chose comme ça

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

Pour que la colonne utilisée dans le ggplot soit déterminée par le paramètre. Par exemple, pour f ("majr"), nous obtenons l'effet de

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

mais pour f ("gender") nous obtenons l'effet de

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

Certaines choses que j'ai essayées:

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

n'a pas marché. Pas plus que

e <- environment() 
ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ), environment=e )
Théodore Norvell
la source

Réponses:

163

Vous pouvez utiliser aes_string:

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

tant que vous passez la colonne à la fonction sous forme de chaîne ( f("majr")plutôt que f(majr)). Notez également que nous avons changé les autres colonnes, "name"et "rate", pour être des chaînes.

Si, pour une raison quelconque, vous préférez ne pas l'utiliser aes_string, vous pouvez le changer en (le plus encombrant):

    ggplot( rates.by.groups, aes(x=name, y=rate, colour= get(column),
                                        group=get(column) ) )
David Robinson
la source
Cela vaut la peine de dire que vous ne devriez pas / ne pouvez pas faire aes_string(x = rates.by.groups$name..., et de toute façon vous n'en avez pas besoin puisque vous avez déjà passé l' ggplot(data = rates.by.groups...argument. (Le problème dans cette question )
smci
3
Il suffit d'ajouter une note pour diriger les gens vers la réponse de Moody_Mudskipper avec des mises à jour pour ggplot2 version 3.0.0
Gregor Thomas
@buncis Ce n'est pas vrai, citer "column_name"ou "column"ne fonctionnerait pas
David Robinson
@DavidRobinson désolé mon erreur, je ne vois pas que le code est enveloppé sur une fonction avec paramètre, je vais supprimer mon commentaire
buncis
"lourd"? L'évaluation non standard dans R est ironiquement la "fonctionnalité" la plus encombrante que j'aie jamais rencontrée dans un langage de programmation. Vraiment exaspérant.
jessexknight le
45

D'après les notes de version de ggplot2 V3.0.0:

aes () prend désormais en charge la quasiquotation afin que vous puissiez utiliser !!, !!! et: =. Cela remplace aes_ () et aes_string () qui sont désormais obsolètes (mais qui resteront longtemps).

La manière idiomatique maintenant serait de convertir en symbole la chaîne que la variable contient, en utilisant sym()(qui est presque le même que les alias de base as.name()/ as.symbol()), et de la décompresser en utilisant!!

Simuler les données d'OP, nous pouvons faire:

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)

Si nous préférons donner des noms bruts à la fonction, nous pouvons faire:

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

Il fonctionnera avec des noms aka symboles ET avec des chaînes littérales

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

Comme le dit Lionel ensym():

il est destiné à imiter la syntaxe des arguments où vous pouvez fournir les deux dans la LHS, par exemple liste (bare = 1, "quoted" = 2)


Une note sur enquo()

enquo()cite l'expression (pas nécessairement un symbole) fournie à l'argument, il ne convertit pas une chaîne littérale en symbole comme le ensym()fait donc il pourrait être moins adapté ici, mais nous pouvons le faire:

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
la source
12
Ce truc tidyeval est tellement ennuyeux. La documentation en aes()elle-même en parle enquo()mais ne fonctionne pas. Et qui en a déjà entendu parler ensym()? BIG SIGH
CoderGuy123
@Moody_Mudskipper Pour f2, les quatre exemples fonctionnent, tout comme la capture du nom de la colonne dans une variable (ie aname <- "mjr"; f2(aname)). Si j'ajoute du code pour manipuler le bloc de données en l'utilisant, dplyril tente de trouver une colonne en utilisant le nom de la variable et non la chaîne dans le nom de la variable. En d'autres termes, comment puis-je me rendre rates.by.groups %>% group_by(!!column)...au travail tout en soutenant les trois modes d'appels f2?
steveb
1
"il en va de même pour la capture du nom de la colonne dans une variable": cela n'échoue pas mais il ne renvoie pas le même résultat, ensymest conçu pour traiter les arguments fournis sous forme de noms et tolère les guillemets autour d'eux. Je crois que vous aimeriez traiter l'argument comme un nom et vous rabattre sur la valeur si le nom n'est pas trouvé. C'est en fait ce qui se passe avec select, mais pas avec group_by... Il est possible de pirater mais pas évident. Si c'est important pour vous, je pense qu'il mériterait sa propre question.
Moody_Mudskipper
@Moody_Mudskipper Merci. J'utilisais les deux selectet group_byc'était probablement le problème. Je peux créer une nouvelle question, mais je dois trouver un exemple simple et vérifier si une réponse a été donnée. Je peux le poster sinon.
steveb
Comment utiliser !! en cas de facet_grid? Cela fonctionne avec facet_grid(cols = vars(!!column))mais génère une erreur avecfacet_grid(~ !!column)
mRiddle
14

Essayez d'utiliser à la aes_stringplace de aes.

MDe
la source
5
C'est un bon conseil, mais pouvez-vous leur dire pourquoi? aes_string vous fait utiliser "" pour les non-variables et vous utilisez des variables sans guillemets. aes_string (x = "foo", y = "fee", group = variable)
mtelesha
@mtelesha peut-être parce que la variable a une chaîne comme valeur
buncis
10

Une autre option ( ggplot2 > 3.0.0) consiste à utiliser le pronom d'évaluation ordonné .datapour découper la variable / colonne choisie dans le bloc de rates.by.groupsdonnées.

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

Créé le 04/04/2019 par le package reprex (v0.2.1.9000)

Tung
la source
1

L'utilisation aes_stringrésout ce problème, mais rencontre un problème lors de l'ajout de barres d'erreur geom_errorbar. Voici une solution simple.

#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, vous pouvez également ajouter des facettes à votre tracé en utilisant ces lignes à l'intérieur du ggplot:

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

Ce script a été modifié à partir de ce message d'origine: ggplot2 - Barres d'erreur utilisant une fonction personnalisée

Marty999
la source
0

Voici un exemple extrêmement simple.

Fais juste deux choses

  1. Transformez la chaîne en symbole
  2. Ajoutez !!quand vous l'utilisez
select_col <- sym("Petal.Length")

iris %>% 
  ggplot(aes(x = Sepal.Length, y = !!select_col)) +
  geom_point()
stevec
la source