Annoter du texte sur une facette individuelle dans ggplot2

150

Je veux annoter du texte sur la dernière facette de l'intrigue avec le code suivant:

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)

entrez la description de l'image ici

Mais ce code annote le texte sur chaque facette. J'apprécierais beaucoup si vous me guidez sur la façon d'obtenir le texte annoté sur une seule facette.

MYaseen208
la source
1
Je pense que cela n'est pas encore implémenté , donc je soupçonne que vous devrez recourir à la méthode éprouvée de construction d'un bloc de données avec le texte et une colonne pour la variable de facettage.
joran

Réponses:

144

En règle générale, vous feriez quelque chose comme ceci:

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

Cela devrait fonctionner sans spécifier complètement la variable de facteur, mais générera probablement des avertissements:

entrez la description de l'image ici

joran
la source
2
Il semble que je rencontre des étiquettes floues lorsque j'essaye d'utiliser geom_text () sur mon tracé à facettes. C'est le même problème discuté ici ( groups.google.com/forum/?fromgroups=#!topic/ggplot2/evsbeBT48M4 ), et a été résolu en utilisant annotate ("text", ...). Est-ce que quelqu'un d'autre a des étiquettes floues avec geom_text ()?
Margaret
6
@Margaret Habituellement, c'est parce que vous avez dit par erreur à ggplot de tracer une copie de chaque étiquette pour chaque ligne de votre bloc de données d'origine (celle avec les points, les lignes, etc.). Notez que je passe un bloc de données distinct à geom_textavec une seule ligne.
joran
3
Ok j'ai compris-Merci. Et si vous vouliez mettre 3 étiquettes différentes sur votre intrigue à facettes? J'ai essayé un dataframe avec autant de lignes que j'avais des facettes et des étiquettes uniques dans chaque ligne. Je devrais peut-être commencer par une question distincte.
Margaret
8
Merci pour votre solution. Je me demande si je peux aussi faire cela en utilisant annotate()...?
polariser
2
@ user3420448 De même, il vous suffit de spécifier des valeurs pour chaque variable de facettage.
joran
108

Voici le tracé sans annotations de texte:

library(ggplot2)

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

tracé sans annotations de texte

Créons un bloc de données supplémentaire pour contenir les annotations de texte:

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
)

tracé avec annotations de texte sur les bords

Alternativement, nous pouvons spécifier manuellement la position de chaque étiquette:

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

tracé avec des étiquettes de texte positionnées manuellement

Nous pouvons également étiqueter les parcelles selon deux facettes:

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
  )

facette par deux variables

Remarques:

  • Vous pouvez utiliser -Infet Infpour positionner le texte sur les bords d'un panneau.
  • Vous pouvez utiliser hjustet vjustpour ajuster la justification du texte.
  • Le bloc de données d'étiquette de texte dat_textdoit avoir une colonne qui fonctionne avec votre facet_grid()ou facet_wrap().
Kamil Slowikowski
la source
7
Cette réponse est supérieure à la réponse acceptée (évidemment une différence de 5 ans entre les deux) pour la clarté de chaque étape. Aussi plus de clarté et d'explications.
Brandon
1
Si vous souhaitez ajouter du texte à plusieurs lignes, assurez-vous que votre colnames()texte data.framecorrespond à ceux des données que vous êtes sur le point de tracer.
Kots
Lorsque j'essaie de faire cela pour une seule de mes facettes, l'annotation apparaît mais les points réels ont disparu (ou sont masqués?).
Ben G
Ben G, vous pourriez envisager de créer un nouveau message pour partager votre code et votre chiffre.
Kamil Slowikowski
37

Si quelqu'un cherche un moyen facile d'étiqueter des facettes pour des rapports ou des publications, le package egg( CRAN ) a des fonctions tag_facet()et des tag_facet_outside()fonctionnalités très intéressantes .

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)

Tag à l'intérieur

Défaut

tag_facet(p)

Remarque: si vous souhaitez conserver le texte et l'arrière-plan de la bande, essayez d'ajouter strip.textet destrip.background revenir themeou de supprimer theme(strip.text = element_blank(), strip.background = element_blank())de la tag_facet()fonction d' origine .

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

Alignez en haut à droite et utilisez des chiffres romains

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

Aligner en bas à gauche et utiliser des majuscules

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

Définissez vos propres balises

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)

Tag à l'extérieur

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)

Edit : ajout d'une autre alternative à l'aide du package 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)

Créé par le package reprex (v0.2.1)

Tung
la source
2
Source dit « Ajoute un calque de texte factice à une ggplot aux facettes de l' étiquette et des ensembles Facet bandes à blanc. » Ergo, si vous avez l' étiquette de facette personnalisée vous bandes ne voulez pas perdre, modifier le script pour tag_facetpar nixingstrip.text = element_blank()
CrunchyTopping
@CrunchyTopping C'était en fait le chapeau que je cherchais, mais cela ne semble pas fonctionner pour moi:Warning: Ignoring unknown parameters: strip.text
efrem
1
Pour répondre à mes problèmes ci-dessus ... cet article explique joliment comment conserver les bandes: stackoverflow.com/a/56064130/3609450
efrem
22

Je pense que pour la réponse ci-dessus lab = "Text" est inutile, le code ci-dessous est également correct.

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

Cependant, si vous souhaitez étiqueter différemment dans différents sous-graphiques, ce sera bien de cette manière:

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
la source
7
Vous devez expliquer en détail ce que votre solution offre par rapport à la réponse déjà donnée et acceptée.
Sascha Wolf
3
Merci, cela a été utile pour étiqueter différents sous-graphiques.
Deathkill14
Pour une raison quelconque, lorsque je fais cela, cela ajoute des facettes (vides) pour les facteurs cyl = 2 et cyl = 3.
emudrak
6

Développant légèrement l'excellente réponse de joran, pour clarifier le fonctionnement du dataframe d'étiquette.

Vous pouvez considérer "mpg" et "wt" comme les coordonnées x et y, respectivement (je trouve qu'il est plus facile de garder une trace des noms de variables d'origine que de les renommer, comme dans l'excellente réponse de Kamil). Vous avez besoin d'une ligne par étiquette, et la colonne «cyl» indique à quelle facette chaque ligne est associée.

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)

tracé avec étiquettes

John
la source
2

Je ne connaissais pas le eggpackage, voici donc une ggplot2solution de package 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
la source