web-dev-qa-db-fra.com

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

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 en tant que couleur et groupe. C'est à dire. Je voudrais quelque chose comme ça

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

Ainsi, la colonne utilisée dans le ggplot est déterminée par le paramètre. Par exemple. pour f ("majr") on obtient l'effet de

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

mais pour f ("genre") on obtient 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 fonctionné. Pas plus que

e <- environment() 
ggplot( rates.by.groups, aes(x=name, y=rate, colour= columnName , group=columnName ), environment=e )
76
Theodore Norvell

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 transmettez 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", En chaînes.

Si, pour une raison quelconque, vous préférez ne pas utiliser aes_string, Vous pouvez le changer (un peu plus lourd):

    ggplot( rates.by.groups, aes(x=name, y=rate, colour= get(column),
                                        group=get(column) ) )
114
David Robinson

De la notes de version de ggplot2 V3.0.0:

aes () supporte maintenant la quasiquotation afin que vous puissiez utiliser !!, !!!, et: =. Ceci remplace aes_ () et aes_string (), qui sont maintenant obsolètes en logiciel (mais le resteront longtemps).

La méthode idiomatique serait maintenant de convertir en symbole la chaîne contenue dans la variable, en utilisant sym (qui est presque identique aux alias de base as.name/as.symbol), et cochez la case en utilisant !!

Simuler les données de l'OP que 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()
}

Cela fonctionnera avec les noms a.k.a. symboles AND et avec les littéraux de chaîne

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

Comme dit Lionel à propos de ensym:

il a pour but de reproduire la syntaxe des arguments pour lesquels vous pouvez fournir les deux dans le LHS, par exemple liste (nue = 1, "cité" = 2)


Une note sur enquo

enquoquote l'expression (pas nécessairement un symbole) introduite dans l'argument, elle ne convertit pas un littéral de chaîne en symbole comme ensym, de sorte qu'elle pourrait être moins adaptée 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)
30
Moody_Mudskipper

Essayez d'utiliser aes_string au lieu de aes.

12
MDe

Une autre option (ggplot2 > 3.0.0) consiste à utiliser le pronom d'évaluation ordonné .data pour découper la variable/colonne choisie de la rates.by.groups trame de donné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 2019-04-04 par le paquetage reprex (v0.2.1.9000)

6
Tung