pythonforbio.
[WASM idle]
Library Overview02/06

Matplotlib

Starting sandbox…
Beginnerlesson

Matplotlib

In one line: a drawing library where every mark on the page is an object you can reach and change.

Version at time of writing: 3.11.x · import matplotlib.pyplot as plt

The mental model

Three nested containers, and one rule.

Figure  ──▶ the whole canvas; owns the size, the DPI, the saving
  └─ Axes ──▶ one plotting panel; owns the data area, ticks, labels
       └─ Artist ──▶ every drawn thing: Line2D, Text, Patch, Collection

The rule: everything you see is an Artist attached to an Axes, and every Artist has getters and setters. If you can see it, you can change it. That is why matplotlib is verbose and why it never dead-ends — unlike higher-level libraries, there is no plot you cannot eventually produce.

"Axes" means a panel, not an axis. A 2×2 grid has four Axes. The x-axis of one panel is ax.xaxis. This naming causes real confusion; see Figure and Axes.

The one habit that matters

Use the object-oriented API, not the implicit plt. state machine:

fig, ax = plt.subplots(figsize=(6, 4))
ax.scatter(x, y)
ax.set_xlabel("log2 fold change")
fig.savefig("plot.pdf", bbox_inches="tight")

not

plt.scatter(x, y)
plt.xlabel("log2 fold change")   # ← which Axes did this hit?
plt.savefig("plot.pdf")

The plt. form writes to whatever the "current" Axes happens to be, which breaks the moment you have subplots, a loop, or a seaborn call in between. See pyplot vs Object-Oriented API.

Why bioinformatics cares

Journals want vector figures at specific column widths with editable text. Only matplotlib gives you that control: exact figure sizes in inches, fonts embedded as text rather than paths, colourblind-safe palettes, and per-Artist tweaking for the one gene label that overlaps another. Seaborn gets you 90% of the way in one line, and then you reach through to matplotlib for the last 10%.

Core notes

Structure Figure and Axes · pyplot vs Object-Oriented API · Matplotlib Artists · Subplots and Layout

Content Common Plot Types · Axes Styling and Annotation · Colormaps and Color

Output Saving Figures · rcParams and Style Sheets

Applied

Applied - Differential Expression Volcano Plot · Applied - Heatmaps and Clustermaps · Applied - Quality Control Plots

Install and check

pip install "matplotlib>=3.10,<4"
python -c "import matplotlib; print(matplotlib.__version__, matplotlib.get_backend())"

If figures do not appear, the backend is usually the culprit. In a headless script or container use matplotlib.use("Agg") before importing pyplot and save to file rather than showing.

The 20% that gets 80% of the work done

fig, axes = plt.subplots(1, 2, figsize=(10, 4), sharey=True, layout="constrained")

axes[0].scatter(x, y, s=8, alpha=0.5, c=colours)
axes[0].axhline(0, ls="--", lw=1, color="grey")
axes[0].set(xlabel="log2FC", ylabel="-log10 p", title="Volcano")

axes[1].hist(y, bins=50)
axes[1].set_xlabel("-log10 p")

fig.savefig("figure.pdf", bbox_inches="tight")
plt.close(fig)

layout="constrained" (the modern replacement for tight_layout()) fixes overlapping labels automatically. plt.close(fig) in loops prevents the memory leak that produces the "More than 20 figures have been opened" warning.

Gotchas that bite newcomers

  • Figures never close in a loop → memory grows until the process dies. Always plt.close(fig).
  • Text saved as paths instead of glyphs, so editors cannot change it. Set rcParams["pdf.fonttype"] = 42. See Saving Figures.
  • Jet / rainbow colormaps. They are perceptually non-uniform and invent structure that is not there. Use viridis. See Colormaps and Color.
  • plt.show() inside a script blocks; inside a notebook it is usually redundant.
  • Resizing after saving does nothing — the save captured the state at that moment.

See also

Seaborn · Ecosystem Map · Pandas

scratch

No output yet — run the code to populate this drawer.

BiopythonNumPy