web-dev-qa-db-fra.com

ggplot: Comment changer les étiquettes de facettes?

J'ai utilisé la commande suivante ggplot:

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 ~ .) 
  + opts(panel.background = theme_blank()) 

produire

alt text

Je voudrais cependant changer les étiquettes facet en quelque chose de plus court (comme Hosp 1, Hosp 2 ...) car elles sont trop longues maintenant et ont l’air étriquées (augmenter la hauteur du graphique n’est pas une option). , cela prendrait trop de place dans le document). J'ai regardé la page facet_grid help mais je ne sais pas comment.

182
wishihadabettername

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 ~ .)
104
Vince

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

Supposons que votre parcelle est facettée par la partie group de votre cadre de données, qui a les 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 insérez-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)
 ...

Ceci utilise les niveaux du cadre de données pour indexer la liste hospital_names, en renvoyant les valeurs de la liste (les noms corrects).


Veuillez noter que cela ne fonctionne que si vous n'avez qu'une seule variable facettée. Si vous avez deux facettes, votre fonction d'étiquetage 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_names et facet2_names sont des listes prédéfinies de noms indexés par les noms d'index de facettes ('Hostpital # 1', etc.).


Edit: 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é intrinsèque aux variables inconnues, comme ceci:

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 comment changer les étiquettes strip.text dans ggplot avec facette et marge = TRUE


edit: WARNING: si vous utilisez cette méthode comme facette avec une colonne caractère, vous obtiendrez peut-être des étiquettes incorrectes. Voir ce rapport de bogue . corrigé dans les versions récentes de ggplot2.

249
naught101

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

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

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

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

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

J'espère que cela t'aides.

170
mbiron

Voici comment je l'ai fait avec facet_grid(yfacet~xfacet) en utilisant 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 moment.

Cette approche s’inspire du dernier exemple de la page d’aide Fonction de forçage en étiqueteuse

20
bovender

Si vous avez deux facettes hospital et room mais que vous souhaitez renommer une seule, vous pouvez utiliser:

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

Pour renommer deux facettes en utilisant 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)))
18
domi

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

 enter image description here

7
Roman Luštrik

Notez que cette solution ne fonctionnera pas correctement si ggplot affichera moins de facteurs que votre variable n'en contient (ce qui pourrait arriver si vous aviez par exemple sous-défini):

 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 s'avérer fastidieux) consiste à supprimer les facteurs inutilisés avec droplevels (), soit dans le jeu 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)
7
Matifou

facet_wrap et facet_grid acceptent également les entrées de ifelse en tant qu'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'instruction ifelse doit être imbriquée .

En tant qu'effet secondaire, cela permet également à la création des groupes d'être facettée dans l'appel ggplot.

4
lillemets

Ajout d'une autre solution similaire à @ domi avec l'analyse de symboles mathématiques, exposant, indice, parenthèse/crochet, .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 paquet reprex (v0.2.1.9000)

3
Tung

La définition de la fonction d'étiquetage avec variable, value comme argument ne fonctionnerait pas pour moi. De même, si vous souhaitez utiliser une expression, vous devez utiliser lapply et ne pas simplement utiliser arr[val], car l'argument de la fonction est un nom 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)
2
reox

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

Je suppose:

  • vous avez installé le paquetage dplyr, qui contient la commande pratique mutate, et 
  • votre jeu de données s'appelle survey.

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

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

Ensuite, faites la même chose avec facet_wrap, tout va bien maintenant. 

2
son520804

Étant donné que je ne suis pas encore autorisé à commenter les messages, je le publie séparément sous la forme d'un addendum à 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 package dplyr, qui contient la commande pratique mutate, et votre jeu de données s'appelle 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 chose 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 obtenu une solution simple sans toucher au jeu de données d'origine . L'astuce consiste à créer un vecteur de nom de remplacement et à utiliser mutate (). à l'intérieur du tuyau 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.

Mot d'avertissement: Cela peut facilement introduire des erreurs dans les noms si le vecteur new_name n'est pas correctement configuré. Il serait probablement beaucoup plus propre d'utiliser une fonction distincte pour remplacer les chaînes de variables. N'oubliez pas 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. S'il vous plaît double et triple vérifier que cela est correctement réalisé.

2
Alexander Kielland

Le moyen le plus facile de changer sans modifier les données sous-jacentes est:

1) Créez un objet à l'aide de la fonction as_labeller 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)
1
Leinfloyd

J'ai un autre moyen d'atteindre le même objectif sans changer 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 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.

1
ytu

Étendre juste 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 en nom

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

et redéfinissez plot_labeller() avec les nouveaux arguments par défaut:

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

Et alors:

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 apporter.

1
user4786271

Cela fonctionne pour moi.

Définir un facteur:

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

et utiliser, en ggplot():

facet_grid( hospitals.factor[hospital] ~ . )
0
Hernán Castelo

Avez-vous essayé de modifier les niveaux spécifiques de votre vecteur Hospital?

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"
0
spacedSparking