Come cambiare le etichette delle faccette?


231

Ho usato il seguente ggplotcomando:

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

produrre

testo alternativo

Vorrei cambiare le etichette delle sfaccettature , tuttavia, in qualcosa di più corto (come Hosp 1, Hosp 2...) perché ora sono troppo lunghe e sembrano strette (aumentare l'altezza del grafico non è un'opzione, richiederebbe troppo spazio in il documento). Ho dato un'occhiata alla pagina di aiuto di facet_grid ma non riesco a capire come.

Risposte:


124

Cambia i nomi dei livelli dei fattori sottostanti con qualcosa del tipo:

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

12
@wishihadabettername: per evitare di modificare i dati sottostanti, è possibile utilizzare: ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Arnaud A

1
correlate ... se si desidera che l'etichetta del pannello sia un'espressione di bquote () (ad es. levels(x$measurements) <- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))) , non verrà visualizzata nell'espressione matematica. Come si potrebbero mostrare le espressioni come etichette di sfaccettatura?
Brian D,

correlati per includere espressioni nell'etichetta delle faccette, utilizzare l' labelleropzione per facet_grid: stackoverflow.com/questions/37089052/…
Brian D,

285

Ecco una soluzione che evita la modifica dei dati:

groupSupponi che la tua trama sia sfaccettata dalla parte del tuo frame di dati, che ha livelli control, test1, test2, quindi crea un elenco chiamato da quei valori:

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

Quindi crea una funzione "etichettatrice" e inseriscila nella tua chiamata 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)
 ...

Questo utilizza i livelli del frame di dati per indicizzare l'elenco hospital_names, restituendo i valori dell'elenco (i nomi corretti).


Nota che funziona solo se hai una sola variabile di sfaccettatura. Se si hanno due sfaccettature, la funzione dell'etichettatrice deve restituire un vettore diverso per ogni sfaccettatura. Puoi farlo con qualcosa del tipo:

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

Dove facet1_namese facet2_namessono elenchi predefiniti di nomi indicizzati dai nomi degli indici delle faccette ("Hostpital # 1", ecc.).


Modifica: il metodo sopra riportato fallisce se si passa una combinazione variabile / valore che l'etichettatrice non conosce. È possibile aggiungere un fail-safe per variabili sconosciute come questa:

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

Risposta adattata da come cambiare le etichette strip.text in ggplot con facet e margin = TRUE


modifica: ATTENZIONE : se stai usando questo metodo per sfaccettare da una colonna di caratteri , potresti avere etichette errate. Vedi questo bug report . risolto nelle versioni recenti di ggplot2.


9
Bello, ma non funzionerà con facet_wrap, mentre la soluzione @Vince funzionerà anche con facet_wrap.
Arnaud A

@ArnaudAmzallag: Corretto, anche se se qualcuno ha voglia di donare un po 'di tempo, potrebbe farlo in futuro .
naught101

Aggiunto un fail-safe per variabili di sfaccettatura sconosciute.
naught101

16
Avviso: questo non funziona in ggplot2 v.2 - la funzione etichettatrice è cambiata. @mbirons risposta funziona stackoverflow.com/a/34811062/162832
Andreas

Interessante, ma non sempre funziona, mentre la modifica dei fattori funziona sempre.
Patrick

214

Ecco un'altra soluzione che è nello spirito di quella data da @ naught101, ma più semplice e non lancia un avvertimento sull'ultima versione di ggplot2.

Fondamentalmente, devi prima creare un vettore di caratteri con nome

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

E poi lo usi come un'etichettatrice, semplicemente modificando l'ultima riga del codice dato da @ naught101 a

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

Spero che questo ti aiuti.


In quale versione di ggplot2 è as_labellerpresente? Ho trovato del codice sorgente sul repository CRAN GitHub , ma dopo l'aggiornamento all'ultima versione (su CRAN!) Sembra che non abbia la funzione.
n1k31t4,

Quello è strano. Ho anche aggiornato tramite CRAN. Ecco la documentazione docs.ggplot2.org/dev/as_labeller.html
mbiron

4
Questo è fico. Cosa succede quando hai due variabili nella griglia delle faccette? Ti piace hospital ~ gendero qualcosa del genere? C'è un modo per usare le etichettatrici su entrambi gli assi? Non riesco a vedere nulla di ovvio nei documenti.
naught101

3
Nota se hai iniziato con la risposta di nulla, questa funziona solo con c () e non con un elenco () .
thomas88wp,

1
Una grande parte di ciò è che funziona con entrambi gli assi della griglia delle faccette!
Calum,

30

Ecco come l'ho fatto facet_grid(yfacet~xfacet)usando ggplot2, versione 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")
    )
)

Nota che questo non contiene una chiamata a as_labeller()- qualcosa con cui ho lottato per un po '.

Questo approccio si ispira all'ultimo esempio nella pagina di aiuto Funzione da forzare a etichettatrice .


questo funziona !!! Non sono stato in grado di applicare le altre soluzioni perché alcune delle soluzioni suggerite sono state deprecate sulle attuali versioni di ggplot2.
yanes

È possibile costruire questi vettori denominati con setNames() stackoverflow.com/a/22428439/3362993
jsta

23

Se hai due facce hospitale roomvuoi rinominarne solo una, puoi usare:

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

Per rinominare due sfaccettature usando l'approccio basato su vettori (come nella risposta di naught101), puoi fare:

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

16

Il modo più semplice per cambiare SENZA modificare i dati sottostanti è:

1) Creare un oggetto utilizzando la as_labellerfunzione aggiungendo il segno di spunta posteriore per ciascuno dei valori predefiniti :

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) Aggiungiamo nel GGplot:

ggplot(dataframe, aes(x=Temperature.C,y=fit))+geom_line()+ facet_wrap(~Humidity.RH., nrow=2,labeller=hum.names)

1
Questo penso sia il metodo più elegante - è efficace e funziona con la versione 3.0.0.9000 di ggplot2
Landak,

9

Nota che questa soluzione non funzionerà bene nel caso in cui ggplot mostrasse meno fattori di quelli effettivamente contenuti nella tua variabile (cosa che potrebbe accadere se tu fossi stato per esempio un sottoinsieme):

 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)

Una soluzione semplice (oltre ad aggiungere tutti i fattori inutilizzati in names_li, che può essere noioso) è eliminare i fattori inutilizzati con droplevels (), nel set di dati originale o nella funzione labbeler, vedere:

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)

9

Questa soluzione è molto simile a quella di @domi, ma è progettata per abbreviare il nome recuperando le prime 4 lettere e l'ultimo numero.

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

inserisci qui la descrizione dell'immagine


6

Entrambi facet_wrape facet_gridaccettano anche input da ifelsecome argomento. Quindi, se la variabile utilizzata per le sfaccettature è logica, la soluzione è molto semplice:

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

Se la variabile ha più categorie, l' ifelseistruzione deve essere nidificata .

Come effetto collaterale, ciò consente anche di creare la sfaccettatura dei gruppi all'interno della ggplotchiamata.


5

Aggiunta di un'altra soluzione simile a @ domi con l'analisi di simboli matematici, apice, pedice, parentesi / parentesi, .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}, "]"))))

Creato il 30-03-2019 dal pacchetto reprex (v0.2.1.9000)



3

Penso che tutte le altre soluzioni siano davvero utili per farlo, ma c'è ancora un altro modo.

Presumo:

  • hai installato il dplyrpacchetto, che ha il mutatecomando conveniente , e
  • il tuo set di dati è denominato survey.

    indagine%>% mutato (Hosp1 = Hospital1, Hosp2 = Hospital2, ........)

Questo comando ti aiuta a rinominare le colonne, ma tutte le altre colonne vengono mantenute.

Quindi fai lo stesso facet_wrap, ora stai bene.


mi dispiace, non funziona in quanto cambia anche il contenuto della colonna
Jens

3

La definizione della funzione etichettatrice con variable, valuecome argomenti non avrebbe funzionato per me. Inoltre, se si desidera utilizzare l'espressione, è necessario utilizzare lapply e non si può semplicemente utilizzare arr[val], poiché l'argomento della funzione è data.frame.

Questo codice ha funzionato:

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)

3

Dal momento che non mi è ancora permesso commentare i post, sto pubblicando questo separatamente come un addendum alla risposta di Vince e alla risposta di son520804 . Il merito va a loro.

Son520804:

utilizzando i dati dell'iride:

Presumo:
tu abbia installato il pacchetto dplyr, che ha il comodo comando mutate, e il tuo set di dati si chiama survey. survey %>% mutate(Hosp1 = Hospital1, Hosp2 = Hospital2,........) Questo comando ti aiuta a rinominare le colonne, ma tutte le altre colonne vengono mantenute. Quindi fai lo stesso facet_wrap, ora stai bene.

Usando l'esempio dell'iride di Vince e il codice parziale di son520804, l'ho fatto con la funzione mutate e ho raggiunto una soluzione semplice senza toccare il set di dati originale. Il trucco è creare un vettore di nomi stand-in e usare mutate () all'interno della pipe per correggere temporaneamente i nomi delle faccette:

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

In questo esempio puoi vedere che i livelli di i $ Species sono temporaneamente cambiati in corrispondenti nomi comuni contenuti nel vettore new_names. La riga contenente

mutate(Species=new_names) %>%

può essere rimosso facilmente per rivelare la denominazione originale.

Avvertenza: questo può facilmente introdurre errori nei nomi se il vettore new_name non è impostato correttamente. Probabilmente sarebbe molto più pulito usare una funzione separata per sostituire le stringhe variabili. Tieni presente che potrebbe essere necessario ripetere il vettore new_name in diversi modi per abbinare l'ordine del set di dati originale. Si prega di controllare due volte e tre volte che ciò sia stato realizzato correttamente.


Potrebbe essere un po 'più bello da usare: new_names <- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris')e quindi nel mutazione potresti creare una nuova colonna in questo modo:mutate(Spec = new_names[Species])
filups21

3

Questo funziona per me.

Definire un fattore:

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

e utilizzare, in ggplot():

facet_grid( hospitals.factor[hospital] ~ . )

2

Solo estendendo la risposta di naught101 - il merito va a lui

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

Quello che devi fare è creare un elenco con la mappatura da nome a nome

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

e ridefinire plot_labeller()con nuovi argomenti predefiniti:

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

E poi:

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

In alternativa, puoi creare una funzione dedicata per ciascuna delle modifiche alle etichette che desideri avere.


2

Ho un altro modo per raggiungere lo stesso obiettivo senza modificare i dati sottostanti:

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

Quello che ho fatto sopra è cambiare le etichette del fattore nel frame di dati originale, e questa è l'unica differenza rispetto al tuo codice originale.


1

Hai provato a cambiare i livelli specifici del tuo Hospitalvettore?

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"

1

Sento che dovrei aggiungere la mia risposta a questo perché mi ci è voluto molto tempo per farlo funzionare:

Questa risposta è per te se:

  • non si desidera modificare i dati originali
  • se hai bisogno di espressioni ( bquote) nelle etichette e
  • se si desidera la flessibilità di un vettore nome-etichetta separato

Fondamentalmente ho messo le etichette in un vettore con nome in modo che le etichette non vengano confuse o scambiate. L' labellerespressione potrebbe probabilmente essere più semplice, ma almeno questo funziona (i miglioramenti sono molto graditi). Nota le `(virgolette posteriori) per proteggere il fattore di sfaccettatura.

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

inserisci qui la descrizione dell'immagine


1

Soluzione semplice (da qui ):

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)

0

Dopo aver lottato per un po ', quello che ho scoperto è che possiamo usare fct_relevel()e fct_recode()da forcatscongiuntamente per cambiare l'ordine delle sfaccettature e fissare anche le etichette delle sfaccettature. Non sono sicuro che sia supportato dal design, ma funziona! Dai un'occhiata ai grafici qui sotto:

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

Creato il 2020-02-16 dal pacchetto reprex (v0.3.0)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.