--- title: "Patchwork Integration" author: "Gilles Colling" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Patchwork Integration} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 5 ) library(ggguides) library(ggplot2) # Theme with transparent backgrounds for pkgdown light/dark mode theme_set( theme_grey() + theme( plot.background = element_rect(fill = "transparent", color = NA), panel.background = element_rect(fill = "transparent", color = NA), legend.background = element_rect(fill = "transparent", color = NA), legend.key = element_rect(fill = "transparent", color = NA), legend.box.background = element_rect(fill = "transparent", color = NA) ) ) ``` ## Overview When combining multiple plots with patchwork, legends often need special handling: - **Duplicate legends** - Same aesthetic mapped in multiple plots creates redundancy - **Alignment issues** - Legends may not align properly across panels - **Spanning** - Legends should sometimes span multiple rows ggguides provides `collect_legends()` and `collect_axes()` to address these challenges. ## The Problem: Duplicate Legends ```{r problem, fig.height=4} library(patchwork) p1 <- ggplot(mtcars, aes(mpg, wt, color = factor(cyl))) + geom_point() + labs(title = "Plot 1", color = "Cylinders") p2 <- ggplot(mtcars, aes(mpg, hp, color = factor(cyl))) + geom_point() + labs(title = "Plot 2", color = "Cylinders") # Default patchwork: duplicate legends p1 | p2 ``` ## Basic Legend Collection Use `collect_legends()` to gather legends from all plots in a composition: ```{r collect-basic, fig.height=4} collect_legends(p1 | p2) ``` ### Position Options Control where the collected legend appears: ```{r collect-bottom, fig.height=5} collect_legends(p1 | p2, position = "bottom") ``` ```{r collect-left, fig.height=4} collect_legends(p1 | p2, position = "left") ``` ## Stacked Plots For vertically stacked plots, legends can be centered or span the full height. Using different plot heights makes the spanning behavior more visible. ### Default: Centered ```{r stacked-default, fig.height=7} # Create plots with different heights using plot_layout p3 <- ggplot(mtcars, aes(mpg, disp, color = factor(cyl))) + geom_point() + labs(title = "Plot 3", color = "Cylinders") # Stack with different heights: 1, 1/2, 1/4 stacked <- (p1 / p2 / p3) + plot_layout(heights = c(4, 2, 1)) collect_legends(stacked, position = "right") ``` ### Spanning Full Height Use `span = TRUE` to make the legend fill the full height: ```{r stacked-span, fig.height=7} gt <- collect_legends(stacked, position = "right", span = TRUE) grid::grid.draw(gt) ``` ### Attaching to Specific Rows Attach the legend to specific row(s) instead of spanning all: ```{r span-row1, fig.height=7} # Legend attached to row 1 only (the tallest plot) gt <- collect_legends(stacked, position = "right", span = 1) grid::grid.draw(gt) ``` ```{r span-row12, fig.height=7} # Legend attached to rows 1 and 2 gt <- collect_legends(stacked, position = "right", span = 1:2) grid::grid.draw(gt) ``` ## Collecting Duplicate Axes When stacking plots vertically, the x-axis may be duplicated. Use `collect_axes()` to remove redundant axes: ```{r collect-axes, fig.height=5} # Plots stacked vertically - x-axis is duplicated p_top <- ggplot(mtcars, aes(mpg, wt)) + geom_point() + labs(y = "Weight") p_bottom <- ggplot(mtcars, aes(mpg, disp)) + geom_point() + labs(y = "Displacement") # Without axis collection (both have x-axis) p_top / p_bottom ``` ```{r collect-axes-fixed, fig.height=5} # With axis collection (removes redundant x-axis from top) collect_axes(p_top / p_bottom) ``` ## Combining with Styling ggguides functions work together: ```{r combined, fig.height=5} p1_styled <- p1 + legend_style(size = 11, title_face = "bold") p2_styled <- p2 + legend_style(size = 11, title_face = "bold") collect_legends(p1_styled | p2_styled, position = "right") ``` ## Complex Layouts Handle more complex patchwork layouts: ```{r complex, fig.height=6} p4 <- ggplot(mtcars, aes(qsec, wt, color = factor(cyl))) + geom_point() + labs(title = "Plot 4", color = "Cylinders") # 2x2 grid layout <- (p1 | p2) / (p3 | p4) collect_legends(layout, position = "right") ``` ## cowplot / Grid Users ggguides provides cowplot-compatible functions that work without patchwork: ```{r cowplot-setup, include=FALSE} # Fresh plots for cowplot examples (not modified by patchwork) cp1 <- ggplot(mtcars, aes(mpg, wt, color = factor(cyl))) + geom_point() + labs(title = "Plot 1", color = "Cylinders") cp2 <- ggplot(mtcars, aes(mpg, hp, color = factor(cyl))) + geom_point() + labs(title = "Plot 2", color = "Cylinders") cp3 <- ggplot(mtcars, aes(mpg, disp, color = factor(cyl))) + geom_point() + labs(title = "Plot 3", color = "Cylinders") cp4 <- ggplot(mtcars, aes(qsec, wt, color = factor(cyl))) + geom_point() + labs(title = "Plot 4", color = "Cylinders") ``` ### `get_legend()` - Extract Legend ```{r get-legend} # Extract legend from a plot leg <- get_legend(cp1) # Use with cowplot::plot_grid() or grid::grid.draw() grid::grid.newpage() grid::grid.draw(leg) ``` ### `shared_legend()` - Combine Plots with Shared Legend ```{r shared-legend-side, fig.height=4} # Side-by-side with shared legend on right gt <- shared_legend(cp1, cp2, ncol = 2, position = "right") grid::grid.newpage() grid::grid.draw(gt) ``` ```{r shared-legend-stacked, fig.height=6} # Stacked with legend at bottom gt <- shared_legend(cp1, cp2, cp3, ncol = 1, position = "bottom") grid::grid.newpage() grid::grid.draw(gt) ``` ```{r shared-legend-grid, fig.height=5} # 2x2 grid gt <- shared_legend(cp1, cp2, cp3, cp4, ncol = 2, nrow = 2, position = "right") grid::grid.newpage() grid::grid.draw(gt) ``` All ggguides styling functions (`legend_style()`, `legend_wrap()`, etc.) work on individual plots regardless of layout package. ## Summary | Function | Purpose | Key Parameters | |----------|---------|----------------| | `collect_legends()` | Gather legends from patchwork | `position`, `span` | | `collect_axes()` | Remove duplicate axes | `guides` | | `get_legend()` | Extract legend as grob | - | | `shared_legend()` | Combine plots with shared legend | `ncol`, `nrow`, `position` | **Learn more:** - [Legend Positioning](positioning.html) for single-plot placement - [Styling & Customization](styling.html) for legend appearance