Search code examples
rggplot2patchwork

Adding shared title spanning two plots under another plot with it's own title with R patchwork and ggplot2


I have three plots that I would like to format in the following way:

 Plot 1
 ------
 P2  P3

However, I would like plot 1 to have it's own title, and plots 2 and 3 to share a title that spans plots 2 and 3 and maintains formatting and alignment.

I have the following code:

library(patchwork)
library(tidyverse)

econ <- select(economics, -pop, -pce, -unemploy)

econ <- pivot_longer(econ,
                    cols = -date,
                    names_to = "variable",
                    values_to = "value")

gg1 <- 
  ggplot(data=econ, aes(x=date, y=value, color=variable)) +
  geom_line() +
  labs(title="This is a Title",
       subtitle="This is a subtitle",
       y=NULL,
       x=NULL) +
  theme(legend.position="bottom",
        plot.margin = margin(t=.5, b=.5, l=0.1, r=1.2, "cm"),
        plot.title = element_text(margin = margin(b = 5)),
        plot.subtitle = element_text(margin = margin(b = 10)),
        #panel.background = element_rect(fill = "grey90"),
        plot.background = element_rect(fill = "grey"))

gg1

gg2 <- 
  ggplot(data=econ, aes(x=date, y=value, color=variable))+
  geom_line() +
  labs(y=NULL,
       x=NULL) +
  theme(legend.position="bottom",
        plot.margin = margin(t=.5, b=.5, l=0.1, r=1.2, "cm"),
        plot.title = element_text(margin = margin(b = 5)),
        plot.subtitle = element_text(margin = margin(b = 10)),
        #panel.background = element_rect(fill = "grey90"),
        plot.background = element_rect(fill = "grey"))

gg2

plots1 <- (gg2 | gg2) + plot_annotation(
  title = "This is a Title",
  subtitle = "This is a subtitle")
plots1

plotswrong <- gg1 / plots1

plotsissue <- gg1 / wrap_elements(plots1)

ggsave(plot = plotswrong,
       file = "./plotswrong.pdf",
       width = 18,
       height = 38,
       dpi = 320,
       units = "cm")

ggsave(plot = plotsissue,
       file = "./plotsissue.pdf",
       width = 18,
       height = 38,
       dpi = 320,
       units = "cm")

When not using wrap_elements, the formatting is correct, but the title is missing. title is missing

But when using wrap elements, the title is there, but the formatting is ruined. formatting is ruined

How do I add a title to span plots 2 and 3 without ruining alignment of the axes, creating unnecessary blank space, and losing the background color?

Thanks in advance.


Solution

  • One option would be to add the title for the second row as another ggplot. Requires some additional or individual theme adjustments. The most tricky part IMHO is to get the "white" separating lines for which I use an empty ggplot or a plot_spacer and which requires some fiddling to set the relative height and width. Additionally note that I have put all plots in a list which allows to use wrap_plots and use the design argument for more control on the placement of the individual plots including the spacers.

    library(patchwork)
    library(ggplot2)
    
    theme_adjust <- theme(
      legend.position = "bottom",
      plot.margin = margin(t = .5, b = .5, l = 0.1, r = 1.2, "cm"),
      plot.title = element_text(margin = margin(b = 5)),
      plot.subtitle = element_text(margin = margin(b = 10)),
      plot.background = element_rect(fill = "grey", color = "grey")
    )
    
    gg1 <- gg2 <-
      ggplot(data = econ, aes(x = date, y = value, color = variable)) +
      geom_line() +
      labs(
        y = NULL,
        x = NULL
      ) + 
      theme_adjust
      
    gg1 <- gg1 +
      labs(
        title = "This is a Title",
        subtitle = "This is a subtitle"
      )
    
    gg2 <- gg2 +
      theme(
        plot.margin = margin(t = 0, b = .5, l = 0.1, r = 1.2, "cm")
      )
    
    title <- ggplot() +
      labs(
        title = "This is a Title",
        subtitle = "This is a subtitle"
      ) +
      theme_adjust +
      theme(
        plot.margin = margin(t = .5, b = 0, l = 0.1, r = 1.2, "cm")
      )
    
    list(
      gg1, title, gg2, gg2
    ) |>
      wrap_plots(
        heights = c(1, 0.01, 0, 1),
        widths = c(1, 0.005, 1),
        design = "AAA\n###\nBBB\nC#D"
      )
    

    enter image description here