1

I have a ggplot with two facets, each containing the same custom added reference line. I want to add a single annotation label for each line, and to specify the location for each label in terms of the position on the overall plot.

I have tried adding the labels using annotate but this adds a label to each individual facet.

How do I specify the location for a single label on the 'global', overall plotting area (analagous to how x and y behave for legend.position in the example below) when facets are involved?

library(ggplot2)

p <- mtcars %>% 
  ggplot(aes(x = mpg, y = disp, colour = am)) + 
  geom_point() + 
  geom_vline(aes(xintercept = 15), 
             linetype = "dotted",
             colour = "grey20") + 
  geom_vline(aes(xintercept = 25), 
             linetype = "dotted",
             colour = "grey20") + 
  facet_wrap(~vs, nrow = 2)

# desired behaviour is to position labels using x and y of overall plot area, as per positioning of legend 
p <- p + 
  # x and y refer to positions on overall plot here, not to values of variables within individual facets
  theme(legend.position = c(x = 0.9, y = 0.5))

# failed attempt adds labels to each facet
p <- p + 
  # x and y refer to individual facets/values of x and y variables here
  annotate("text", x = 15 , y = 0.5,
           label = "This label\nshould be on midpoint of y", 
           colour = "grey50") +
  annotate("text", x = 25 , y = 0.75,
           label = "This label\nshould be 3/4 up plot", 
           colour = "grey50")
 
# show plot
p

example_ggplot_output

Thanks!

monkeytennis
  • 848
  • 7
  • 18
  • related https://stackoverflow.com/questions/11889625/annotating-text-on-individual-facet-in-ggplot2 – tjebo Apr 22 '23 at 19:18

2 Answers2

2

You can use grid::grid.text() to position a specific label in your canvas. Use it multiple times to achieve what you want. Of course, also adjust the position of the label.

Please, have a look at the code below.

library(ggplot2)
library(magrittr)
library(grid)

p <- mtcars %>% 
  ggplot(aes(x = mpg, y = disp, colour = am)) + 
  geom_point() + 
  geom_vline(aes(xintercept = 15), 
             linetype = "dotted",
             colour = "grey20") + 
  geom_vline(aes(xintercept = 25), 
             linetype = "dotted",
             colour = "grey20") + 
  facet_wrap(~vs, nrow = 2)

p
grid.text("text1", x = 0.5, y = 0.5)
grid.text("text2", x = 0.5, y = 0.75)

Is this what you would like to have?

Created on 2021-03-03 by the reprex package (v1.0.0)

Francesco Grossetti
  • 1,555
  • 9
  • 17
1

Note, any annotation of that sort will be somewhat hacky and will require careful adjustment of the position of your labels. I think most convenient should be using either patchwork or cowplot for custom annotation. Cowplot offers specific functionality for plot labelling.

library(tidyverse)
library(cowplot)

p <- mtcars %>% 
  ggplot(aes(x = mpg, y = disp, colour = am)) + 
  geom_point() + 
  geom_vline(aes(xintercept = 15), 
             linetype = "dotted",
             colour = "grey20") + 
  geom_vline(aes(xintercept = 25), 
             linetype = "dotted",
             colour = "grey20") + 
  facet_wrap(~vs, nrow = 2) +
  theme(legend.position = c(x = 0.9, y = 0.5))

# desired behaviour is to position labels using x and y of overall plot area, as per positioning of legend 
ggdraw(p) + draw_plot_label(x = c(.2,.6), y = c(.6,.6), 
                       label =  c("This label\nshould be on midpoint of y",  "This label\nshould be 3/4 up plot"),
                       hjust = 0, size = 9)

Created on 2021-03-03 by the reprex package (v1.0.0)

tjebo
  • 21,977
  • 7
  • 58
  • 94
  • 1
    I hadn't thought about using cowplot or patchwork. I'm using patchwork already for the plots I'm working with so this is a great suggestion/solution, thank you. – monkeytennis Mar 03 '21 at 21:38