2

I am trying to annotate many plots iteratively. I want an annotation to appear in the exact same place on all graphs, but they all have different y-axis scales. How do I annotate a graph without using the y-values? There must be a data-independent way, but I think I am missing a key piece of vocabulary so my searching has been fruitless.

Normally, I would add, e.g., annotate("text", x = 5, y = 10) to the ggplot object, but this doesn't work because the range of y varies widely between groups.

Bearing in mind there are around 30 plots to keep track of, here is a toy example using mtcars and ggpubr.

library(ggpubr)
ggboxplot(mtcars, x = "gear", y = "wt") +
  annotate("text", x = 2, y = 5, label = "I should be in the same place in both plots")
ggboxplot(mtcars, x = "gear", y = "disp") + 
  annotate("text", x = 2, y = 5, label = "I should be in the same place in both plots")

wt

disp

HarD
  • 183
  • 9
  • 1
    You need `annotation_custom` to which you pass a `textGrob` defined in "npc" space. – Allan Cameron Jun 13 '22 at 16:15
  • You could place the text dynamically like `annotate("text", x = median(mtcars$gear), y = max(mtcars$disp), label = "I should be in the same place in both plots")` – Skaqqs Jun 13 '22 at 16:16

3 Answers3

3

You could use inset_element from patchwork to overlay a plot consisting of just the label on top of each other plot.

library(ggpubr)
library(patchwork)

label <- ggplot() + 
  annotate("text", x = 2, y = 5, label = "I should be in the same place in both plots") +
  coord_cartesian(clip = "off") +   # allows text to overflow if needed
  theme_void()
ggboxplot(mtcars, x = "gear", y = "wt") +
  inset_element(label, left = 0.4, bottom = 0.7, right = 0.8, top = 0.8)
ggboxplot(mtcars, x = "gear", y = "disp") + 
  inset_element(label, left = 0.4, bottom = 0.7, right = 0.8, top = 0.8)

enter image description here

enter image description here

We could go one step further and define:

label_layer <- inset_element(label, left = 0.4, bottom = 0.7, 
                             right = 0.8, top = 0.8) 

Then each plot could be:

ggboxplot(mtcars, x = "gear", y = "wt") + label_layer
Jon Spring
  • 55,165
  • 4
  • 35
  • 53
1

Devide the first y by 100:

library(ggpubr)
ggboxplot(mtcars, x = "gear", y = "wt") +
  annotate("text", x = 2, y = 5/100, label = "I should be in the same place in both plots")
ggboxplot(mtcars, x = "gear", y = "disp") + 
  annotate("text", x = 2, y = 5, label = "I should be in the same place in both plots")

enter image description here enter image description here

TarJae
  • 72,363
  • 6
  • 19
  • 66
0

You can pass a percentage of the maximum value of the axis. It doesn't get them always in the same spot but it gets pretty close.

library(ggpubr)
ggboxplot(mtcars, x = "gear", y = "wt") +
  annotate("text", y = max(mtcars$wt)*.9, x = 2, label = "I should be in the same place in both plots")
ggboxplot(mtcars, x = "gear", y = "disp") + 
  annotate("text", y = max(mtcars$disp)*.9, x = 2, label = "I should be in the same place in both plots")

enter image description here

enter image description here

Claudio Paladini
  • 1,000
  • 1
  • 10
  • 20