Skip to main content

Publication-correct matplotlib figures, journal by journal (APS, Nature, IEEE, + presentation).

Project description

paperplot

CI Docs Python License: MIT Open in Colab Binder

Publication-correct matplotlib figures, journal by journal.

Most matplotlib styling focuses on the look. paperplot does that too — but it also handles the parts that decide whether a journal accepts your figure:

  • sizes it to the journal's real column width (8.6 cm, 17.8 cm, …), not a generic default;
  • embeds fonts correctly (Type-42, no Type-3);
  • preflights it for the rules figures actually get rejected over — font type, line weight, lettering height, and grayscale legibility.

Ships Physical Review (APS) (incl. PRL/PRX/PRB), Nature, and IEEE, plus a presentation target for slides. matplotlib-only core; seaborn/IPython are optional extras.

Just want the look? pp.register_mplstyles() then plt.style.use("paperplot-aps") — no API to learn. You give up only the parts a style sheet can't do (true column sizing, font embedding, preflight); pp.figure()/pp.save() add those back. See Drop-in style sheets.

Install

pip install paperplot-quantum                 # core (matplotlib + numpy)
pip install "paperplot-quantum[notebook]"     # + IPython for pp.show()

The PyPI package is paperplot-quantum, but you still import paperplot. Python ≥ 3.10. Latest main from GitHub: pip install "git+https://github.com/zlatko-minev/paperplot.git". Full matrix on the Install page.

30-second quickstart

import numpy as np
import paperplot as pp

pp.use("aps")                          # or "nature" / "ieee" / "prl" / "talk" — set once

fig, ax = pp.figure(width="single")    # 8.6 cm wide, golden ratio, styled
ax.plot(np.linspace(0, 10, 200), np.sin(np.linspace(0, 10, 200)))
ax.set_xlabel(r"delay $\tau$ (ns)")
ax.set_ylabel(r"population $\langle n \rangle$")

pp.save(fig, "fig1.pdf")               # embeds fonts, runs preflight()

Gallery

Same three-curve plot, same data — stock matplotlib versus one pp.use("aps"). paperplot fixes the column width, type scale, color cycle, ticks, and line weights in a single call.

matplotlib defaults
paperplot — pp.use("aps")

One figure, many panels

A custom GridSpec, four panel letters: (a) $T_1$ relaxation and (b) Ramsey fringes — each a fit with a flush residual strip — plus (c) outlined $T_1$ distributions and (d) a chevron map. Journal styling carries through a hand-built grid.

See it on the page before you submit

The part most styling packages skip: pp.preview_in_page(fig) drops your figure into a true-to-scale mock journal page with real body text — so you see exactly how big it lands in the column and whether the lettering still reads, before you submit. More in the gallery.


single column

histograms, in context

double column, across the page

Every image is generated from examples/showcase.py by docs/generate_gallery.py and regenerated by CI on each docs build (published to GitHub Pages). Build locally:

pip install -e ".[docs,notebook]"
python docs/generate_gallery.py && mkdocs serve

What you get

True journal sizing width="single"/"onehalf"/"double"/"full_page" → exact column widths in inches.
Correct export PDF default, EPS first-class; fonts embedded as Type-42, no Type-3; RGB; revision stamped in metadata.
Preflight linter pp.preflight(fig) → structured Report: flags sub-spec fonts/lines and grayscale-ambiguous colors. Warn, never block.
Colorblind-safe by default Okabe-Ito cycle; sequential/diverging maps kept separate (pp.cmap("BuGn")); custom via pp.register_palette. Fill/stroke convention: pp.fills() (muted) under pp.strokes() (bright). pp.show_palettes() shows every palette tagged for colorblind-safety.
Plot helpers pp.hist_outline (translucent fill + crisp staircase outline), pp.hist_filled, pp.data_fit_band (markers + fit + CI band), pp.swatches.
See it on the page pp.preview_in_page(fig) drops the figure into a true-to-scale mock journal page with real body text — catch sizing/legibility before you submit (a paperplot original). Plus pp.show(fig, zoom=2) and pp.grayscale_proof(fig).
Helpers pp.panel_labels(axes), pp.despine(ax), pp.clean_shared_axes(fig).

A bit more

# multi-panel, double column
fig, axes = pp.figure(width="double", nrows=2, ncols=2, sharex=True)
pp.panel_labels(axes, fmt="({})")          # (a) (b) (c) (d)
pp.clean_shared_axes(fig)

# sans-serif labels with Computer Modern math is the default (the physics look);
# math="sans" pairs Arial-style math instead, font_scale nudges every size
pp.use("aps", math="cm", font_scale=1.1)    # sticky: pp.figure() inherits both

# scoped style (doesn't leak), serif to match REVTeX Times
with pp.style("aps", serif=True):
    fig, ax = pp.figure(width="full_page")

# per-figure overrides
fig, ax = pp.figure("single", journal="prl", palette="mylab")

# overlapping histograms, fig-3 style: muted fills, crisp outlines
fig, ax = pp.figure("single")
for s, c in zip((sample_a, sample_b), pp.fills()):
    pp.hist_outline(s, ax, bins=60, rescale=True, color=c)
ax.axvline(ideal, color=pp.strokes()[8], ls="--", lw=1.2, zorder=100)

# data + fit + ±1σ band (e.g. lmfit result.eval / eval_uncertainty)
pp.data_fit_band(ax, x, y, yerr=yerr, x_fit=xf, y_fit=yf, y_fit_err=yf_err)

# pre-submission check
report = pp.preflight(fig)
if not report:                              # truthy == clean
    print(report)                           # aligned table of issues

Targets

pp.use(...) / pp.figure(journal=...) accept any of:

key target single / double width
aps (+ prl prx prb) Physical Review 8.6 cm / 17.8 cm
nature Nature 8.9 cm / 18.3 cm
ieee IEEE Transactions / conference 8.9 cm (3.5″) / 18.2 cm (7.16″)
talk slides / presentation larger type, thicker lines (scale with the target)

pp.available() lists them all. New journals are pure data — add a table to data/journals.toml; no code.

Drop-in style sheets

The product is pp.figure()/pp.save() — they size to the real column, embed fonts, and preflight, which a style sheet cannot. But the look is just rcParams, and rcParams travel as .mplstyle files, so you can adopt it with zero buy-in and graduate later:

import paperplot as pp, matplotlib.pyplot as plt

pp.register_mplstyles()                 # registers paperplot-aps/-nature/-ieee/-talk
plt.style.use("paperplot-aps")          # now use plain matplotlib
# composable, matplotlib-native: layer a built-in modifier on top
plt.style.use(["paperplot-nature", "ggplot"])

# or write a file to commit / share / drop into ~/.config/matplotlib/stylelib/
pp.export_mplstyle("ieee", "ieee.mplstyle", serif=True)

paperplot never touches matplotlib's global style library on import — registration is an explicit opt-in. A style sheet carries the target's default (single-column) size; reach for pp.figure(width=...) when you need the column-true figure.

Fonts

Journals want figure lettering in Helvetica or Arial (Nature requires it), but those are proprietary and can't be redistributed. So paperplot ships TeX Gyre Heros — a free, metric-compatible Helvetica clone — and registers it automatically. The font preference is Arial → Helvetica → TeX Gyre Heros → DejaVu Sans: if you have the real thing installed it's used, otherwise the bundled clone gives the same Helvetica look on every machine (and embeds a proper Type-42 font in the PDF, instead of silently falling back to matplotlib's DejaVu Sans). This is why the figures look identical on your laptop, a collaborator's box, and CI. Bundled under the free GUST Font License (paperplot/data/fonts/LICENSE.md).

Design

See paperplot_DESIGN.md for the full design — journal specs as data (data/journals.toml), the rcParams mapping, and the registry/versioning model.

Layout

paperplot/
  journals.py   registry.py   data/journals.toml   layout.py
  style.py      lint.py       palettes.py          preview.py
  fonts.py      save.py       core.py              plots.py
  mplstyle.py

Develop

pip install -e ".[dev]"
pytest                              # tests
python examples/run_all.py          # run every example -> examples/out/render/*.png

Releasing

Published to PyPI as paperplot-quantum via Trusted Publishing (OIDC — no stored tokens). To cut a release: bump version in pyproject.toml, push, then create a GitHub Release with tag vX.Y.Z. The release.yml workflow builds, runs twine check, and publishes. (One-time: register the trusted publisher on PyPI — repo zlatko-minev/paperplot, workflow release.yml, environment pypi.)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

paperplot_quantum-0.1.0.tar.gz (304.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

paperplot_quantum-0.1.0-py3-none-any.whl (299.6 kB view details)

Uploaded Python 3

File details

Details for the file paperplot_quantum-0.1.0.tar.gz.

File metadata

  • Download URL: paperplot_quantum-0.1.0.tar.gz
  • Upload date:
  • Size: 304.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for paperplot_quantum-0.1.0.tar.gz
Algorithm Hash digest
SHA256 41a387148036ddf598f06975fda1d88d7292431abd01bdafe1544a8effe60d85
MD5 e6d3d34c688f7ccec0e4151b13aac8a4
BLAKE2b-256 c583ae5d2a742af68f08c244abd8364b8784204d3824aec44b38d2fabe257688

See more details on using hashes here.

Provenance

The following attestation bundles were made for paperplot_quantum-0.1.0.tar.gz:

Publisher: release.yml on zlatko-minev/paperplot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file paperplot_quantum-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for paperplot_quantum-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6e2518dd410f7f176b81abd47d575082c61450046c91acc7110608fddd70a4ab
MD5 b1cbf9fa687868376765a82d9c198d36
BLAKE2b-256 8f8e5a3b9074d1d55c59eedac9b197d099e20b5a123645eda580c1b7e0bdb3f2

See more details on using hashes here.

Provenance

The following attestation bundles were made for paperplot_quantum-0.1.0-py3-none-any.whl:

Publisher: release.yml on zlatko-minev/paperplot

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page