本文へ移動
cccskills
無料GitHub で公開

bio-data-visualization-matplotlib-fundamentals

Build publication-quality figures with matplotlib using the object-oriented Figure/Axes API, constrained_layout, rcParams customization, TrueType (Type-42) font embedding for journal submission, and CVD-safe palettes. Covers seaborn integration, common chart types, axis formatting, and the small gotchas that distinguish reproducible matplotlib from notebook scratch. Use when producing publication figures in Python — RNA-seq scatter, single-cell embeddings, generic biological plotting.

インストール方法を見る

含まれるファイル(3)

  • SKILL.md11.5 KB
  • examples/matplotlib_phd.py4.3 KB
  • usage-guide.md3.9 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Version Compatibility

Reference examples tested with: matplotlib 3.8+, seaborn 0.13+, numpy 1.26+, pandas 2.2+.

Before using code patterns, verify installed versions match. If versions differ:

  • Python: pip show <package> then help(module.function) to check signatures

If code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.

matplotlib Fundamentals

"Make a publication figure in Python" -> Build via the object-oriented Figure/Axes API (not pyplot state-machine), with constrained_layout for axes alignment, pdf.fonttype=42 for journal-compliant TrueType fonts, CVD-safe palettes, and rasterized point layers for large scatter. The pyplot interface is for notebook scratch; the Figure/Axes API is for reproducible figures.

  • Python: fig, ax = plt.subplots() -> ax.scatter / ax.plot / ax.bar; seaborn.objects (new grammar API) for ggplot-like

The Three Modern Defaults

  1. Object-oriented API — fig, ax = plt.subplots(figsize=(4, 3)) then ax.scatter(x, y), ax.set_xlabel(...). The pyplot state-machine (plt.scatter, plt.xlabel) hides which axes are being modified and breaks in multi-subplot figures.

  2. constrained_layout — plt.subplots(constrained_layout=True) automatically prevents axis-label clipping and tight-packs subplots. Replaces the older tight_layout() and is the default in matplotlib 3.6+.

  3. Type-42 (TrueType) font embedding — plt.rcParams['pdf.fonttype']=42 produces searchable/editable PDF text. Default Type-3 PostScript glyphs are not searchable and rejected by Nature, IEEE, ACM, and many other publishers.

Standard Setup for Publication

import matplotlib.pyplot as plt
import matplotlib as mpl

# rcParams for publication compliance
mpl.rcParams.update({
    'pdf.fonttype': 42,                 # TrueType -- searchable PDFs
    'ps.fonttype': 42,                  # TrueType in EPS
    'font.family': 'sans-serif',
    'font.sans-serif': ['Arial', 'Helvetica', 'DejaVu Sans'],
    'font.size': 7,                     # Nature requires 5-7 pt body text
    'axes.labelsize': 7,
    'axes.titlesize': 8,
    'xtick.labelsize': 6,
    'ytick.labelsize': 6,
    'legend.fontsize': 6,
    'figure.dpi': 100,                  # display
    'savefig.dpi': 300,                 # save
    'savefig.bbox': 'tight',
    'savefig.pad_inches': 0.05,
    'axes.linewidth': 0.5,
    'xtick.major.width': 0.5,
    'ytick.major.width': 0.5,
    'lines.linewidth': 1.0,
    'patch.linewidth': 0.5,
})

Figure / Axes API

import matplotlib.pyplot as plt

# Single axes
fig, ax = plt.subplots(figsize=(89/25.4, 70/25.4),       # 89mm x 70mm in inches; Nature single col
                       constrained_layout=True)
ax.scatter(x, y, c='#0072B2', s=10, alpha=0.7, edgecolors='none', rasterized=True)
ax.set_xlabel('PC1 (45%)')
ax.set_ylabel('PC2 (12%)')
ax.spines[['top', 'right']].set_visible(False)
fig.savefig('scatter.pdf')

# Grid of axes
fig, axes = plt.subplots(2, 3, figsize=(180/25.4, 100/25.4),  # 180mm double col
                          constrained_layout=True)
for ax, (label, panel_data) in zip(axes.flat, data.items()):
    ax.plot(panel_data['x'], panel_data['y'])
    ax.set_title(label, fontsize=8)

Common Chart Types

# Scatter -- always rasterized for >1000 points
ax.scatter(x, y, c=values, cmap='viridis', s=8, alpha=0.6,
           edgecolors='none', rasterized=True)
plt.colorbar(ax.collections[0], ax=ax, label='Expression', shrink=0.8)

# Line
ax.plot(x, y1, color='#0072B2', label='Control', linewidth=1)
ax.plot(x, y2, color='#D55E00', label='Treatment', linewidth=1)
ax.fill_between(x, y_low, y_high, color='#0072B2', alpha=0.2)
ax.legend(frameon=False, fontsize=6)

# Bar
ax.bar(categories, values, color='#0072B2', edgecolor='black', linewidth=0.5)

# Box / violin (prefer seaborn for these -- see distribution-plots)
ax.boxplot([group_a, group_b, group_c], labels=['A', 'B', 'C'],
           patch_artist=True, boxprops=dict(facecolor='#0072B2', alpha=0.7))

# Histogram
ax.hist(values, bins=30, color='#0072B2', edgecolor='white', linewidth=0.5)

# Heatmap (prefer seaborn for clustered; see heatmaps-clustering)
im = ax.imshow(matrix, cmap='RdBu_r', aspect='auto', vmin=-vmax, vmax=vmax)
plt.colorbar(im, ax=ax, label='Z-score')

seaborn Integration

import seaborn as sns

# seaborn shares the matplotlib Figure/Axes -- pass ax= argument
fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
sns.scatterplot(data=df, x='log_fold_change', y='neg_log_p',
                hue='significance', palette=['#999999', '#0072B2', '#D55E00'],
                s=10, alpha=0.7, ax=ax, rasterized=True)

# seaborn 0.13+ has the `objects` grammar interface (ggplot-like)
import seaborn.objects as so
(so.Plot(df, x='log_fold_change', y='neg_log_p')
   .add(so.Dots(pointsize=2), color='significance')
   .scale(color=['#999999', '#0072B2', '#D55E00']))

Return-type gotcha: seaborn axes-level functions (scatterplot, boxplot, barplot) return Axes. Figure-level (displot, relplot, catplot) return FacetGrid — needs .set_axis_labels(x, y) not .set_xlabel(x).

Axis Formatting

# Log scale
ax.set_yscale('log')

# Scientific notation
from matplotlib.ticker import ScalarFormatter
ax.xaxis.set_major_formatter(ScalarFormatter(useMathText=True))

# Date axis
import matplotlib.dates as mdates
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))

# Tick frequency
ax.set_xticks(np.arange(0, 10, 2))
ax.set_xticklabels(['A', 'B', 'C'], rotation=45, ha='right')

# Grid
ax.grid(axis='y', alpha=0.3, linestyle='--', linewidth=0.5)

Color and Palette

# CVD-safe categorical
okabe_ito = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
             '#0072B2', '#D55E00', '#CC79A7', '#000000']

# Perceptually-uniform sequential (Crameri batlow / viridis cividis)
from cmcrameri import cm as cmc
plt.imshow(data, cmap=cmc.batlow)
plt.imshow(data, cmap='viridis')                          # built-in

# Diverging symmetric for LFC / z-score
vmax = np.quantile(np.abs(data), 0.99)
plt.imshow(data, cmap='RdBu_r', vmin=-vmax, vmax=vmax)   # symmetric

See data-visualization/color-palettes for full palette decision tree.

Saving

# PDF for vector text + raster scatter (best of both)
fig.savefig('figure.pdf', dpi=300, bbox_inches='tight')

# PNG for raster (web, presentations)
fig.savefig('figure.png', dpi=300, bbox_inches='tight')

# TIFF for some journals
fig.savefig('figure.tiff', dpi=300, pil_kwargs={'compression': 'tiff_lzw'})

# SVG for editable vector
fig.savefig('figure.svg', bbox_inches='tight')

Common Failure Modes

Default Type-3 fonts rejected by journals

Trigger: Default pdf.fonttype=3 (PostScript Type 3 glyphs as drawing operators).

Mechanism: Type-3 glyphs are not searchable or selectable; many journals reject.

Symptom: Submission rejected at automated check; "Type 3 fonts not permitted."

Fix: mpl.rcParams['pdf.fonttype']=42 AND ps.fonttype=42. Verify with pdffonts figure.pdf showing TrueType.

tight_layout fails on complex grids

Trigger: plt.tight_layout() on a figure with colorbars or shared axes.

Mechanism: tight_layout doesn't account for axes added after-the-fact (colorbars).

Symptom: Labels clipped; subplots overlap colorbar.

Fix: Use constrained_layout=True in plt.subplots() instead; or fig.set_constrained_layout(True) after creation.

pyplot state-machine in multi-subplot

Trigger: plt.xlabel(...) after plt.subplots(2, 3).

Mechanism: pyplot calls modify the current axes — usually the last created. Multi-subplot code becomes order-dependent.

Symptom: Wrong subplot gets the label.

Fix: Use ax.set_xlabel(...) with explicit axes reference.

Scatter of 100000 points crashes PDF viewer

Trigger: Vector scatter at large N; one PDF page becomes 50 MB.

Mechanism: Each scatter point is a vector circle.

Symptom: PDF takes 30 seconds to open; Illustrator crashes; reviewer files complaint.

Fix: rasterized=True on the scatter call. Keep axes and text vector.

seaborn FacetGrid vs Axes return-type confusion

Trigger: g = sns.displot(...); calling g.set_xlabel('x') fails.

Mechanism: displot returns FacetGrid; needs .set_axis_labels(x, y) or per-axes iteration.

Symptom: AttributeError on .set_xlabel.

Fix: Use set_axis_labels for FacetGrid; set_xlabel for Axes. Switch to axes-level sns.histplot(ax=ax) to get Axes-API behavior.

figsize in inches when mm was intended

Trigger: figsize=(89, 70) thinking mm; matplotlib expects inches.

Mechanism: Default figure unit is inches.

Symptom: Figure is 89 inches wide.

Fix: Convert: figsize=(89/25.4, 70/25.4) for mm input.

Colorbar over-fills the axes

Trigger: Default plt.colorbar(im, ax=ax).

Mechanism: Colorbar takes the same height as the axes; on small subplots dominates.

Symptom: Subplot looks squished.

Fix: plt.colorbar(im, ax=ax, shrink=0.6, aspect=20); or use make_axes_locatable for fine control.

Vector grid + rasterized scatter mixed properly

Trigger: Want vector axes + raster scatter; save as PDF.

Mechanism: Default rasterization can include axes if not controlled.

Symptom: Whole plot rasterized; axis text blurry on zoom.

Fix: Per-element rasterized=True on scatter only; axes and text stay vector. Set fig.set_rasterization_zorder(0) to globally control.

Common Errors

Error / symptomCauseSolution
PDF rejected by journalType-3 fontspdf.fonttype=42
Subplots overlapNo constrained_layoutplt.subplots(constrained_layout=True)
Wrong subplot labeledpyplot state-machineUse ax.set_xlabel explicitly
50 MB PDFVector scatter at large Nrasterized=True on scatter
Figure too bigmm interpreted as inchesDivide by 25.4
Colorbar dominatesDefault sizeshrink=0.6, aspect=20
seaborn .set_xlabel failsFacetGrid not Axesg.set_axis_labels(x, y)
Axes spine missingWrong APIax.spines[['top','right']].set_visible(False)

References

  • Hunter JD. 2007. Matplotlib: A 2D graphics environment. Comput Sci Eng 9(3):90-95.
  • Rougier NP, Droettboom M, Bourne PE. 2014. Ten simple rules for better figures. PLOS Comp Biol 10(9):e1003833.
  • Waskom ML. 2021. seaborn: statistical data visualization. J Open Source Softw 6(60):3021.

Related Skills

  • data-visualization/color-palettes - Palette selection
  • data-visualization/multipanel-figures - GridSpec and patchwork-equivalent layouts
  • data-visualization/distribution-plots - seaborn boxplot/violin/raincloud
  • data-visualization/heatmaps-clustering - seaborn.clustermap
  • data-visualization/volcano-and-ma-plots - matplotlib scatter for volcano
  • reporting/figure-export - DPI / format / journal-spec details

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Testing patterns for PHPUnit and Playwright E2E tests. Use when writing tests, debugging test failures, setting up test coverage, or implementing test patterns for ActivityPub features.

日本語の概要は準備中です。原文の説明を表示しています。

lilinji/GeneTind-Life-Skills142026年8月21日 更新

adaptyv

無料

How to use the Adaptyv Bio Foundry API and Python SDK for protein experiment design, submission, and results retrieval. Use this skill whenever the user mentions Adaptyv, Foundry API, protein binding assays, protein screening experiments, BLI/SPR assays, thermostability assays, or wants to submit protein sequences for experimental characterization. Also trigger when code imports `adaptyv`, `adaptyv_sdk`, or `FoundryClient`, or references `foundry-api-public.adaptyvbio.com`.

日本語の概要は準備中です。原文の説明を表示しています。

lilinji/GeneTind-Life-Skills142026年8月21日 更新

Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.

日本語の概要は準備中です。原文の説明を表示しています。

lilinji/GeneTind-Life-Skills142026年8月21日 更新

Time-blind friendly planning, executive function support, and daily structure for ADHD brains. Specializes in realistic time estimation, dopamine-aware task design, and building systems that actually work for neurodivergent minds.

日本語の概要は準備中です。原文の説明を表示しています。

lilinji/GeneTind-Life-Skills142026年8月21日 更新

aeon

無料

This skill should be used for time series machine learning tasks including classification, regression, clustering, forecasting, anomaly detection, segmentation, and similarity search. Use when working with temporal data, sequential patterns, or time-indexed observations requiring specialized algorithms beyond standard ML approaches. Particularly suited for univariate and multivariate time series analysis with scikit-learn compatible APIs.

日本語の概要は準備中です。原文の説明を表示しています。

lilinji/GeneTind-Life-Skills142026年8月21日 更新

Unified analysis pipeline for affinity-based proteomics platforms — Olink (PEA, NPX) and SomaLogic SomaScan (SOMAmer, RFU). Platform-aware QC, normalisation, differential abundance, volcano plots, heatmaps, and PCA.

日本語の概要は準備中です。原文の説明を表示しています。

lilinji/GeneTind-Life-Skills142026年8月21日 更新

lilinji のスキルをすべて見る

このスキルの問題を報告する