Anotar texto en una faceta individual en ggplot2

150

Quiero anotar algún texto en la última faceta de la trama con el siguiente código:

library(ggplot2)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p <- p + facet_grid(. ~ cyl)
p <- p + annotate("text", label = "Test", size = 4, x = 15, y = 5)
print(p)

ingrese la descripción de la imagen aquí

Pero este código anota el texto en cada faceta. Le agradecería mucho que me guíe cómo obtener el texto anotado en una sola faceta.

MYaseen208
fuente
1
Creo que esto aún no está implementado , por lo que sospecho que tendrá que recurrir al método probado y verdadero de construir un marco de datos con el texto y una columna para la variable de facetado.
joran

Respuestas:

144

Por lo general, harías algo como esto:

ann_text <- data.frame(mpg = 15,wt = 5,lab = "Text",
                       cyl = factor(8,levels = c("4","6","8")))
p + geom_text(data = ann_text,label = "Text")

Debería funcionar sin especificar completamente la variable del factor, pero probablemente arrojará algunas advertencias:

ingrese la descripción de la imagen aquí

joran
fuente
2
Parece que me encuentro con algunas etiquetas borrosas cuando intento usar geom_text () en mi gráfico facetado. Es el mismo problema discutido aquí ( groups.google.com/forum/?fromgroups=#!topic/ggplot2/evsbeBT48M4 ), y se resolvió mediante la anotación ("texto", ...). ¿Alguien más obtiene etiquetas borrosas con geom_text ()?
Margaret
66
@Margaret Por lo general, eso se debe a que por error le ha dicho a ggplot que trace una copia de cada etiqueta para cada fila en su marco de datos original (el que tiene los puntos, líneas, etc.). Tenga en cuenta que paso un marco de datos separado geom_textcon solo una fila.
joran
3
Ok, tengo eso, gracias. ¿Qué pasaría si quisieras poner 3 etiquetas diferentes en tu trama facetada? Probé un marco de datos con tantas filas como facetas y etiquetas únicas en cada fila. Tal vez debería comenzar esto como una pregunta separada.
Margaret
8
Gracias por tu solución. Me pregunto si también puedo hacer esto usando annotate()...?
polarice el
2
@ user3420448 Lo mismo, solo tiene que especificar valores para cada variable de facetado.
joran
106

Aquí está la trama sin anotaciones de texto:

library(ggplot2)

p <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  facet_grid(. ~ cyl) +
  theme(panel.spacing = unit(1, "lines"))
p

trama sin anotaciones de texto

Creemos un marco de datos adicional para contener las anotaciones de texto:

dat_text <- data.frame(
  label = c("4 cylinders", "6 cylinders", "8 cylinders"),
  cyl   = c(4, 6, 8)
)
p + geom_text(
  data    = dat_text,
  mapping = aes(x = -Inf, y = -Inf, label = label),
  hjust   = -0.1,
  vjust   = -1
)

trazar con anotaciones de texto en los bordes

Alternativamente, podemos especificar manualmente la posición de cada etiqueta:

dat_text <- data.frame(
  label = c("4 cylinders", "6 cylinders", "8 cylinders"),
  cyl   = c(4, 6, 8),
  x     = c(20, 27.5, 25),
  y     = c(4, 4, 4.5)
)

p + geom_text(
  data    = dat_text,
  mapping = aes(x = x, y = y, label = label)
)

trazar con etiquetas de texto posicionadas manualmente

También podemos etiquetar parcelas en dos facetas:

dat_text <- data.frame(
  cyl   = c(4, 6, 8, 4, 6, 8),
  am    = c(0, 0, 0, 1, 1, 1)
)
dat_text$label <- sprintf(
  "%s, %s cylinders",
  ifelse(dat_text$am == 0, "automatic", "manual"),
  dat_text$cyl
)
p +
  facet_grid(am ~ cyl) +
  geom_text(
    size    = 5,
    data    = dat_text,
    mapping = aes(x = Inf, y = Inf, label = label),
    hjust   = 1.05,
    vjust   = 1.5
  )

faceta por dos variables

Notas:

  • Puede usar -Infy Infpara colocar texto en los bordes de un panel.
  • Puede usar hjusty vjustpara ajustar la justificación del texto.
  • El marco de datos de la etiqueta de texto dat_textdebe tener una columna que funcione con su facet_grid()o facet_wrap().
Kamil Slowikowski
fuente
66
Esta respuesta es superior a la respuesta aceptada (obviamente, una diferencia de 5 años entre los dos) por la claridad con la que pasa por cada paso. También mayor claridad y explicaciones.
Brandon el
1
Si desea agregar texto a varias filas, asegúrese de que su colnames()texto data.framecoincida con los datos que está a punto de trazar.
Kots
Cuando trato de hacer esto para una de mis facetas, aparece la anotación pero los puntos reales se han ido (¿u ocultado?).
Ben G
Ben G, podrías considerar hacer una nueva publicación para compartir tu código y figura.
Kamil Slowikowski
36

Si alguien está buscando una manera fácil de etiquetar facetas para informes o publicaciones, el paquete egg( CRAN ) tiene funciones tag_facet()y tag_facet_outside()funciones bastante ingeniosas .

library(ggplot2)

p <- ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_grid(. ~ am) +
  theme_bw(base_size = 12)

# install.packages('egg', dependencies = TRUE)
library(egg)

Etiqueta dentro

Defecto

tag_facet(p)

Nota: si desea conservar el texto y el fondo de la tira, intente agregar strip.textystrip.background volver a themeingresar o eliminar theme(strip.text = element_blank(), strip.background = element_blank())de la tag_facet()función original .

tag_facet <- function(p, open = "(", close = ")", tag_pool = letters, x = -Inf, y = Inf, 
                      hjust = -0.5, vjust = 1.5, fontface = 2, family = "", ...) {

  gb <- ggplot_build(p)
  lay <- gb$layout$layout
  tags <- cbind(lay, label = paste0(open, tag_pool[lay$PANEL], close), x = x, y = y)
  p + geom_text(data = tags, aes_string(x = "x", y = "y", label = "label"), ..., hjust = hjust, 
                vjust = vjust, fontface = fontface, family = family, inherit.aes = FALSE) 
}

Alinear arriba a la derecha y usar números romanos

tag_facet(p, x = Inf, y = Inf, 
          hjust = 1.5,
          tag_pool = as.roman(1:nlevels(factor(mtcars$am))))

Alinee la esquina inferior izquierda y use letras mayúsculas

tag_facet(p, 
          x = -Inf, y = -Inf, 
          vjust = -1,
          open = "", close = ")",
          tag_pool = LETTERS)

Define tus propias etiquetas

my_tag <- c("i) 4 cylinders", "ii) 6 cyls")
tag_facet(p, 
          x = -Inf, y = -Inf, 
          vjust = -1, hjust = -0.25,
          open = "", close = "",
          fontface = 4,
          size = 5,
          family = "serif",
          tag_pool = my_tag)

Etiqueta afuera

p2 <- ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_grid(cyl ~ am, switch = 'y') +
  theme_bw(base_size = 12) +
  theme(strip.placement = 'outside')

tag_facet_outside(p2)

Editar : agregar otra alternativa usando el paquete stickylabeller

- `.n` numbers the facets numerically: `"1"`, `"2"`, `"3"`...
- `.l` numbers the facets using lowercase letters: `"a"`, `"b"`, `"c"`...
- `.L` numbers the facets using uppercase letters: `"A"`, `"B"`, `"C"`...
- `.r` numbers the facets using lowercase Roman numerals: `"i"`, `"ii"`, `"iii"`...
- `.R` numbers the facets using uppercase Roman numerals: `"I"`, `"II"`, `"III"`...

# devtools::install_github("rensa/stickylabeller")
library(stickylabeller)

ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_wrap(. ~ am, 
             labeller = label_glue('({.l}) am = {am}')) +
  theme_bw(base_size = 12)

Creado por el paquete reprex (v0.2.1)

Tung
fuente
2
Fuente dice "añade una capa de texto de relleno a un ggplot a facetas de la etiqueta y conjuntos faceta tiras en blanco." Ergo, si usted tiene la etiqueta personalizada faceta tiras no quiere perder, editar el guión de tag_facetpor nixingstrip.text = element_blank()
CrunchyTopping
@CrunchyTopping Esto era realmente el sombrero que estaba buscando, pero no parece funcionar para mí:Warning: Ignoring unknown parameters: strip.text
efrem
1
Para responder a mis problemas anteriores ... esta publicación explica muy bien cómo mantener las tiras: stackoverflow.com/a/56064130/3609450
efrem
22

Creo que la respuesta anterior lab = "Text" es inútil, el siguiente código también está bien.

ann_text <- data.frame(mpg = 15,wt = 5,
                       cyl = factor(8,levels = c("4","6","8")))
p + geom_text(data = ann_text,label = "Text" )

Sin embargo, si desea etiquetar de manera diferente en diferentes sub-gráficos, estará bien de esta manera:

ann_text <- data.frame(mpg = c(14,15),wt = c(4,5),lab=c("text1","text2"),
                       cyl = factor(c(6,8),levels = c("4","6","8")))
p + geom_text(data = ann_text,aes(label =lab) )
kdyhl
fuente
77
Debe explicar en profundidad lo que ofrece su solución en comparación con la respuesta ya dada y aceptada.
Sascha Wolf
3
Gracias, esto fue útil para etiquetar diferentes sub-gráficos.
Deathkill14
Por alguna razón, cuando hago esto, agrega facetas (vacías) para los factores cyl = 2 y cyl = 3.
emudrak
6

Ampliando ligeramente la excelente respuesta de joran, para aclarar cómo funciona el marco de datos de la etiqueta.

Puede pensar en "mpg" y "wt" como las coordenadas x e y, respectivamente (me resulta más fácil hacer un seguimiento de los nombres de variables originales que renombrarlos, como en la excelente respuesta de Kamil). Necesita una fila por etiqueta y la columna "cyl" muestra con qué faceta está asociada cada fila.

ann_text<-data.frame(mpg=c(25,15),wt=c(3,5),cyl=c(6,8),label=c("Label 1","Label 2"))

ann_text
>  mpg wt cyl  label
>  25  3   6   Label 1
>  15  5   8   Label 2

p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p <- p + facet_grid(. ~ factor(cyl))
p + geom_text(data = ann_text,label=ann_text$label)

trama con etiquetas

Juan
fuente
2

No sabía sobre el eggpaquete, así que aquí hay una ggplot2solución de paquete simple

library(tidyverse)
library(magrittr)
Data1=data.frame(A=runif(20, min = 0, max = 100), B=runif(20, min = 0, max = 250), C=runif(20, min = 0, max = 300))
Data2=data.frame(A=runif(20, min = -10, max = 50), B=runif(20, min = -5, max = 150), C=runif(20, min = 5, max = 200))
bind_cols(
Data1 %>% gather("Vars","Data_1"),
Data2 %>% gather("Vars","Data_2")
) %>% select(-Vars1) -> Data_combined
Data_combined %>%
  group_by(Vars) %>%
  summarise(r=cor(Data_1,Data_2),
            r2=r^2,
            p=(pt(abs(r),nrow(.)-2)-pt(-abs(r),nrow(.)-2))) %>%
  mutate(rlabel=paste("r:",format(r,digits=3)),
         plabel=paste("p:",format(p,digits=3))) ->
  label_df 
label_df %<>% mutate(x=60,y=190)
Data_combined %>%
  ggplot(aes(x=Data_1,y=Data_2,color=Vars)) +
  geom_point() + 
  geom_smooth(method="lm",se=FALSE) +
  geom_text(data=label_df,aes(x=x,y=y,label=rlabel),inherit.aes = FALSE) + 
  geom_text(data=label_df,aes(x=x,y=y-10,label=plabel),inherit.aes = FALSE) + 
    facet_wrap(~ Vars)
Erich Neuwirth
fuente