Two things stand between a rough plot and a figure a journal editor will trust, and neither gets taught in any one place. The first is knowing which of the seventy-odd chart types actually fits the data in front of you, instead of reaching for a bar chart because that's the reflex. The second is craft — the small, unglamorous rules you tend to learn the hard way, somewhere around the second round of reviewer comments: colours that still separate for a colour-blind reader, points drawn on top of bars rather than hidden behind them, a sequential colour map instead of the rainbow, real vector output. I kept re-deriving that same handful of rules every time I built a figure, so I collected them here, and I added a small program that just answers "which chart should I use?" rather than leaving you to scroll and guess.
| Path | What it is |
|---|---|
references/graph-style-library.md |
74 graph styles across 9 purposes, a decision layer, and a 16-rule anti-pattern registry |
scripts/choose_graph.py |
A decision engine — describe your intent and it returns ranked styles, the anti-patterns it rejects for your case, and the palette to use |
scripts/graph_catalog.json |
The machine-readable index the engine reads (styles, anti-patterns, palettes, style-engines, methods) |
references/publication-ready-figures.md |
The craft rules: zero-overlap checks, one colorblind-safe palette, typography, accessibility, journal style-engines (SciencePlots, ultraplot), journal color cycles |
references/statistics-rigor.md, references/domain-conventions.md |
The statistics behind the graphs, and how to keep them domain-correct for IVIVC / dissolution / PK / PBPK / CFD / PINN work |
scripts/generate_gallery.py, scripts/_figure_qc.py |
The gallery builder (synthetic seeded data) and the deterministic text-overlap gate every figure is checked against as it is drawn |
examples/ |
138 worked example figures across 10 categories (PNG + vector PDF), regenerated by the builder above |
python3 scripts/choose_graph.py --intent "compare means" --data categorical --n 4 --domain PKRecommended styles (ranked)
S1 Bar + individual data points (dot-on-bar)
S25 Confidence-interval / equivalence forest
S30 Semi-log PK concentration-time profile
Rules enforced
AP2 drop the violin/box — quartiles are unstable below n = 20
DS5 drop mean±SD + t-test — PK wants geometric mean, log axis, 90% CI
Palette: Okabe-Ito (colorblind-safe) Method: geometric mean / 90% CI (BE 80-125%)
An intent is all it really needs, but a sharper answer comes back if you also pass the shape of the data, the sample size, the domain, and the journal you're aiming at. The catalog is read and you get a short ranked list with the reasoning already attached — which was the whole point, since I never wanted a menu, I wanted the decision made. The flags are --intent --data --n --domain --journal --json.
There are 138 figures, and each one is drawn from synthetic seeded data, so anyone who reruns the script gets exactly the same picture back rather than something that drifts between machines. They were built to obey the same rules the library preaches, which felt like the only honest way to ship it: a single colorblind-safe palette, points on the bars, exact statistics, sequential colour maps instead of jet, clean axes, vector output. The full set is laid out with a caption on each in examples/README.md. Redrawing them is a two-line job:
pip install -r requirements.txt # matplotlib, numpy, scipy, seaborn, networkx, pandas (no LaTeX)
python3 scripts/generate_gallery.py # the full gallery, Okabe-Ito default
python3 scripts/generate_gallery.py --palette npg # or recolour it to any catalog palette
python3 scripts/generate_gallery.py --list-palettes # okabe_ito, npg, aaas, nejm, lancet, jama, prism_colorblind_safeThe gallery page lays the thumbnails out three across so the whole set scrolls quickly, and --palette recolours every figure to a named palette from the catalog (a colorblind-safety warning prints for any non-Okabe choice). The PDFs are written without an embedded timestamp, so a rebuild that changed nothing produces byte-identical files.
The ten categories run from the everyday to the specialized: distributions, correlation, comparison, part-of-whole, flow and network, time-series, scientific and biomedical, single-cell / omics / cytometry, 3D and fields, and the multi-panel layouts you reach for when several small pictures have to read as one story.
- Decide, don't hunt. A catalog paired with a chooser beats a wall of options you scroll past — most of all at four in the afternoon, when the figure was due an hour ago.
- Colorblind-safe by default. Okabe-Ito is used unless you ask for something else (Wong 2011). The journal colour cycles are there when a house style insists on one, but you're warned whenever the cycle you picked isn't actually colorblind-safe.
- The mistakes are enforced, not just listed. Bars that hide a distribution, violins at tiny n, jet colour maps, pie and donut charts, heatmaps whose rows were never sorted — sixteen anti-patterns are encoded (AP1 through AP16), each tied back to the paper that documented it.
- Domain-aware. A modeling trick is never quietly laundered onto a wet-lab endpoint. PK is given geometric means and 90% CIs, dissolution is judged by f2, and a model is asked for parity and agreement before anyone has to believe it.
The breadth of graph types and the modeling-statistics notes were distilled — as technique, not code — from Nathan Kutz's Data-Driven Modeling & Scientific Computation. The anti-pattern registry comes from FriendsDontLetFriends (MIT), with the literature it cites (Wong 2011, Weissgerber 2015). The journal style-engines are SciencePlots and ultraplot, both MIT; the journal palette hex values were lifted from ggsci and ggprism, on the view that a colour value is a fact and their GPL-3 code could be left alone. Six of the newer chart types (swimmer plot, compact-letter-display bars, binned heatmap, Circos, Mantel composite, polar heatmap) were rebuilt as matplotlib idioms after studying GeneticistHere/ggplot2-20-journal-cases — the idioms, not the R code. The standards the figures are held to were benchmarked against a handful of Nature-family papers, and those analyses are kept in references/_exemplar_mining/.
MIT — see LICENSE. The example data are synthetic throughout.


