Combining plots in a grid

Author

Charlotte Soneson, Michael Stadler

Summary

This document illustrates how to use cowplot and patchwork (two companion packages to ggplot2) to:

  • combine multiple panels into a single figure
  • include a non-ggplot2 panel and set a joint title for the figure

Prepare data

Run the following code to prepare the data used in this document:

suppressPackageStartupMessages({
    library(tibble)
    library(swissknife)
    library(ggplot2)
    library(cowplot)
    library(patchwork)
})

loadExampleData("mycars")
`mycars`: re-encoded version of `datasets::mtcars`
tibble(mycars)
# A tibble: 32 × 13
     mpg cyl    disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  21   6      160    110  3.9   2.62  16.5     0     1     4     4
 2  21   6      160    110  3.9   2.88  17.0     0     1     4     4
 3  22.8 4      108     93  3.85  2.32  18.6     1     1     4     1
 4  21.4 6      258    110  3.08  3.22  19.4     1     0     3     1
 5  18.7 8      360    175  3.15  3.44  17.0     0     0     3     2
 6  18.1 6      225    105  2.76  3.46  20.2     1     0     3     1
 7  14.3 8      360    245  3.21  3.57  15.8     0     0     3     4
 8  24.4 4      147.    62  3.69  3.19  20       1     0     4     2
 9  22.8 4      141.    95  3.92  3.15  22.9     1     0     4     2
10  19.2 6      168.   123  3.92  3.44  18.3     1     0     4     4
# ℹ 22 more rows
# ℹ 2 more variables: engine_shape <fct>, transmission <fct>

Create individual panels

We first create the individual plots that we will later use as panels in the combined plot.

Code
p1 <- ggplot(data = mycars, mapping = aes(x = mpg, y = hp)) +
    geom_point(size = 3, alpha = 0.5, aes(color = transmission)) +
    labs(x = "Fuel efficiency (miles/gallon)", y = "Gross horsepower") +
    theme_bw(13) +
    theme(panel.grid = element_blank(),
          legend.position = "bottom")
p1

Code
p2 <- ggplot(data = mycars, mapping = aes(x = mpg)) +
    geom_histogram(bins = 10, 
                   color = "darkgrey", fill = "lightgrey") +
    labs(x = "Fuel efficiency (miles/gallon)") +
    theme_bw(13) +
    theme(panel.grid = element_blank(),
          legend.position = "bottom")
p2

Code
p3 <- ggplot(data = mycars, mapping = aes(x = transmission, y = hp)) + 
    geom_boxplot(outlier.size = -1) + 
    geom_jitter(width = 0.2, height = 0, alpha = 0.5) + 
    labs(x = "Transmission", y = "Gross horsepower") + 
    theme_bw(13) + 
    theme(panel.grid = element_blank(),
          legend.position = "bottom")
p3

Combine panels into final figure (cowplot)

Next we combine these plots into a single figure. We also want to include a jpg image of a puppy. The first thing we need to do is to convert this image into a format that can be understood by cowplot:

## Generate image object from jpg file
img <- ggdraw() + 
    draw_image("https://publicdomainvectors.org/photos/johnny_automatic_puppy.png")

Next, we combine the three plots and the puppy image into a single figure, using a grid layout.

Code
comb <- plot_grid(
    p3, p1, img, p2, 
    ncol = 2, labels = c("A", "B", "", "C"), 
    align = "hv", axis = "tblr", rel_widths = c(0.5, 1)
)
comb

We can also set a joint title for the full plot (this has to be generated separately and added as an additional figure component).

Code
## Create a joint title
jointtitle <- ggdraw() + 
    draw_label("Combined plot title",
               fontface = "bold", x = 0, hjust = 0)

plot_grid(jointtitle, 
          comb, 
          ncol = 1, rel_heights = c(0.1, 1)
)

Combine panels into final figure (patchwork)

Here we create the same combined figure as above, but now using patchwork::wrap_plots rather than cowplot.

Code
wrap_plots(p3, p1, img, p2, ncol = 2) + 
    plot_layout(widths = c(0.5, 1)) + 
    plot_annotation(tag_levels = list(c("A", "B", "", "C")), 
                    title = "Combined plot title",
                    theme = theme(plot.title = element_text(face = "bold")))

Here’s another visualization, where the different rows distribute the plot widths in different ways.

Code
(p3 + p1 + plot_layout(widths = c(1, 1))) / (img + p2 + plot_layout(widths = c(0.5, 1))) + 
    plot_annotation(tag_levels = list(c("A", "B", "", "C")),
                    title = "Combined plot title",
                    theme = theme(plot.title = element_text(face = "bold")))

Remarks

  • If panels have a shared legend and we only wish to include it once, we can extract it using cowplot::get_legend() and include it as a separate panel (note that some issues were reported with this functionality starting with ggplot2 3.5.0).
  • To include ggpairs panels, see the tips here.

Session info

Code
sessioninfo::session_info()
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.4.0 (2024-04-24)
 os       macOS Sonoma 14.5
 system   aarch64, darwin20
 ui       X11
 language (EN)
 collate  en_US.UTF-8
 ctype    en_US.UTF-8
 tz       Europe/Zurich
 date     2024-06-12
 pandoc   3.2 @ /opt/homebrew/bin/ (via rmarkdown)

─ Packages ───────────────────────────────────────────────────────────────────
 package              * version date (UTC) lib source
 abind                  1.4-5   2016-07-21 [1] CRAN (R 4.4.0)
 Biobase                2.64.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 BiocGenerics           0.50.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 BiocParallel           1.38.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 cli                    3.6.2   2023-12-11 [1] CRAN (R 4.4.0)
 codetools              0.2-20  2024-03-31 [2] CRAN (R 4.4.0)
 colorspace             2.1-0   2023-01-23 [1] CRAN (R 4.4.0)
 cowplot              * 1.1.3   2024-01-22 [1] CRAN (R 4.4.0)
 crayon                 1.5.2   2022-09-29 [1] CRAN (R 4.4.0)
 curl                   5.2.1   2024-03-01 [1] CRAN (R 4.4.0)
 DelayedArray           0.30.1  2024-05-30 [1] Bioconductor 3.19 (R 4.4.0)
 digest                 0.6.35  2024-03-11 [1] CRAN (R 4.4.0)
 dplyr                  1.1.4   2023-11-17 [1] CRAN (R 4.4.0)
 evaluate               0.23    2023-11-01 [1] CRAN (R 4.4.0)
 fansi                  1.0.6   2023-12-08 [1] CRAN (R 4.4.0)
 farver                 2.1.2   2024-05-13 [1] CRAN (R 4.4.0)
 fastmap                1.2.0   2024-05-15 [1] CRAN (R 4.4.0)
 fs                     1.6.4   2024-04-25 [1] CRAN (R 4.4.0)
 generics               0.1.3   2022-07-05 [1] CRAN (R 4.4.0)
 GenomeInfoDb           1.40.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 GenomeInfoDbData       1.2.12  2024-05-02 [1] Bioconductor
 GenomicRanges          1.56.0  2024-05-01 [1] Bioconductor 3.19 (R 4.4.0)
 ggplot2              * 3.5.1   2024-04-23 [1] CRAN (R 4.4.0)
 glue                   1.7.0   2024-01-09 [1] CRAN (R 4.4.0)
 gtable                 0.3.5   2024-04-22 [1] CRAN (R 4.4.0)
 htmltools              0.5.8.1 2024-04-04 [1] CRAN (R 4.4.0)
 htmlwidgets            1.6.4   2023-12-06 [1] CRAN (R 4.4.0)
 httr                   1.4.7   2023-08-15 [1] CRAN (R 4.4.0)
 IRanges                2.38.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 jsonlite               1.8.8   2023-12-04 [1] CRAN (R 4.4.0)
 KernSmooth             2.23-22 2023-07-10 [2] CRAN (R 4.4.0)
 knitr                  1.47    2024-05-29 [1] CRAN (R 4.4.0)
 labeling               0.4.3   2023-08-29 [1] CRAN (R 4.4.0)
 lattice                0.22-6  2024-03-20 [2] CRAN (R 4.4.0)
 lifecycle              1.0.4   2023-11-07 [1] CRAN (R 4.4.0)
 magick                 2.8.3   2024-02-18 [1] CRAN (R 4.4.0)
 magrittr               2.0.3   2022-03-30 [1] CRAN (R 4.4.0)
 Matrix                 1.7-0   2024-03-22 [2] CRAN (R 4.4.0)
 MatrixGenerics         1.16.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 matrixStats            1.3.0   2024-04-11 [1] CRAN (R 4.4.0)
 munsell                0.5.1   2024-04-01 [1] CRAN (R 4.4.0)
 patchwork            * 1.2.0   2024-01-08 [1] CRAN (R 4.4.0)
 pillar                 1.9.0   2023-03-22 [1] CRAN (R 4.4.0)
 pkgconfig              2.0.3   2019-09-22 [1] CRAN (R 4.4.0)
 png                    0.1-8   2022-11-29 [1] CRAN (R 4.4.0)
 purrr                  1.0.2   2023-08-10 [1] CRAN (R 4.4.0)
 R6                     2.5.1   2021-08-19 [1] CRAN (R 4.4.0)
 Rcpp                   1.0.12  2024-01-09 [1] CRAN (R 4.4.0)
 rlang                  1.1.4   2024-06-04 [1] CRAN (R 4.4.0)
 rmarkdown              2.27    2024-05-17 [1] CRAN (R 4.4.0)
 rstudioapi             0.16.0  2024-03-24 [1] CRAN (R 4.4.0)
 S4Arrays               1.4.1   2024-05-30 [1] Bioconductor 3.19 (R 4.4.0)
 S4Vectors              0.42.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 scales                 1.3.0   2023-11-28 [1] CRAN (R 4.4.0)
 sessioninfo            1.2.2   2021-12-06 [1] CRAN (R 4.4.0)
 SparseArray            1.4.8   2024-05-30 [1] Bioconductor 3.19 (R 4.4.0)
 SummarizedExperiment   1.34.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 swissknife           * 0.41    2024-05-29 [1] Github (fmicompbio/swissknife@bbfe1f9)
 tibble               * 3.2.1   2023-03-20 [1] CRAN (R 4.4.0)
 tidyselect             1.2.1   2024-03-11 [1] CRAN (R 4.4.0)
 UCSC.utils             1.0.0   2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 usethis                2.2.3   2024-02-19 [1] CRAN (R 4.4.0)
 utf8                   1.2.4   2023-10-22 [1] CRAN (R 4.4.0)
 vctrs                  0.6.5   2023-12-01 [1] CRAN (R 4.4.0)
 withr                  3.0.0   2024-01-16 [1] CRAN (R 4.4.0)
 xfun                   0.44    2024-05-15 [1] CRAN (R 4.4.0)
 XVector                0.44.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)
 yaml                   2.3.8   2023-12-11 [1] CRAN (R 4.4.0)
 zlibbioc               1.50.0  2024-04-30 [1] Bioconductor 3.19 (R 4.4.0)

 [1] /Users/charlottesoneson/Library/R/arm64/4.4/library/__bioc319
 [2] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library

──────────────────────────────────────────────────────────────────────────────