bio-data-visualization-multipanel-figures
Compose multi-panel publication figures with patchwork, cowplot, gridExtra (R), or matplotlib GridSpec/subfigures (Python) including shared axes/legends/guides collection, panel labels in Nature/Cell convention, and journal-spec sizing. Covers patchwork ≥1.2.0 axes='collect' feature, Type-42 font embedding, and the cairo_pdf save path. Use when composing 2+ subpanels into a single figure for journal submission.
What this skill does
## Version Compatibility
Reference examples tested with: patchwork 1.2+ (axes='collect' requires this version, released 2024-01-05), cowplot 1.1+, ggplot2 3.5+, matplotlib 3.8+ (subfigures stable since 3.4).
Before using code patterns, verify installed versions match. If versions differ:
- R: `packageVersion('<pkg>')` then `?function_name`
- Python: `pip show <package>` then `help(module.function)`
If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.
# Multi-Panel Figures
**"Combine plots into a multi-panel figure"** -> Arrange individual plots into a single composed figure with consistent sizing, shared legends/axes, and panel labels (a, b, c) in the Nature/Cell convention. The decision space: which composition library (patchwork most modern in R; matplotlib subfigures in Python), how to share legends and axes, and how to size at journal specifications.
- R: `patchwork` (modern; supports axes/guides collection since 1.2), `cowplot` (older; align_plots), `gridExtra` (basic grid arrange)
- Python: `matplotlib.gridspec.GridSpec`, `fig.subfigures()` (matplotlib 3.4+)
## The Single Most Important Modern Insight -- Axes Collection Requires patchwork ≥ 1.2.0
patchwork 1.2.0 (released 2024-01-05) added `axes = 'collect'` and `axis_titles = 'collect'` to `plot_layout()`. These collect repeated axes / titles across subplots into a single shared axis label — the same way `guides = 'collect'` (available since patchwork 1.0) collects legends.
Without this, multi-panel figures with shared axes show redundant labels on every subplot (visually cluttered AND non-Nature compliant). Verify patchwork version is ≥ 1.2.0; older versions silently ignore the `axes` argument.
## patchwork -- Modern R Composition
**Goal:** Compose 4 ggplot objects into a 2×2 panel figure with shared legend, collected axes, and bold panel labels (a, b, c, d) in upper-left of each subplot.
**Approach:** Combine plots with `+`, `/`, `|` operators; apply `plot_layout(guides='collect', axes='collect')` for shared elements; add `plot_annotation(tag_levels='a')` for Nature-style panel labels.
```r
library(patchwork)
library(ggplot2)
p1 <- ggplot(df, aes(x, y)) + geom_point() + theme_classic()
p2 <- ggplot(df, aes(group, value)) + geom_boxplot() + theme_classic()
p3 <- ggplot(df, aes(x)) + geom_histogram() + theme_classic()
p4 <- ggplot(df, aes(x, y, color = group)) + geom_point() + theme_classic()
# 2x2 grid
fig <- (p1 + p2) / (p3 + p4) +
plot_annotation(tag_levels = 'a',
theme = theme(plot.tag = element_text(face = 'bold', size = 10))) +
plot_layout(guides = 'collect', # share legends
axes = 'collect', # share axes (patchwork >= 1.2.0)
axis_titles = 'collect')
ggsave('figure1.pdf', fig, width = 180, height = 140, units = 'mm', device = cairo_pdf)
```
## patchwork Operators
```r
p1 + p2 # side-by-side
p1 / p2 # vertical stack
(p1 | p2) / p3 # mixed: top row two, bottom one
p1 + p2 + p3 + plot_layout(ncol = 3)
p1 + p2 + plot_layout(widths = c(2, 1)) # 2:1 width ratio
# Complex grid via design string
design <- "
AAB
AAB
CCC
"
p1 + p2 + p3 + plot_layout(design = design)
# Inset
p1 + inset_element(p2, left = 0.6, bottom = 0.6, right = 1, top = 1)
```
## cowplot -- Alternative with Alignment Focus
```r
library(cowplot)
# plot_grid is the workhorse
combined <- plot_grid(p1, p2, p3, p4,
ncol = 2, labels = 'AUTO', # 'AUTO' = A, B, C, D
label_size = 12, label_fontface = 'bold',
align = 'hv', # align horizontally + vertically
rel_widths = c(1, 1), rel_heights = c(1, 1))
# Nested grids
top_row <- plot_grid(p1, p2, ncol = 2, labels = c('A', 'B'))
bottom <- plot_grid(p3, p4, ncol = 2, labels = c('C', 'D'))
combined <- plot_grid(top_row, bottom, nrow = 2, rel_heights = c(1, 1.2))
ggsave('figure.pdf', combined, width = 180, height = 140, units = 'mm', device = cairo_pdf)
```
cowplot is older but its alignment behavior is sometimes more reliable than patchwork on edge cases (axes-with-titles of different lengths).
## matplotlib GridSpec (Python)
```python
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
fig = plt.figure(figsize=(180/25.4, 120/25.4), constrained_layout=True)
gs = GridSpec(2, 3, figure=fig)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1:]) # top right, spans columns 1-2
ax3 = fig.add_subplot(gs[1, :]) # bottom row, spans all columns
ax1.scatter(x, y, s=4, rasterized=True)
ax2.plot(x, y)
ax3.bar(cats, vals)
# Panel labels at (-0.15, 1.05) of each axes
for ax, lbl in zip([ax1, ax2, ax3], 'abc'):
ax.text(-0.15, 1.05, lbl, transform=ax.transAxes,
fontsize=10, fontweight='bold', va='top')
fig.savefig('figure.pdf', dpi=300, bbox_inches='tight')
```
## matplotlib Subfigures
```python
fig = plt.figure(figsize=(180/25.4, 120/25.4), constrained_layout=True)
subfigs = fig.subfigures(1, 2, width_ratios=[2, 1])
# Left subfigure has 2 stacked panels
axs_left = subfigs[0].subplots(2, 1)
axs_left[0].plot(x, y)
axs_left[1].scatter(x, y, rasterized=True)
# Right subfigure has one panel
ax_right = subfigs[1].subplots(1, 1)
ax_right.imshow(matrix)
subfigs[1].colorbar(ax_right.images[0], ax=ax_right, shrink=0.5)
```
Subfigures are stronger than GridSpec for complex compositions because each subfigure has its own constrained_layout.
## Journal Sizing
| Journal | Single col | Double col | Max height |
|---------|------------|------------|------------|
| Nature | 89 mm | 183 mm | 247 mm |
| Cell | 85 mm | 174 mm | 235 mm |
| Science | 55 mm | 120 mm | 220 mm |
| PNAS | 87 mm | 178 mm | 225 mm |
| eLife | 86 mm | 175 mm | ~240 mm |
Always set explicit units in mm; default inches is the most common source of "figure too large" errors.
## Panel Labels — Nature/Cell Convention
- **Nature**: lowercase bold serif (a, b, c) in upper-left corner of each panel; 8 pt
- **Cell**: uppercase bold sans-serif (A, B, C); placed flush left at panel top
- **Science**: capital bold (A, B, C)
```r
# patchwork tag_levels for lowercase (Nature)
plot_annotation(tag_levels = 'a',
theme = theme(plot.tag = element_text(face = 'bold', size = 9)))
# 'A' for uppercase (Cell)
plot_annotation(tag_levels = 'A')
# 'i' for roman numerals (sometimes for sub-panels)
```
```r
# cowplot
plot_grid(..., labels = 'AUTO') # auto uppercase A, B, C
plot_grid(..., labels = 'auto') # auto lowercase a, b, c
```
## Per-Method Failure Modes
### patchwork axes='collect' silently ignored
**Trigger:** Using `plot_layout(axes='collect')` with patchwork < 1.2.0.
**Mechanism:** Older versions silently accept the argument but don't act on it.
**Symptom:** Redundant axes on each subplot; no warning or error.
**Fix:** `packageVersion('patchwork')` must be ≥ 1.2.0. Update with `install.packages('patchwork')`.
### Default ggsave produces non-portable PDF
**Trigger:** `ggsave('out.pdf', fig)` without `device = cairo_pdf`.
**Mechanism:** Default pdf() device produces fonts that journals reject on some systems.
**Symptom:** Submission rejected at automated check; "non-embedded fonts."
**Fix:** Always `device = cairo_pdf`.
### Figure dimensions in inches when mm intended
**Trigger:** `ggsave('out.pdf', fig, width = 180, height = 140)`.
**Mechanism:** Default `units = 'in'`.
**Symptom:** Figure file rejected for being 180 × 140 inches.
**Fix:** Explicit `units = 'mm'`.
### Panel labels not aligned to panel content
**Trigger:** patchwork `plot_annotation(tag_levels)` with subplots of different y-axis label widths.
**Mechanism:** Tag is positioned relative to the plot canvas, including the y-axis label area.
**Symptom:** LabelsRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.