ggplot: size of annotate() vs size of element_text()

Viewed 940

I have some trouble harmonizing the sizes of different elements of my plot. Specifically I want the size of an annotation to be the same as the size of the title of the y-axis.

The following code results in different sizes however:

library(ggplot2)
test_data <- data.frame(x = c(1), y = c(1))
ggplot(test_data) +
  geom_point(aes(x = x, y = y)) +
  theme_bw(base_size = 14) +
  annotate("text", label = "A", x = 0.975, y = 1.025, size = unit(14, "pt")) +
  ylab("Why not the same size?") +
  theme(axis.title.y = element_text(size = unit(14, "pt")))

See here

What gives?

1 Answers

annotate effectively just creates a new geom_text layer. If you look inside the source code of GeomText$draw_panel you will see that the text drawn in a geom_text layer is ultimately drawn by grid::textGrob, and its font size is determined by the expression:

fontsize = data$size * .pt

where we can see the size parameter is automatically upscaled by the (hidden) global variable .pt. You can see the value of .pt if you type in your console:

.pt
#> [1] 2.845276

For some reason this scaling is not applied to the size parameter in element_text, even though element_text ultimately also uses grid::textGrob (via ggplot2:::title_spec). There's probably a good reason for this that I'm just not aware of.

Anyway, the bottom line is that if you want the size of a geom_text (or, by extension, an annotation("text") ) to match the size of an element_text, you, either divide the annotation's size by .pt or multiply the element_text size by .pt:

library(ggplot2)

test_data <- data.frame(x = c(1), y = c(1))
ggplot(test_data) +
  geom_point(aes(x = x, y = y)) +
  theme_bw(base_size = 14) +
  annotate("text", label = "Now the same size", x = 0.975, y = 1, 
           angle = 90, size = 14/.pt) +
  ylab("Now the same size") +
  theme(axis.title.y = element_text(size = 14))

Created on 2020-11-30 by the reprex package (v0.3.0)

Related