Search code examples
rggplot2cowplotpatchworkgrob

Adding and aligning plot to spare facet at end of facet_wrap()


This is similar to the question here, but I am interested in how to add and align a separate plot to a spare panel that may exists at the end of a facet_wrap() call.

Currently I am thinking it might not be possible currently, and I would need to make all the facet plots separately, but maybe there is a way.

I made a reproducible example using the palmerpenguins dataset. I tried putting the second plot in as a grob, which worked but did not align the plot axes with the other panels and not sure I know how I could make it happen.

# if librarian is not installed, install it
if (!requireNamespace("librarian", quietly = TRUE)){
  install.packages("librarian")
}

# load packages
librarian::shelf(tidyverse, palmerpenguins, ggbeeswarm, patchwork, ggplotify)

data("penguins")

# make first plot
p1 <- ggplot(penguins, aes(bill_length_mm, flipper_length_mm)) +
  geom_point() +
  facet_wrap(~species, ncol = 2)

# make second plot
p2 <- ggplot(penguins, aes(species, body_mass_g)) +
  geom_quasirandom()

p1

p2


# make plots into grobs and insert p2 into the empty slot of p1
p3 <- ggplotGrob(p1)
p3$grobs[[5]] <- ggplotGrob(p2)

# plot new plot
as.ggplot(p3)

Created on 2024-12-05 with reprex v2.1.1


Solution

  • Using patchwork inset_element seems to work, however I'm not sure how robust it is if you make changes. I tried exporting at different sizes/aspect ratios and it held together.

    I've plotted iris data as I didn't have the penguin data installed and don't really think it makes a difference to the functionality of the answer.

    library(ggplot2)
    library(dplyr)
    library(patchwork)
    
    # create facet plot with some extra space so there will be room for axis labels on fourth plot
    # move x axis label so its not hidden behind the 4th plot
    pp1 <- ggplot(iris, aes(Sepal.Width, Sepal.Length))+
      geom_point()+
      facet_wrap(~Species, ncol = 2)+ 
      theme(panel.spacing = unit(2.5, "lines"),
            axis.title.x = element_text(hjust = 0.25))
    
    #create 4th plot
    pp2 <- ggplot(iris, aes(Species, Sepal.Length))+
      geom_boxplot()
    
    #get spacing from pp1 and apply to pp2 (in particular space where the facet label is)
    pp2aligned <- set_dim(pp2,get_dim(pp1) )
    
    #add plots, intuitively I thought the align_to should be "plot" but "full" appears better
    pp1 +
      inset_element(pp2aligned, left = 0.5, bottom = 0.0, right = 1, top = 0.5, align_to = "full")
    

    Created on 2024-12-09 with reprex v2.1.1