Anotando texto na faceta individual no ggplot2

150

Quero anotar algum texto na última faceta do gráfico com o seguinte 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)

insira a descrição da imagem aqui

Mas esse código anota o texto em todas as facetas. Eu apreciaria muito se você me orientasse como obter o texto anotado em apenas uma faceta.

MYaseen208
fonte
1
Eu acredito que isso ainda não foi implementado , então eu suspeito que você precisará recorrer ao método testado e verdadeiro de construir um quadro de dados com o texto e uma coluna para a variável facetada.
joran

Respostas:

144

Normalmente, você faria algo assim:

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

Ele deve funcionar sem especificar a variável fator completamente, mas provavelmente lançará alguns avisos:

insira a descrição da imagem aqui

joran
fonte
2
Parece que encontro alguns rótulos borrados quando tento usar geom_text () no meu gráfico facetado. É o mesmo problema discutido aqui ( groups.google.com/forum/?fromgroups=#!topic/ggplot2/evsbeBT48M4 ) e foi resolvido usando a anotação ("texto", ...). Alguém mais tem rótulos embaçados com geom_text ()?
Margaret
6
@Margaret Geralmente, isso ocorre porque você disse ao ggplot por engano para plotar uma cópia de cada rótulo para cada linha em seu quadro de dados original (aquele com os pontos, linhas, etc.). Observe que eu passo um quadro de dados separado para geom_textapenas uma linha.
joran
3
Ok, entendi, obrigado. E se você quisesse colocar três rótulos diferentes em seu enredo facetado? Tentei um quadro de dados com tantas linhas quanto facetas e rótulos exclusivos em cada linha. Talvez eu devesse começar isso como uma pergunta separada.
Margaret
8
Obrigado pela sua solução. Gostaria de saber se também posso fazer isso usando annotate()...?
polarize
2
@ user3420448 Da mesma forma, você apenas precisa especificar valores para cada variável facetada.
joran
106

Aqui está o gráfico sem anotações de texto:

library(ggplot2)

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

plotagem sem anotações de texto

Vamos criar um quadro de dados adicional para armazenar as anotações 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
)

plotagem com anotações de texto nas bordas

Como alternativa, podemos especificar manualmente a posição de cada rótulo:

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

plotagem com etiquetas de texto posicionadas manualmente

Também podemos rotular plotagens em duas 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 duas variáveis

Notas:

  • Você pode usar -Infe Infposicionar o texto nas bordas de um painel.
  • Você pode usar hjuste vjustajustar a justificativa do texto.
  • O quadro de dados do rótulo de texto dat_textdeve ter uma coluna que funcione com o seu facet_grid()ou facet_wrap().
Kamil Slowikowski
fonte
6
Essa resposta é superior à resposta aceita (obviamente uma diferença de cinco anos entre os dois) pela clareza com que ela passa por cada etapa. Também maior clareza e explicações.
Brandon
1
Se você deseja adicionar texto a várias linhas, verifique se colnames()o texto data.framecorresponde aos dados que você está prestes a plotar.
Kots
Quando tento fazer isso para uma única das minhas facetas, a anotação aparece, mas os pontos reais se foram (ou estão obscurecidos?).
Ben G
Ben G, considere criar uma nova postagem para compartilhar seu código e sua figura.
Kamil Slowikowski
36

Se alguém estiver procurando uma maneira fácil de rotular facetas para relatórios ou publicações, o pacote egg( CRAN ) possui funções tag_facet()e tag_facet_outside()funções muito bacanas .

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)

Etiquetar dentro

Padrão

tag_facet(p)

Nota: se você deseja manter o texto e o plano de fundo da faixa, tente adicionar strip.textestrip.background voltar themeou remover theme(strip.text = element_blank(), strip.background = element_blank())da tag_facet()função 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) 
}

Alinhar o canto superior direito e usar algarismos romanos

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

Alinhar o canto inferior esquerdo e usar letras maiúsculas

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

Defina suas próprias tags

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)

Etiquetar fora

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 : adicionando outra alternativa usando o pacote 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)

Criado pelo pacote reprex (v0.2.1)

Tung
fonte
2
A fonte diz: "Adiciona uma camada de texto fictícia a um ggplot para rotular facetas e define tiras de faceta em branco". Portanto, se você tiver tiras de etiquetas de facetas personalizadas que não deseja perder, edite o script tag_facetnixingstrip.text = element_blank()
CrunchyTopping
@CrunchyTopping Este era realmente o chapéu que eu procurava, mas não parece funcionar para mim:Warning: Ignoring unknown parameters: strip.text
efrem 12/06
Para responder aos meus problemas acima ... este post explica muito bem como manter as tiras: stackoverflow.com/a/56064130/3609450
efrem
22

Acho que a resposta acima lab = "Text" é inútil, o código abaixo também está ok.

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

No entanto, se você quiser rotular de forma diferente em subgráficos diferentes, tudo ficará bem desta maneira:

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
fonte
7
Você deve explicar em profundidade o que sua solução oferece em comparação com a resposta já dada e aceita.
Sascha Lobo
3
Obrigado, isso foi útil para rotular diferentes subgráficos.
Deathkill14
Por alguma razão, quando faço isso, ele adiciona facetas (vazias) para os fatores cyl = 2 e cyl = 3.
emudrak
6

Expandindo um pouco a excelente resposta de joran, para esclarecer como o dataframe da etiqueta funciona.

Você pode pensar em "mpg" e "wt" como as coordenadas xey, respectivamente (acho mais fácil acompanhar os nomes das variáveis ​​originais do que renomeá-los, como na excelente resposta de Kamil). Você precisa de uma linha por rótulo e a coluna "cyl" mostra a qual faceta cada linha está associada.

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)

enredo com etiquetas

John
fonte
2

Eu não sabia sobre o eggpacote, então aqui está uma ggplot2solução simples para o pacote

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
fonte