¿Cómo cambiar las etiquetas de faceta?

231

He usado el siguiente 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())

para producir

texto alternativo

Sin embargo, me gustaría cambiar las etiquetas de faceta a algo más corto (como Hosp 1, Hosp 2...) porque ahora son demasiado largas y se ven apretadas (aumentar la altura del gráfico no es una opción, tomaría demasiado espacio en el documento). Miré la página de ayuda de facet_grid pero no puedo entender cómo.

wishihadabettername
fuente

Respuestas:

124

Cambie los nombres de nivel de factor subyacentes con algo como:

# 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
fuente
12
@wishihadabettername: Para evitar cambiar los datos subyacentes, puede usar: ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
Arnaud A
1
relacionado ... si desea que la etiqueta del panel sea una expresión bquote () (por ejemplo, levels(x$measurements) <- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))) no aparecerá en la expresión matemática. ¿Cómo se mostrarían las expresiones como etiquetas de faceta?
Brian D
relacionado para incluir expresiones en la etiqueta de faceta, use la labelleropción para facet_grid: stackoverflow.com/questions/37089052/…
Brian D
285

Aquí hay una solución que evita editar sus datos:

Digamos que su trama está facetada por la groupparte de su marco de datos, que tiene niveles control, test1, test2, luego cree una lista nombrada por esos valores:

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

Luego cree una función 'etiquetadora' y empújela en su llamada 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)
 ...

Utiliza los niveles del marco de datos para indexar la lista hospital_names, devolviendo los valores de la lista (los nombres correctos).


Tenga en cuenta que esto solo funciona si solo tiene una variable de facetado. Si tiene dos facetas, entonces su función de etiquetado debe devolver un vector de nombre diferente para cada faceta. Puedes hacer esto con algo como:

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

Dónde facet1_namesy facet2_namesson listas predefinidas de nombres indexados por los nombres de índice de faceta ('Hostpital # 1', etc.).


Editar: el método anterior falla si pasa una combinación de variable / valor que el etiquetador no conoce. Puede agregar una prueba de fallas para variables desconocidas como esta:

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

Respuesta adaptada de cómo cambiar las etiquetas strip.text en ggplot con faceta y margen = VERDADERO


editar: ADVERTENCIA : si está utilizando este método para facetar por una columna de caracteres , es posible que obtenga etiquetas incorrectas. Ver este informe de error . corregido en versiones recientes de ggplot2.

nada101
fuente
99
Agradable, pero no funcionará con facet_wrap, mientras que la solución @Vince también funcionará con facet_wrap.
Arnaud A
@ArnaudAmzallag: Correcto, aunque si alguien tiene ganas de donar algo de tiempo, podría hacerlo en el futuro .
naught101
Se agregó una prueba de fallas para variables de facetas desconocidas.
naught101
16
Aviso: Esto no funciona en ggplot2 v.2: la función de etiquetado ha cambiado. @mbirons answer works stackoverflow.com/a/34811062/162832
Andreas
Interesante, pero esto no siempre funciona, mientras que editar los factores siempre lo hace.
PatrickT
214

Aquí hay otra solución que está en el espíritu de la dada por @ naught101, pero más simple y tampoco arroja una advertencia sobre la última versión de ggplot2.

Básicamente, primero crea un vector de caracteres con nombre

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

Y luego lo usa como etiquetador, simplemente modificando la última línea del código dada por @ naught101 para

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

Espero que esto ayude.

mbiron
fuente
¿En qué versión de ggplot2 está as_labeller? Encontré un código fuente en el repositorio CRAN GitHub , pero después de actualizar a la última versión (¡en CRAN!) No parece tener la función.
n1k31t4
Eso es raro. También actualicé a través de CRAN. Aquí está la documentación docs.ggplot2.org/dev/as_labeller.html
mbiron el
44
Esto es genial ¿Qué sucede cuando tienes dos variables en tu cuadrícula de facetas? ¿Me gusta hospital ~ gendero algo? ¿Hay alguna forma de usar etiquetadoras en ambos ejes? No puedo ver nada obvio en los documentos.
naught101
3
Tenga en cuenta que si comenzó con la respuesta de nada, esta solo funciona con una c () no una lista () .
thomas88wp
1
¡Una gran parte de esto es que esto funciona con ambos ejes de la cuadrícula de facetas!
Calum You
30

Así es como lo hice facet_grid(yfacet~xfacet)usando ggplot2, versión 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")
    )
)

Tenga en cuenta que esto no contiene un llamado a as_labeller(), algo con lo que luché por un tiempo.

Este enfoque está inspirado en el último ejemplo en la página de ayuda Coerce para etiquetar la función .

bovender
fuente
¡¡¡esto funciona!!! No pude aplicar las otras soluciones porque algunas de las soluciones sugeridas quedaron obsoletas en las versiones actuales de ggplot2.
yanes
Puede construir estos vectores con nombre con setNames() stackoverflow.com/a/22428439/3362993
jsta el
23

Si tiene dos facetas hospitaly roomdesea cambiar el nombre de una sola, puede usar:

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

Para renombrar dos facetas utilizando el enfoque basado en vectores (como en la respuesta de naught101), puede hacer:

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

La forma MÁS FÁCIL de cambiar SIN modificar los datos subyacentes es:

1) Cree un objeto utilizando la as_labellerfunción agregando la marca de verificación posterior para cada uno de los valores predeterminados :

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) Agregamos al GGplot:

ggplot(dataframe, aes(x=Temperature.C,y=fit))+geom_line()+ facet_wrap(~Humidity.RH., nrow=2,labeller=hum.names)
Leinfloyd
fuente
1
Este creo que es el método más elegante: es efectivo y funciona con ggplot2 versión 3.0.0.9000
Landak
9

Tenga en cuenta que esta solución no funcionará bien en caso de que ggplot muestre menos factores de los que su variable realmente contiene (lo que podría suceder si hubiera estado, por ejemplo, subconjunto):

 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 solución simple (además de agregar todos los factores no utilizados en names_li, que puede ser tedioso) es eliminar los factores no utilizados con droplevels (), ya sea en el conjunto de datos original o en la función labbeler, consulte:

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
fuente
9

Esta solución está muy cerca de lo que tiene @domi, pero está diseñada para acortar el nombre al buscar las primeras 4 letras y el último número.

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

ingrese la descripción de la imagen aquí

Roman Luštrik
fuente
6

Ambos facet_wrapy facet_gridtambién aceptan la entrada de ifelsecomo argumento. Entonces, si la variable utilizada para el facetado es lógica, la solución es muy simple:

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

Si la variable tiene más categorías, la ifelsedeclaración debe estar anidada .

Como efecto secundario, esto también permite que la creación de los grupos sea facetada dentro de la ggplotllamada.

lillemets
fuente
5

Agregar otra solución similar a @ domi con análisis de símbolos matemáticos, superíndice, subíndice, paréntesis / paréntesis, .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}, "]"))))

Creado el 30/03/2019 por el paquete reprex (v0.2.1.9000)

Tung
fuente
3

Creo que todas las demás soluciones son realmente útiles para hacer esto, pero hay otra forma.

Asumo:

  • ha instalado el dplyrpaquete, que tiene el convenientemutate comando , y
  • su conjunto de datos se llama survey .

    encuesta%>% mutate (Hosp1 = Hospital1, Hosp2 = Hospital2, ........)

Este comando le ayuda a cambiar el nombre de las columnas, pero todas las demás columnas se mantienen.

Entonces haz lo mismo facet_wrap, estás bien ahora.

son520804
fuente
lo siento, no funciona ya que también cambia el contenido de la columna
Jens
3

La definición de la función etiquetadora con variable, valueargumentos no funcionaría para mí. Además, si desea usar la expresión, debe usar lapply y no puede simplemente usar arr[val], ya que el argumento de la función es un data.frame.

Este código funcionó:

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
fuente
3

Puesto que aún no se me permite comentar las publicaciones, les dejo esto por separado en una adición a la respuesta de Vince y la respuesta de son520804 . El crédito va para ellos.

Son520804:

utilizando datos de Iris:

Supongo:
ha instalado el paquete dplyr, que tiene el conveniente comando mutate, y su conjunto de datos se denomina encuesta. survey %>% mutate(Hosp1 = Hospital1, Hosp2 = Hospital2,........) Este comando le ayuda a cambiar el nombre de las columnas, pero todas las demás columnas se mantienen. Luego haz lo mismo facet_wrap, estás bien ahora.

Utilizando el ejemplo de iris de Vince y el código parcial de son520804, hice esto con la función de mutación y logré una solución fácil sin tocar el conjunto de datos original. El truco es crear un vector de nombre suplente y usar mutate () dentro de la tubería para corregir los nombres de faceta temporalmente:

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

En este ejemplo, puede ver que los niveles de i $ Species se cambian temporalmente a los nombres comunes correspondientes contenidos en el vector new_names. La línea que contiene

mutate(Species=new_names) %>%

se puede quitar fácilmente para revelar el nombre original.

Palabra de precaución: esto puede introducir fácilmente errores en los nombres si el vector new_name no está configurado correctamente. Probablemente sería mucho más limpio usar una función separada para reemplazar las cadenas variables. Tenga en cuenta que el vector new_name puede necesitar repetirse de diferentes maneras para que coincida con el orden de su conjunto de datos original. Verifique doble y triplemente que esto se haya logrado correctamente.

Alexander Kielland
fuente
Puede ser un poco más agradable de usar: new_names <- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris')y luego en la mutación podría crear una nueva columna de esta manera:mutate(Spec = new_names[Species])
filups21
3

Esto es trabajo para mí.

Definir un factor:

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

y uso, en ggplot():

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

Simplemente extendiendo la respuesta de nada101: el crédito va para él

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

Lo que debe hacer es crear una lista con mapeo de nombre a nombre

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

y redefinir plot_labeller()con nuevos argumentos predeterminados:

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

Y entonces:

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

Alternativamente, puede crear una función dedicada para cada uno de los cambios de etiqueta que desee tener.

usuario4786271
fuente
2

Tengo otra forma de lograr el mismo objetivo sin cambiar los datos subyacentes:

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

Lo que hice anteriormente fue cambiar las etiquetas del factor en el marco de datos original, y esa es la única diferencia en comparación con su código original.

ytu
fuente
1

¿Has intentado cambiar los niveles específicos de tu Hospitalvector?

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
fuente
1

Siento que debería agregar mi respuesta a esto porque me tomó bastante tiempo hacer que esto funcione:

Esta respuesta es para ti si:

  • usted no desea modificar sus datos originales
  • si necesita expresiones ( bquote) en sus etiquetas y
  • si desea la flexibilidad de un vector de nombre de etiquetado separado

Básicamente coloco las etiquetas en un vector con nombre para que las etiquetas no se confundan o cambien. La labellerexpresión probablemente podría ser más simple, pero esto al menos funciona (las mejoras son muy bienvenidas). Tenga en cuenta el `(comillas inversas) para proteger el factor de faceta.

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

ingrese la descripción de la imagen aquí

dani
fuente
1

Solución simple (desde aquí ):

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)
Mella
fuente
0

Después de luchar durante un tiempo, lo que he encontrado es que podemos usar fct_relevel()y fct_recode()desde forcatsconjuntamente para cambiar el orden de las facetas, así fijar las etiquetas de faceta. No estoy seguro de si es compatible con el diseño, ¡pero funciona! Echa un vistazo a las parcelas a continuación:

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

Creado el 16/02/2020 por el paquete reprex (v0.3.0)

Ashirwad
fuente