When using {patchwork} to combine separate ggplots into the same graphic, I sometimes want to add one or more sections that are no plots at all, but basically a textbox.
As far as I can tell, the only time this is adressed in the patchwork documentation is here making use of wrap_elements(grid::textGrob('Text on left side'))
. This won't do, however, since I want to use {ggtext} mostly to (i) have automated word-wrapping and (ii) mix regular, italics, bold and colored text (see e.g. here).
So far, I have found two different approaches that made this work and they are demonstrated in the reprex below. Both approaches have in common that they basically hide every part of the ggplot that is not the desired text.
- The 1st approach (inspiration from here: plot and relevant code) adds the text as
ggtext::geom_textbox()
. - The 2nd approach (inspiration from here: plot and relevant code) adds the text as a
subtitle
withtheme(plot.subtitle = ggtext::element_markdown())
.
Question
My question is, however, if there are even better/simpler ways to implement this. Mostly because as you can see in the reprex below, there is some playing around with margin()
and plot_layout()
necessary until the text lines up correctly.
I can think of two different vertical alignments I would want for this text:
- So that it starts at the same height as the title of the left plot.
p2
is close to this, but needs manual twisting. Furthermore, it currently adds unnecessary vertical space for title and subtitle of the left plot. - So that it starts at the same height as the plot area of the left plot.
p1
is close to this, but needs manual twisting
reprex
# setup -------------------------------------------------------------------
library(ggtext)
library(glue)
library(patchwork)
library(tidyverse)
cols <- c(ctrl = "red", trt1 = "blue", trt2 = "purple")
string <- glue("<i style='color:{cols}'>{names(cols)}</i>") %>%
paste(collapse = ", ") %>%
paste("There are three treatments", .,
"and here are some interesting facts about them.") %>%
rep(5) %>% paste(collapse = " ")
plot <- ggplot(PlantGrowth) +
aes(x = group, y = weight, color = group) +
geom_point() +
scale_color_manual(values = cols, guide = "none") +
labs(title = "Title",
subtitle = "Subtitle",
caption = "Caption")
# 1st approach: geom_textbox() --------------------------------------------
text1 <- ggplot(data = tibble(x = 0, y = 1, label = string)) +
aes(x = x, y = y, label = label) +
geom_textbox(
box.color = NA,
fill = NA,
width = unit(10, "cm"),
hjust = 0,
vjust = 1
) +
scale_x_continuous(limits = c(0, 1), expand = c(0, 0)) +
scale_y_continuous(limits = c(0, 1), expand = c(0, 0)) +
theme_void() +
theme(
plot.margin = margin(0, 0, 0, 0)
)
p1_left <- plot
p1_right <- text1 / plot + plot_layout(heights = c(1, 1))
p1 <- p1_left | p1_right
ggsave("p1.png", p1, width = 9, height = 6)
cowplot::ggdraw() + cowplot::draw_image(png::readPNG("p1.png"))
# 2nd approach: subtitle --------------------------------------------------
text2 <- ggplot(data = data.frame(x = 1:2, y = 1:10)) +
labs(subtitle = string) +
theme_void() +
theme(
plot.subtitle = ggtext::element_textbox_simple(
hjust = 0,
halign = 0,
margin = margin(20, 0, 0, 0)
),
plot.margin = margin(0, 0, 0, 0)
)
p2_left <- plot
p2_right <- text2 / plot + plot_layout(heights = c(1, 6))
p2 <- p2_left | p2_right
ggsave("p2.png", p2, width = 9, height = 6)
cowplot::ggdraw() + cowplot::draw_image(png::readPNG("p2.png"))
Created on 2022-08-24 with reprex v2.0.2
edit 1
Based on Quinten's answer, I updated
- the reprex. It was correctly pointed out that the ggplots created via {reprex} were sort of arbitrary in their dimensions. This is similar with the plot preview window in RStudio. However, I do not wish this to be the focus of this question, since ggplots will always be exported with some given dimensions. Therefore I added two lines that export the ggplot with given dimensions via
ggsave(...)
and then display the actual png viacowplot::draw_image(png::readPNG(".png"))
. - the question. It is now more precise in what I want.
edit 2
Related tweet: https://twitter.com/CedScherer/status/1579066626741178368