Comment changer les étiquettes des facettes?

231

J'ai utilisé la ggplotcommande suivante :

ggplot(survey, aes(x = age)) + stat_bin(aes(n = nrow(h3), y = ..count.. / n), binwidth = 10)
  + scale_y_continuous(formatter = "percent", breaks = c(0, 0.1, 0.2))
  + facet_grid(hospital ~ .)
  + theme(panel.background = theme_blank())

produire

texte alternatif

J'aimerais changer les étiquettes de facette , cependant, en quelque chose de plus court (comme Hosp 1, Hosp 2...) car elles sont trop longues maintenant et semblent étroites (augmenter la hauteur du graphique n'est pas une option, cela prendrait trop de place dans le document). J'ai regardé la page d'aide de facet_grid mais je ne sais pas comment.

wishihadabettername
la source

Réponses:

125

Modifiez les noms de niveau de facteur sous-jacents avec quelque chose comme:

# Using the Iris data
> i <- iris
> levels(i$Species)
[1] "setosa"     "versicolor" "virginica" 
> levels(i$Species) <- c("S", "Ve", "Vi")
> ggplot(i, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Vince
la source
13
@wishihadabettername: Pour éviter de modifier les données sous-jacentes, vous pouvez utiliser: ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Arnaud A
1
connexes ... si vous voulez que l'étiquette du panneau soit une expression bquote () (par exemple, levels(x$measurements) <- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))) elle n'apparaîtra pas dans l'expression mathématique. Comment afficher des expressions sous forme d'étiquettes de facettes?
Brian D
liés pour inclure des expressions dans l'étiquette de facette, utilisez l' labelleroption pour facet_grid: stackoverflow.com/questions/37089052/…
Brian D
286

Voici une solution qui évite de modifier vos données:

Supposons que votre tracé soit facetté par la grouppartie de votre trame de données, qui a des niveaux control, test1, test2, puis créez une liste nommée par ces valeurs:

hospital_names <- list(
  'Hospital#1'="Some Hospital",
  'Hospital#2'="Another Hospital",
  'Hospital#3'="Hospital Number 3",
  'Hospital#4'="The Other Hospital"
)

Créez ensuite une fonction 'étiqueteuse' et poussez-la dans votre appel facet_grid:

hospital_labeller <- function(variable,value){
  return(hospital_names[value])
}

ggplot(survey,aes(x=age)) + stat_bin(aes(n=nrow(h3),y=..count../n), binwidth=10)
 + facet_grid(hospital ~ ., labeller=hospital_labeller)
 ...

Celui-ci utilise les niveaux de la trame de données pour indexer la liste hospital_names, renvoyant les valeurs de la liste (les noms corrects).


Veuillez noter que cela ne fonctionne que si vous n'avez qu'une seule variable de facettage. Si vous avez deux facettes, votre fonction d'étiqueteuse doit renvoyer un vecteur de nom différent pour chaque facette. Vous pouvez le faire avec quelque chose comme:

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else {
    return(facet2_names[value])
  }
}

facet1_nameset facet2_namessont des listes prédéfinies de noms indexés par les noms d'index de facette ('Hostpital # 1', etc.).


Modifier: la méthode ci-dessus échoue si vous transmettez une combinaison variable / valeur que l'étiqueteuse ne connaît pas. Vous pouvez ajouter une sécurité intégrée pour les variables inconnues comme celle-ci:

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else if (variable=='facet2') {
    return(facet2_names[value])
  } else {
    return(as.character(value))
  }
}

Réponse adaptée de la façon de changer les étiquettes strip.text dans ggplot avec facette et marge = VRAI


edit: AVERTISSEMENT : si vous utilisez cette méthode pour créer une facette par une colonne de caractères , vous pouvez obtenir des étiquettes incorrectes. Voir ce rapport de bogue . corrigé dans les versions récentes de ggplot2.

naught101
la source
9
Bien, mais ne fonctionnera pas avec facet_wrap, tandis que la solution @Vince fonctionnera également avec facet_wrap.
Arnaud A
@ArnaudAmzallag: Exact, bien que si quelqu'un a envie de donner du temps, cela pourrait le devenir à l'avenir .
naught101
Ajout d'une sécurité intégrée pour les variables de facettage inconnues.
naught101
16
Remarque: cela ne fonctionne pas dans ggplot2 v.2 - la fonction d'étiqueteuse a changé. @mbirons answer works stackoverflow.com/a/34811062/162832
Andreas
Intéressant, mais cela ne fonctionne pas toujours, contrairement à l'édition des facteurs.
PatrickT
214

Voici une autre solution qui est dans l'esprit de celle donnée par @ naught101, mais plus simple et ne lance pas non plus d'avertissement sur la dernière version de ggplot2.

Fondamentalement, vous créez d'abord un vecteur de caractères nommé

hospital_names <- c(
                    `Hospital#1` = "Some Hospital",
                    `Hospital#2` = "Another Hospital",
                    `Hospital#3` = "Hospital Number 3",
                    `Hospital#4` = "The Other Hospital"
                    )

Et puis vous l'utilisez comme étiqueteuse, simplement en modifiant la dernière ligne du code donné par @ naught101 en

... + facet_grid(hospital ~ ., labeller = as_labeller(hospital_names))

J'espère que cela t'aides.

mbiron
la source
Dans quelle version de ggplot2 se trouve as_labeller? J'ai trouvé du code source sur le référentiel CRAN GitHub , mais après la mise à niveau vers la dernière version (sur CRAN!), Je ne semble pas avoir la fonction.
n1k31t4
C'est bizarre. J'ai également mis à jour via CRAN. Voici la documentation docs.ggplot2.org/dev/as_labeller.html
mbiron
4
C'est cool. Que se passe-t-il quand vous avez deux variables dans votre grille de facettes? Comme hospital ~ genderou quelque chose? Existe-t-il un moyen d'utiliser des étiqueteuses sur les deux axes? Je ne vois rien d'évident dans les documents.
naught101
3
Notez que si vous avez commencé avec la réponse de rien, celle-ci ne fonctionne qu'avec un c () et non une liste () .
thomas88wp
1
Une grande partie de cela est que cela fonctionne avec les deux axes de la grille de facettes!
Calum You du
30

Voici comment je l'ai fait avec facet_grid(yfacet~xfacet)ggplot2, version 2.2.1:

facet_grid(
    yfacet~xfacet,
    labeller = labeller(
        yfacet = c(`0` = "an y label", `1` = "another y label"),
        xfacet = c(`10` = "an x label", `20` = "another x label")
    )
)

Notez que cela ne contient pas d'appel à as_labeller()- quelque chose avec lequel j'ai lutté pendant un certain temps.

Cette approche est inspirée du dernier exemple de la page d'aide Fonction Coerce to Labeller .

bovender
la source
cela marche!!! Je n'ai pas pu appliquer les autres solutions car certaines des solutions suggérées étaient obsolètes sur les versions actuelles de ggplot2.
yanes
Vous pouvez construire ces vecteurs nommés avec setNames() stackoverflow.com/a/22428439/3362993
jsta
23

Si vous avez deux facettes hospitalet roomque vous souhaitez renommer une seule, vous pouvez utiliser:

facet_grid( hospital ~ room, labeller = labeller(hospital = as_labeller(hospital_names)))

Pour renommer deux facettes à l'aide de l'approche vectorielle (comme dans la réponse de naught101), vous pouvez faire:

facet_grid( hospital ~ room, labeller = labeller(hospital = as_labeller(hospital_names),
                                                 room = as_labeller(room_names)))
domi
la source
16

Le moyen LE PLUS FACILE de changer SANS modifier les données sous-jacentes est:

1) Créez un objet en utilisant la as_labellerfonction en ajoutant la coche arrière pour chacune des valeurs par défaut :

hum.names <- as_labeller(c(`50` = "RH% 50", `60` = "RH% 60",`70` = "RH% 70", `80` = "RH% 80",`90` = "RH% 90", `100` = "RH% 100")) #Necesarry to put RH% into the facet labels

2) Nous ajoutons dans le GGplot:

ggplot(dataframe, aes(x=Temperature.C,y=fit))+geom_line()+ facet_wrap(~Humidity.RH., nrow=2,labeller=hum.names)
Leinfloyd
la source
1
Je pense que c'est la méthode la plus élégante - elle est efficace et fonctionne avec ggplot2 version 3.0.0.9000
Landak
9

Notez que cette solution ne fonctionnera pas bien dans le cas où ggplot affichera moins de facteurs que votre variable ne contient réellement (ce qui pourrait arriver si vous aviez par exemple été un sous-ensemble):

 library(ggplot2)
 labeli <- function(variable, value){
  names_li <- list("versicolor"="versi", "virginica"="virg")
  return(names_li[value])
 }

 dat <- subset(iris,Species!="setosa")
 ggplot(dat, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ ., labeller=labeli)

Une solution simple (en plus d'ajouter tous les facteurs inutilisés dans names_li, ce qui peut être fastidieux) consiste à supprimer les facteurs inutilisés avec droplevels (), soit dans l'ensemble de données d'origine, soit dans la fonction labbeler, voir:

labeli2 <- function(variable, value){
  value <- droplevels(value)
  names_li <- list("versicolor"="versi", "virginica"="virg")
  return(names_li[value])
}

dat <- subset(iris,Species!="setosa")
ggplot(dat, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ ., labeller=labeli2)
Matifou
la source
9

Cette solution est très proche de celle de @domi, mais est conçue pour raccourcir le nom en récupérant les 4 premières lettres et le dernier numéro.

library(ggplot2)

# simulate some data
xy <- data.frame(hospital = rep(paste("Hospital #", 1:3, sep = ""), each = 30),
                 value = rnorm(90))

shortener <- function(string) {
  abb <- substr(string, start = 1, stop = 4) # fetch only first 4 strings
  num <- gsub("^.*(\\d{1})$", "\\1", string) # using regular expression, fetch last number
  out <- paste(abb, num) # put everything together
  out
}

ggplot(xy, aes(x = value)) +
  theme_bw() +
  geom_histogram() +
  facet_grid(hospital ~ ., labeller = labeller(hospital = shortener))

entrez la description de l'image ici

Roman Luštrik
la source
6

Les deux facet_wrapet facet_gridacceptent également l'entrée de ifelsecomme argument. Donc, si la variable utilisée pour le facettage est logique, la solution est très simple:

facet_wrap(~ifelse(variable, "Label if true", "Label if false"))

Si la variable a plus de catégories, l' ifelseinstruction doit être imbriquée .

Comme effet secondaire, cela permet également de créer des groupes à facettes dans l' ggplotappel.

lillemets
la source
5

Ajout d'une autre solution similaire à @ domi avec analyse des symboles mathématiques, exposant, indice, parenthèse / parenthèse, .etc.

library(tidyverse)
theme_set(theme_bw(base_size = 18))

### create separate name vectors
# run `demo(plotmath)` for more examples of mathematical annotation in R
am_names <- c(
  `0` = "delta^{15}*N-NO[3]^-{}",
  `1` = "sqrt(x,y)"
)

# use `scriptstyle` to reduce the size of the parentheses &
# `bgroup` to make adding `)` possible 
cyl_names <- c(
  `4` = 'scriptstyle(bgroup("", a, ")"))~T~-~5*"%"',
  `6` = 'scriptstyle(bgroup("", b, ")"))~T~+~10~degree*C',
  `8` = 'scriptstyle(bgroup("", c, ")"))~T~+~30*"%"'
)

ggplot(mtcars, aes(wt, mpg)) + 
  geom_jitter() +
  facet_grid(am ~ cyl,
             labeller = labeller(am  = as_labeller(am_names,  label_parsed),
                                 cyl = as_labeller(cyl_names, label_parsed))
             ) +
  geom_text(x = 4, y = 25, size = 4, nudge_y = 1,
            parse = TRUE, check_overlap = TRUE,
            label = as.character(expression(paste("Log"["10"], bgroup("(", frac("x", "y"), ")")))))

### OR create new variables then assign labels directly
# reverse facet orders just for fun
mtcars <- mtcars %>% 
  mutate(am2  = factor(am,  labels = am_names),
         cyl2 = factor(cyl, labels = rev(cyl_names), levels = rev(attr(cyl_names, "names")))
  )

ggplot(mtcars, aes(wt, mpg)) + 
  geom_jitter() +
  facet_grid(am2 ~ cyl2,
             labeller = label_parsed) +
  annotate("text", x = 4, y = 30, size = 5,
           parse = TRUE, 
           label = as.character(expression(paste("speed [", m * s^{-1}, "]"))))

Créé le 2019-03-30 par le package reprex (v0.2.1.9000)

Tung
la source
Voir aussi
Tung
3

Je pense que toutes les autres solutions sont vraiment utiles pour ce faire, mais il existe encore un autre moyen.

Je suppose:

  • vous avez installé le dplyrpackage, qui a la mutatecommande pratique , et
  • votre jeu de données est nommé survey.

    enquête%>% mutent (Hosp1 = Hospital1, Hosp2 = Hospital2, ........)

Cette commande vous aide à renommer les colonnes, mais toutes les autres colonnes sont conservées.

Faites de même facet_wrap, vous allez bien maintenant.

son520804
la source
désolé, cela ne fonctionne pas car il modifie également le contenu de la colonne
Jens
3

La définition de la fonction d'étiqueteuse avec variable, valuecomme arguments ne fonctionnerait pas pour moi. De plus, si vous souhaitez utiliser une expression, vous devez utiliser lapply et ne pouvez pas simplement utiliser arr[val], car l'argument de la fonction est un data.frame.

Ce code a fonctionné:

libary(latex2exp)
library(ggplot2)
arr <- list('virginica'=TeX("x_1"), "versicolor"=TeX("x_2"), "setosa"=TeX("x_3"))
mylabel <- function(val) { return(lapply(val, function(x) arr[x])) }
ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) + geom_line() + facet_wrap(~Species, labeller=mylabel)
reox
la source
3

Depuis que je ne suis pas encore autorisé à commenter les messages, je poste ce séparément comme additif à la réponse de Vince et la réponse de son520804 . Le crédit leur revient.

Son520804:

en utilisant les données Iris:

Je suppose:
vous avez installé le paquet dplyr, qui a la commande mutate pratique, et votre jeu de données est nommé survey. survey %>% mutate(Hosp1 = Hospital1, Hosp2 = Hospital2,........) Cette commande vous aide à renommer les colonnes, mais toutes les autres colonnes sont conservées. Ensuite, faites la même facet_wrap, vous allez bien maintenant.

En utilisant l'exemple de l'iris de Vince et le code partiel de son520804, je l'ai fait avec la fonction mutate et j'ai trouvé une solution facile sans toucher au jeu de données d'origine. L'astuce consiste à créer un vecteur de nom stand-in et à utiliser mutate () à l'intérieur du canal pour corriger temporairement les noms de facettes:

i <- iris

levels(i$Species)
[1] "setosa"     "versicolor" "virginica"

new_names <- c(
  rep("Bristle-pointed iris", 50), 
  rep("Poison flag iris",50), 
  rep("Virginia iris", 50))

i %>% mutate(Species=new_names) %>% 
ggplot(aes(Petal.Length))+
    stat_bin()+
    facet_grid(Species ~ .)

Dans cet exemple, vous pouvez voir que les niveaux de i $ Species sont temporairement modifiés en noms communs correspondants contenus dans le vecteur new_names. La ligne contenant

mutate(Species=new_names) %>%

peut facilement être retiré pour révéler le nom d'origine.

Avertissement: cela peut facilement introduire des erreurs dans les noms si le vecteur nouveau_nom n'est pas correctement configuré. Il serait probablement beaucoup plus propre d'utiliser une fonction distincte pour remplacer les chaînes variables. Gardez à l'esprit que le vecteur new_name peut devoir être répété de différentes manières pour correspondre à l'ordre de votre jeu de données d'origine. Veuillez vérifier deux fois et trois fois que ceci est correctement réalisé.

Alexander Kielland
la source
Il peut être un peu plus agréable à utiliser: new_names <- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris')puis dans le mutate, vous pouvez créer une nouvelle colonne ainsi:mutate(Spec = new_names[Species])
filups21
3

Cela fonctionne pour moi.

Définissez un facteur:

hospitals.factor<- factor( c("H0","H1","H2") )

et utiliser, dans ggplot():

facet_grid( hospitals.factor[hospital] ~ . )
Hernán Castelo
la source
2

Prolonger la réponse de naught101 - le mérite lui revient

plot_labeller <- function(variable,value, facetVar1='<name-of-1st-facetting-var>', var1NamesMapping=<pass-list-of-name-mappings-here>, facetVar2='', var2NamesMapping=list() )
{
  #print (variable)
  #print (value)
  if (variable==facetVar1) 
    {
      value <- as.character(value)
      return(var1NamesMapping[value])
    } 
  else if (variable==facetVar2) 
    {
      value <- as.character(value)
      return(var2NamesMapping[value])
    } 
  else 
    {
      return(as.character(value))
    }
}

Ce que vous devez faire est de créer une liste avec un mappage de nom à nom

clusteringDistance_names <- list(
  '100'="100",
  '200'="200",
  '300'="300",
  '400'="400",
  '600'="500"
)

et redéfinir plot_labeller()avec de nouveaux arguments par défaut:

plot_labeller <- function(variable,value, facetVar1='clusteringDistance', var1NamesMapping=clusteringDistance_names, facetVar2='', var1NamesMapping=list() )

Puis:

ggplot() + 
  facet_grid(clusteringDistance ~ . , labeller=plot_labeller) 

Vous pouvez également créer une fonction dédiée pour chacune des modifications d'étiquette que vous souhaitez avoir.

user4786271
la source
2

J'ai une autre façon d'atteindre le même objectif sans modifier les données sous-jacentes:

ggplot(transform(survey, survey = factor(survey,
        labels = c("Hosp 1", "Hosp 2", "Hosp 3", "Hosp 4"))), aes(x = age)) +
  stat_bin(aes(n = nrow(h3),y=..count../n), binwidth = 10) +
  scale_y_continuous(formatter = "percent", breaks = c(0, 0.1, 0.2)) +
  facet_grid(hospital ~ .) +
  opts(panel.background = theme_blank())

Ce que j'ai fait ci-dessus, c'est de changer les étiquettes du facteur dans le bloc de données d'origine, et c'est la seule différence par rapport à votre code d'origine.

ytu
la source
1

Avez-vous essayé de changer les niveaux spécifiques de votre Hospitalvecteur?

levels(survey$hospital)[levels(survey$hospital) == "Hospital #1"] <- "Hosp 1"
levels(survey$hospital)[levels(survey$hospital) == "Hospital #2"] <- "Hosp 2"
levels(survey$hospital)[levels(survey$hospital) == "Hospital #3"] <- "Hosp 3"
philiporlando
la source
1

Je pense que je devrais ajouter ma réponse à cela, car il m'a fallu assez de temps pour que cela fonctionne:

Cette réponse est pour vous si:

  • vous ne pas à modifier vos données d' origine
  • si vous avez besoin d' expressions ( bquote) dans vos étiquettes et
  • si vous voulez la flexibilité d'un nom-vecteur d'étiquetage séparé

J'ai essentiellement mis les étiquettes dans un vecteur nommé afin que les étiquettes ne soient pas confondues ou échangées. L' labellerexpression pourrait probablement être plus simple, mais cela fonctionne au moins (les améliorations sont les bienvenues). Notez le `(guillemets arrière) pour protéger le facteur de facette.

n <- 10
x <- seq(0, 300, length.out = n)

# I have my data in a "long" format
my_data <- data.frame(
  Type = as.factor(c(rep('dl/l', n), rep('alpha', n))),
  T = c(x, x),
  Value = c(x*0.1, sqrt(x))
)

# the label names as a named vector
type_names <- c(
  `nonsense` = "this is just here because it looks good",
  `dl/l` = Linear~Expansion~~Delta*L/L[Ref]~"="~"[%]", # bquote expression
  `alpha` = Linear~Expansion~Coefficient~~alpha~"="~"[1/K]"
  )


ggplot() + 
  geom_point(data = my_data, mapping = aes(T, Value)) + 
  facet_wrap(. ~ Type, scales="free_y", 
             labeller = label_bquote(.(as.expression(
               eval(parse(text = paste0('type_names', '$`', Type, '`')))
               )))) +
  labs(x="Temperature [K]", y="", colour = "") +
  theme(legend.position = 'none')

entrez la description de l'image ici

Dani
la source
1

Solution simple (d' ici ):

p <- ggplot(mtcars, aes(disp, drat)) + geom_point()
# Example (old labels)
p + facet_wrap(~am)


to_string <- as_labeller(c(`0` = "Zero", `1` = "One"))
# Example (New labels)
p + facet_wrap(~am, labeller = to_string)
pseudo
la source
0

Après avoir lutté pendant un certain temps, ce que j'ai trouvé, c'est que nous pouvons utiliser fct_relevel()et à fct_recode()partir forcatsde conjointement pour changer l'ordre des facettes ainsi que fixer les étiquettes des facettes. Je ne sais pas si c'est supporté par la conception, mais ça marche! Découvrez les parcelles ci-dessous:

library(tidyverse)

before <- mpg %>%
  ggplot(aes(displ, hwy)) + 
  geom_point() +
  facet_wrap(~class)
before

after <- mpg %>%
  ggplot(aes(displ, hwy)) + 
  geom_point() + 
  facet_wrap(
    vars(
      # Change factor level name
      fct_recode(class, "motorbike" = "2seater") %>% 
        # Change factor level order
        fct_relevel("compact")
    )
  )
after

Créé le 2020-02-16 par le package reprex (v0.3.0)

Ashirwad
la source