Combine multiple plots into publication-ready multi-panel figures using patchwork, cowplot, or matplotlib GridSpec with shared legends and panel labels. Use when combining multiple plots into publication figures.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add FridrichMethod/awesome-skills --skill bio-data-visualization-multipanel-figures --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Bio Data Visualization Multipanel Figures?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/fridrichmethod-bio-data-visualization-multipanel-figures)More formats (shields.io, HTML) on the badges page.
---
name: bio-data-visualization-multipanel-figures
description: Combine multiple plots into publication-ready multi-panel figures using patchwork, cowplot, or matplotlib GridSpec with shared legends and panel labels. Use when combining multiple plots into publication figures.
tool_type: mixed
primary_tool: patchwork
measurable_outcome: Execute skill workflow successfully with valid output within 15 minutes.
allowed-tools:
- read_file
- run_shell_command
---
<!--
# COPYRIGHT NOTICE
# This file is part of the "Universal Biomedical Skills" project.
# Copyright (c) 2026 MD BABU MIA, PhD <md.babu.mia@mssm.edu>
# All Rights Reserved.
#
# This code is proprietary and confidential.
# Unauthorized copying of this file, via any medium is strictly prohibited.
#
# Provenance: Authenticated by MD BABU MIA
-->
# Multi-Panel Figure Assembly
## patchwork Basics
```r
library(patchwork)
p1 <- ggplot(df, aes(x, y)) + geom_point()
p2 <- ggplot(df, aes(group, value)) + geom_boxplot()
p3 <- ggplot(df, aes(x)) + geom_histogram()
# Horizontal
p1 + p2 + p3
# Vertical
p1 / p2 / p3
# Mixed layouts
(p1 | p2) / p3
(p1 + p2) / (p3 + p4)
```
## Panel Labels
```r
# Automatic labels
(p1 + p2 + p3) + plot_annotation(tag_levels = 'A')
# Custom labels
(p1 + p2 + p3) + plot_annotation(tag_levels = list(c('A', 'B', 'C')))
# Label styling
(p1 + p2) + plot_annotation(
tag_levels = 'A',
tag_prefix = '(',
tag_suffix = ')',
theme = theme(plot.tag = element_text(face = 'bold', size = 14))
)
```
## Layout Control
```r
# Width ratios
p1 + p2 + plot_layout(widths = c(2, 1))
# Height ratios
p1 / p2 + plot_layout(heights = c(1, 2))
# Complex grid
layout <- "
AAB
AAB
CCC
"
p1 + p2 + p3 + plot_layout(design = layout)
# Fixed dimensions
p1 + p2 + plot_layout(widths = unit(c(5, 3), 'cm'))
```
## Shared Legends
```r
# Collect legends
(p1 + p2 + p3) + plot_layout(guides = 'collect')
# Position at bottom
(p1 + p2) + plot_layout(guides = 'collect') &
theme(legend.position = 'bottom')
# Keep individual legends
(p1 + p2) + plot_layout(guides = 'keep')
```
## Inset Plots
```r
# Add inset
p1 + inset_element(p2, left = 0.6, bottom = 0.6, right = 1, top = 1)
# Multiple insets
p1 +
inset_element(p2, 0.6, 0.6, 1, 1) +
inset_element(p3, 0.02, 0.6, 0.4, 1)
```
## cowplot Alternative
```r
library(cowplot)
# Simple grid
plot_grid(p1, p2, p3, ncol = 3, labels = 'AUTO')
# With labels
plot_grid(p1, p2, labels = c('A', 'B'), label_size = 14)
# Relative widths
plot_grid(p1, p2, rel_widths = c(2, 1))
# Nested grids
top_row <- plot_grid(p1, p2, ncol = 2)
bottom_row <- p3
plot_grid(top_row, bottom_row, nrow = 2, labels = c('', 'C'))
```
## Shared Axes
```r
library(patchwork)
# Same axis limits
(p1 + p2) & xlim(0, 10) & ylim(0, 100)
# Same theme
(p1 + p2 + p3) & theme_minimal()
# Same color scale
(p1 + p2) & scale_color_viridis_d()
```
## Empty Spaces
```r
# Add blank panel
p1 + plot_spacer() + p2
# With layout
layout <- "
AB#
CCC
"
p1 + p2 + p3 + plot_layout(design = layout)
```
## Titles and Captions
```r
(p1 + p2 + p3) +
plot_annotation(
title = 'Main Title',
subtitle = 'Subtitle text',
caption = 'Data source: ...',
theme = theme(
plot.title = element_text(face = 'bold', size = 16),
plot.subtitle = element_text(size = 12, color = 'grey40')
)
)
```
## Saving Multi-Panel Figures
```r
# Combine and save
combined <- (p1 | p2) / (p3 | p4) +
plot_annotation(tag_levels = 'A') &
theme(plot.tag = element_text(face = 'bold'))
ggsave('figure.pdf', combined, width = 10, height = 8)
ggsave('figure.png', combined, width = 10, height = 8, dpi = 300)
# For specific journal dimensions
ggsave('figure.pdf', combined, width = 180, height = 150, units = 'mm')
```
## Complex Publication Figure
```r
# Create themed plots
theme_pub <- theme_bw(base_size = 10) +
theme(
panel.grid = element_blank(),
legend.position = 'none'
)
p_volcano <- create_volcano(res) + theme_pub + ggtitle('Volcano Plot')
p_pca <- create_pca(vsd) + theme_pub + ggtitle('PCA')
p_heatmap <- wrap_elements(pheatmap_grob)
p_boxplot <- create_boxplot(expr_df) + theme_pub + ggtitle('Expression')
# Assemble
figure <- (p_volcano | p_pca) / (p_heatmap | p_boxplot) +
plot_annotation(tag_levels = 'A') +
plot_layout(guides = 'collect') &
theme(
plot.tag = element_text(face = 'bold', size = 12),
legend.position = 'bottom'
)
ggsave('Figure1.pdf', figure, width = 180, height = 160, units = 'mm')
```
## matplotlib GridSpec (Python)
```python
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(12, 8))
gs = GridSpec(2, 3, figure=fig)
ax1 = fig.add_subplot(gs[0, 0]) # Top left
ax2 = fig.add_subplot(gs[0, 1:]) # Top right, spans 2 columns
ax3 = fig.add_subplot(gs[1, :]) # Bottom, spans all columns
# Add plots to each axis
ax1.plot(x, y)
ax2.scatter(x, y)
ax3.bar(x, y)
plt.tight_layout()
```
## matplotlib Panel Labels
```python
# Add panel labels
for ax, label in zip([ax1, ax2, ax3], ['A', 'B', 'C']):
ax.text(-0.1, 1.1, label, transform=ax.transAxes,
fontsize=14, fontweight='bold', va='top')
```
## matplotlib Subfigures
```python
# matplotlib 3.4+ subfigures for complex layouts
fig = plt.figure(figsize=(12, 8))
subfigs = fig.subfigures(1, 2, width_ratios=[2, 1])
axs_left = subfigs[0].subplots(2, 1)
ax_right = subfigs[1].subplots(1, 1)
```
## Publication Export
```python
# Python
fig.savefig('figure1.pdf', bbox_inches='tight')
fig.savefig('figure1.png', dpi=300, bbox_inches='tight')
```
## Related Skills
- data-visualization/ggplot2-fundamentals - Individual plots
- reporting/rmarkdown-reports - Figures in documents
- differential-expression/de-visualization - DE-specific plots
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!