J.Sabree
J.Sabree

Reputation: 2536

What does annotate() shift over my geom_text() in ggplot2 when using rich text?

I have 2 plots that I'm joining together. The top shows the raw data and the second is a subjective rating. The issue is that when I try to have a label using annotate() with rich text explaining what the ratings are, everything gets shifted. However, when I use annotate() with regular text, I don't get this issue. However, in my real use case, I need the richtext because I need the label to have multiple colors. Having multiple annotates() each with their own color is unruly because the text easily gets shifted.

Why is this happening and is there a way to fix it? I want the plot to look like the second image but with FAST and SLOW in color.

library(ggplot2)
library(ggtext)
library(dplyr)
library(patchwork)

#sample data; basic tidying to resemble my real data, no help needed here
car_data <- mtcars %>%
  mutate(gear_fct = factor(gear), ordered = is.ordered(gear)) %>%
  group_by(gear_fct) %>%
  dplyr::summarize(avg_hp = mean(hp)) %>%
  mutate(power = if_else(avg_hp >= 100, "Fast", "Slow"))


#make base plot, no help needed here
plot <- car_data %>%
  ggplot(aes(x = gear_fct, y = avg_hp)) +
  geom_col()

  

#Make labels to go below the plot
table_plot <- ggplot(car_data, aes(x = gear_fct, y = 1)) +
  geom_text(aes(label = power), size = 2.5, fontface = "bold", nudge_x = 0) +
  annotate("richtext", label = "Rating<br>(<span style='color:#87B8C5;'>FAST</span> or <span style='color:#BD8A8B;'>SLOW</span>):",
           x = 0, y = 1,  size = 2, fontface = "bold", hjust = -.5,
           fill = NA, label.color = NA) +
  theme_void() +
  theme(axis.text.x = element_blank(), 
        axis.ticks.x = element_blank(),
        plot.margin = margin(0, 0, 0, 0))

#join plots together
combined_plot <- plot / table_plot + plot_layout(heights = c(3, 0.5))
combined_plot

That code produces this plot; note the shifting and that the ratings aren't underneath the axis.

enter image description here

But, if I switch out the annotate in the above code with:

   annotate("text", label = "Rating\n(FAST or SLOW):", 
            x = .65, y = 1, size = 1, fontface = "bold") +

Then I get a plot that looks exactly how I want it, but the FAST and SLOW aren't in color, which I need:

enter image description here

Upvotes: 0

Views: 52

Answers (1)

Jon Spring
Jon Spring

Reputation: 66880

add

coord_cartesian(xlim = c(1, 3), clip = "off") +

I think the issue is that ggplot is treating the "text" annotation as separate from the data, so it does not influence the range of the table_plot x axis, but it does treat the "richtext" annotation as data that should be sized around. Arguably a bug, but I don't know enough about how ggplot2 should treat extension-package geom's as annotations.

To get around it, you could manually specify the range of data. In this case you have three factor levels, so xlim = c(1,3) will set the limits accordingly, and clip = "off" will prevent clipping of data beyond the axis range.

To get the "Rating" part centered, use x = 0.5, y = 1, size = 2, fontface = "bold", hjust = 0.5,.

enter image description here

Upvotes: 1

Related Questions