SuperAPI AI Directory

scientific-visualization

Data & analytics

View repository

Updated 10-16 05:55

About this skill

Scientific Visualization (CS Edition)

Overview

Turn benchmark and experiment data into publication-quality figures for CS venues. This skill is opinionated for systems, ML, networking, and security papers: it covers latency CDFs, throughput curves, training-loss plots, ablation bars, speedup comparisons, and Pareto fronts. It replaces the upstream biology-leaning version (microscopy, gene expression, fluorophores) with CS conventions and CS venue specs (IEEE, ACM, USENIX, NeurIPS, ICML, ICLR, arXiv).

The plugin produces LaTeX-only manuscripts. PDF is the default figure format — it embeds losslessly into LaTeX via \includegraphics{...}, scales without artifacts, and matches every CS venue's preferred line-art format. Use PNG only for raster screenshots, profilers, or visualizations that already started as raster.

Scope

Use this skill when:

  • Creating plots for a CS paper (latency, throughput, accuracy, loss, memory, F1, CDF, etc.)
  • Targeting IEEE Transactions, an ACM conference (acmart), a USENIX venue, NeurIPS / ICML / ICLR, or arXiv
  • Building multi-panel figures with consistent styling
  • Drawing a concept plot: idealized curves, distributions, or point clouds that illustrate a mechanism or a failure mode, made in matplotlib so its axes and colors match the result figures (Pattern 19 in references/matplotlib_examples.md)
  • Ensuring figures stay readable in grayscale and for colorblind reviewers
  • Exporting at the right resolution and format for LaTeX inclusion

Do not use this skill for:

  • Architecture / data-flow / pipeline schematics — use superpower-writing:tikz-figures (vector) or superpower-writing:scientific-schematics (image-model PNG). The split: boxes and arrows between named components go to those skills; a concept whose content is a curve, a distribution, a geometric picture, or a trajectory through a space stays here.
  • Ad-hoc exploratory plots in a notebook — just import seaborn / plotly directly
  • Tables — use LaTeX booktabs directly; no Python needed

Quick Start

Single-column IEEE figure (most common case)

import matplotlib.pyplot as plt
import numpy as np

# Apply IEEE-tuned publication style (sets fonts, sizes, default palette)
plt.rcParams.update({
    'figure.dpi': 100, 'savefig.dpi': 600,
    'font.family': 'sans-serif', 'font.sans-serif': ['Arial', 'Helvetica', 'DejaVu Sans'],
    'font.size': 8, 'axes.labelsize': 9, 'axes.titlesize': 9,
    'xtick.labelsize': 7, 'ytick.labelsize': 7, 'legend.fontsize': 7,
    'axes.linewidth': 0.5, 'lines.linewidth': 1.5,
    'axes.spines.top': False, 'axes.spines.right': False,
    'savefig.format': 'pdf', 'savefig.bbox': 'tight',
})
# figures4papers semantic palette: colors carry roles, not cycle order
OURS, BASELINE = '#0F4D92', '#B64342'   # blue_main, red_strong

# IEEE single-column = 3.5 inches
fig, ax = plt.subplots(figsize=(3.5, 2.4))

x = np.array([1, 2, 4, 8, 16, 32])
baseline_p99 = np.array([12.4, 13.1, 14.8, 18.6, 27.3, 49.5])
proposed_p99 = np.array([10.2, 10.4, 11.1, 12.7, 16.4, 24.0])

ax.plot(x, baseline_p99, marker='o', linestyle='--', color=BASELINE, label='Baseline')
ax.plot(x, proposed_p99, marker='s', color=OURS, label='Ours')

ax.set_xlabel('Concurrent clients')
ax.set_ylabel(r'p99 latency (ms)')
ax.set_xscale('log', base=2)
ax.legend(frameon=False, loc='upper left')

fig.savefig('latency_p99.pdf', bbox_inches='tight')

The output drops into LaTeX with \includegraphics[width=\columnwidth]{figures/latency_p99.pdf}.

Using a bundled style file

The plugin ships matplotlib style files under ${CLAUDE_PLUGIN_ROOT}/skills/scientific-visualization/assets/. Load one with the absolute path:

import os, matplotlib.pyplot as plt
PLUGIN = os.environ['CLAUDE_PLUGIN_ROOT']
plt.style.use(f'{PLUGIN}/skills/scientific-visualization/assets/ieee.mplstyle')
# or 'acm.mplstyle', 'neurips.mplstyle', 'publication.mplstyle', 'presentation.mplstyle'

To make figures self-contained (no env-var dependency), copy the chosen style file into .writing/figures/ once and reference it locally.

Core Principles

1. Format and resolution

  • Vector PDF for every plot. Embeds in LaTeX without rasterization, scales perfectly. Use fig.savefig('foo.pdf', bbox_inches='tight').
  • PNG at 300 – 600 DPI only for raster content (screenshots, profilers, heatmaps with thousands of cells where a vector explodes). Set savefig.dpi: 600 for PNGs going into camera-ready.
  • Never JPEG for plots. The lossy artifacts around lines and text are obvious in print.
  • Embed fonts in PDFs — matplotlib does this by default with pdf.fonttype: 42 (TrueType). Without it, IEEE / ACM sometimes flag text as "Type 3 fonts" during eXpress / paperplaza checks.
plt.rcParams['pdf.fonttype'] = 42  # TrueType, embedded
plt.rcParams['ps.fonttype'] = 42

2. Color: semantic palette by default

The default categorical palette comes from figures4papers (Chen Liu's figures for Nature Machine Intelligence, ICML, NeurIPS, and ECCV papers). Colors carry roles, and the reader learns them from the first figure:

OURS       = '#0F4D92'                         # blue_main: the proposed method, nothing else
ABLATION   = '#3775BA'                         # blue_secondary at alpha 0.2 -> 1.0 for variants of ours
GREENS     = ['#DDF3DE', '#AADCA9', '#8BCF8B'] # related family, light to dark
REDS       = ['#F6CFCB', '#E9A6A1', '#B64342'] # contrasting family, light to dark
NEUTRAL, GRAY = '#CFCECE', '#767676'           # reference fill, reference line
F4P_CYCLE  = ['#0F4D92', '#B64342', '#8BCF8B', '#42949E', '#767676']  # when roles are not hand-assigned
  • Color a family, shade a variant. Methods from one family share a hue and step light to dark, strongest member nearest to ours.
  • Colorblind limits are measured, not assumed. The first four cycle colors stay at least 21 CAM02-UCS units apart under simulated deuteranopia, protanopia, and tritanopia. The light reds (red_1, red_2, red_mid) fall to 4 to 8 against greens under deuteranopia. When a light red appears next to any green, hatch (bars) or dash (lines) the reds, unless a tick or direct label names every bar or line. red_strong stays 28 or more from every green. From the fifth series on, markers and line styles carry the distinction.
  • Okabe-Ito is the strict alternative for figures that must separate more than four series by color alone, or when a co-author or venue names a palette. references/color_palettes.md has the role rules, the measured pair table, and a checker for a project's own METHOD_COLORS.

For heatmaps:

  • Sequential single-variable data (latency, accuracy, count): viridis or cividis. Both are perceptually uniform and colorblind-safe.
  • Diverging data (speedup vs baseline, log-fold change, error signed): RdBu_r or PuOr centered at the neutral value. Avoid RdGn / RdYlGn.
  • Never jet or rainbow. Not perceptually uniform; over-emphasizes mid-range; bad in B/W. Reviewers will flag this.

Always add redundant encoding beyond color: line styles ('-', '--', ':'), markers ('o', 's', '^'), or hatching on bars. If the figure still reads in grayscale, the color choice is solid.

3. Typography

  • Sans-serif at the final printed size. Always give a fallback list, ['Arial', 'Helvetica', 'DejaVu Sans']: Linux machines usually lack Helvetica, and a bare font.family = 'helvetica' warns and falls back to an arbitrary font.
  • Stroke weight in proportion. Spines, lines, and error bars thin enough to vanish make a figure look like a matplotlib default. At column width use axis lines of 0.6 to 0.8 pt and data lines of 1.2 to 1.5 pt; the heavier strokes are what make the figures4papers plots read as finished.
  • Minimums at the size that lands on the page:
    • Axis labels: 8 pt
    • Tick labels: 7 pt
    • Legend: 7 pt
    • Panel labels (a, b, c): 9 – 10 pt bold
  • Embed fonts. Use pdf.fonttype: 42 so TrueType fonts ship inside the PDF.
  • One size hierarchy per figure: tick labels ≤ legend ≤ axis labels < panel labels, and in-figure annotations no larger than tick labels. An axis label at twice the tick size, or a value label bigger than the axis label, reads as unfinished.
  • Sentence case: Throughput (req/s) not THROUGHPUT (REQ/S).
  • Always include units in parentheses. Use SI / IEC prefixes consistently (KB, MiB, μs, not K, M, us).

4. Figure dimensions for CS venues

Venue Single column Double column / full Typical class file
IEEE Transactions / Conf. 3.5 in (89 mm) 7.16 in (182 mm) IEEEtran
ACM (sigconf, acmsmall) 3.33 in (8.45 cm) 7.0 in (17.78 cm) acmart
USENIX (Annual / OSDI / NSDI / Sec.) 3.33 in 7.0 in usenix2019_v3
NeurIPS / ICML / ICLR n/a (one column) 5.5 in (14.0 cm) venue style
arXiv follow target venue follow target venue venue style

Match \columnwidth exactly when you use \includegraphics[width=\columnwidth]. Set figsize=(3.5, ...) for IEEE single-column figures and let LaTeX scale only when the figure spans both columns.

Drawing on a larger canvas and letting LaTeX shrink it is also valid (figures4papers draws at 28 in with 24 pt text, which lands near 6 pt at 7 in), provided every figure in the paper uses the same scale factor and the text lands at or above the minimums above after scaling. Mixed factors are what make one figure's labels twice the size of the next one's. Compute the printed size as font_pt * printed_width / figsize_width before committing.

See references/venue_requirements.md for the full per-venue spec, including \figcomp / \columnsep quirks and ACM's two-class width difference.

5. Multi-panel layout

  • Label panels with bold lowercase letters: (a), (b), (c) — IEEE and ACM both use lowercase parenthesized.
  • Use GridSpec for non-uniform layouts; plt.subplots() for uniform grids.
  • Align panels along edges; equalize axis ranges across panels comparing the same quantity.
  • Use constrained_layout=True (replaces tight_layout) — handles colorbars and panel labels better.
from string import ascii_lowercase

fig = plt.figure(figsize=(7.0, 4.0), constrained_layout=True)  # ACM full width
gs = fig.add_gridspec(2, 3)
axes = [fig.add_subplot(gs[i // 3, i % 3]) for i in range(6)]

for i, ax in enumerate(axes):
    ax.text(-0.20, 1.05, f'({ascii_lowercase[i]})',
            transform=ax.transAxes, fontsize=10, fontweight='bold', va='top')

Multi-panel anti-redundancy checklist

A multi-panel figure should read as one figure where each panel earns its space. Covering any one panel must leave a gap the others cannot fill. Run this before finalizing a composite:

  • Every panel answers a distinct question. Write the one-line question each panel answers; if two lines are the same, one panel is redundant.
  • No panel re-displays a subset of another panel's data in a different visual form. A bar of per-method accuracy plus a heatmap of the same accuracies is the same data twice.
  • No panel is a slice of another. A "method X only" bar that is just one group pulled out of the grouped-bar panel adds nothing; replace it with a relationship view (scatter, trade-off).
  • Each panel has its own axis vocabulary (different x/y quantities), not the same axes recomputed.

Common redundancy traps and the fix:

Trap CS example Fix
Absolute + absolute Grouped-bar accuracy + heatmap of the same accuracies Replace the heatmap with a deviation view (per-method delta vs baseline)
Subset of parent "Ours-only" latency bar that is one column of the grouped bar Swap for a scatter: latency vs throughput across methods
Two rankings Two ranked bars on accuracy and on F1 (highly correlated) Replace one with an accuracy-vs-F1 scatter
Same slice, different chart Pie plus stacked bar of one breakdown Merge, or replace one with a trade-off plot

When a panel shows absolute values, a good companion panel shows what is atypical (a signed deviation from a baseline or mean, on a diverging colormap like RdBu_r) rather than the same absolutes again. A third panel that reveals co-variation between two of the quantities (a scatter or bubble plot, with reference lines at the medians) adds a dimension the first two lack.

Generalizable multi-panel techniques

These transfer to almost any CS composite:

  • Luminance-based in-bar text color. When you print values inside bars, pick black or white text by the bar's luminance so the number stays readable on both light and dark fills:

    for bar, value in zip(bars, values):
        r, g, b = bar.get_facecolor()[:3]
        luminance = 0.299 * r + 0.587 * g + 0.114 * b   # 0..1
        ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height(),
                f'{value:.2f}', ha='center', va='bottom',
                color='white' if luminance < 0.5 else 'black')
    
  • Dynamic y-limit tightening. Never leave 0–100 when the values sit in a narrow band (e.g. accuracies of 80–95). A fixed wide range flattens the differences the figure exists to show. Tighten to the data with a small margin:

    lo, hi = data.min(), data.max()
    margin = 0.05 * (hi - lo)
    ax.set_ylim(lo - margin, hi + margin)
    

    For a bar chart, the lower limit must be a meaningful floor: zero, the chance level (0.5 for AUROC, 1/k for k-way accuracy), or the baseline's score, named on the axis, a reference line, or in the caption. A floor picked to make the gap look large (0.15 for an AUPRC panel because the worst method scores 0.2) is a silent truncation; use a broken-axis indicator or start at zero.

  • Dedicated legend-only subplot. For a multi-axis figure where one shared legend serves all panels, reserve the last cell for the legend alone instead of crowding one panel or repeating legends:

    ax_legend = fig.add_subplot(gs[-1])
    ax_legend.legend(handles, labels, loc='center', frameon=False)
    ax_legend.set_axis_off()
    

    Prefer one shared legend strip (or direct labels on stable regions) over repeating a legend inside every axis.

  • Bars identified by the legend alone. With one legend panel, the x ticks of a method-comparison bar row can go (ax.set_xticks([])) instead of repeating nine rotated method names under every metric. Do this only when every method has a unique color, method order is identical in every panel, and legend order equals bar order (ours last in both). Otherwise keep tick labels, or switch to horizontal bars.

  • Direction marks in axis labels. Append ↑ or ↓ to a metric label (AUROC ↑, p99 latency (ms) ↓) when panels mix metrics where higher is better and lower is better. The reader stops checking the caption to learn which way is good.

  • Reference lines that state the claim. A reference line is worth drawing when it is the claim: the full model's score across an ablation (Pattern 13), "SFT only" as the floor every method must clear, or a dotted line from ours at 25 percent data to where a baseline needs 100 percent (Pattern 15). Label each reference line in place or in the legend.

Common CS Figure Patterns

Reference implementations live in references/matplotlib_examples.md. To choose among these and the standard ML charts by the question the figure answers, with scale remedies and venue cautions, read references/chart-chooser.md. The patterns covered:

Pattern Use case Notes
Latency CDF / ECDF Tail behavior of a request distribution Log-scale x-axis; cap at p99 or p99.9; include median + tail callouts
Throughput vs concurrency Scaling curves Log-scale x; mark saturation knee; pair with median latency
Speedup bar chart Per-benchmark improvement vs baseline Always include 1.0 × reference line; group by suite
Training / loss curves ML convergence Show mean over seeds + shaded std; log-scale y for loss
Pareto front (acc vs params / FLOPs) Model-size tradeoff Highlight your model; annotate frontier
Stacked bar (latency breakdown) Where time goes Stable color order across runs
Roofline plot Compute vs memory bound Log-log axes; ridge line at peak FLOPS
Heatmap (cache miss / attention) 2D intensity viridis or cividis; never jet
Box / violin (per-seed variability) Multi-run distribution Overlay individual seeds as strip plot
Significance bars A / B / ablation comparison Optional in CS — only when stats are central to the claim
Ablation drop arrows How much each removed component costs Dashed line at the full model; one arrow and −Δ per variant (Pattern 13)
Cumulative ablation ramp Many component combinations Horizontal bars, "A + B + C" labels, one blue at rising alpha (Pattern 14)
Family-shaded comparison row Many baselines across 3 to 4 metrics Family hues, ours in blue at the right, one legend panel, meaningful floors (Pattern 15)
Color × hatch composition Two categorical factors in one stacked bar Color and tick labels name the method, hatch the second factor with its own legend (Pattern 16)
Radar with per-spoke scales Many benchmarks × few methods, venue expects radar Per-spoke ticks from one range rule; vertices marked (Pattern 17)
Event-annotated timeline Cumulative counts against dated events Stacked area, arrows naming each event (Pattern 18)
Concept plot Illustrate a mechanism, not report a measurement Idealized curves, labeled as illustrative (Pattern 19)

Statistical rigor (CS-specific)

CS reviewers care less about p-values than biomedicine reviewers, but more about run-to-run variability and error bars over seeds. Standard expectations:

  • Run each measurement ≥ 3 times (≥ 5 for ML, ≥ 10 for noisy systems benchmarks). Report mean and std or 95 % bootstrap CI.
  • Show individual data points (strip plot) when n is small (≤ 10) — averages alone hide bimodal failure modes.
  • State error type in the caption: Error bars: 95 % CI over 5 seeds or Shaded region: ±1 std over 10 runs.
  • For ML, also report median + min/max if you train fewer than 5 seeds.
  • For latency, report a percentile (median, p99, p99.9) — never just the mean. The mean of a heavy-tail distribution is a lie.

Don't fabricate error bars. If a measurement is from a single run, say so in the caption and prefer a bar / scatter without error indicators rather than zero-width error bars.

Choosing a library

Library Best for Notes
matplotlib Multi-panel, full control, anything that needs custom annotations Default for camera-ready CS figures
seaborn Statistical plots with automatic CI / bootstrap Built on matplotlib; styles compose; great for box / violin / regression
plotly Interactive HTML for project pages or supplementary Use kaleido to export static PDF
pgfplots / TikZ When you want LaTeX to compile the figure Best for diagrams that mix math and data; covered by tikz-figures

If a figure is reused across paper / poster / slides, render at multiple sizes from the same script — keep a single source-of-truth Python file under .writing/figures/src/.

Workflow inside this plugin

Confirmation gates — pause for the user before these three points:

  1. Before writing a generator script, confirm the target venue, the column width (single vs full), and the data source path. If any is unknown, ask rather than assume a default — guessing the venue silently produces a figure sized for the wrong template.
  2. Never invent measurements. If .writing/figures/data/<fig_id>.{csv,jsonl} is missing or the user hasn't supplied numbers, stop and ask for the data. Do not synthesize plausible-looking benchmark values, error bars, or trend lines to fill a plot — a polished figure built on fabricated data is worse than no figure. Placeholder values are acceptable only when the user explicitly asks for a layout mock-up and the figure is labeled as such.
  3. Before overwriting an existing .writing/figures/<fig_id>.pdf, confirm with the user (or note that you are about to replace it) so a prior camera-ready figure isn't clobbered silently.

Then proceed:

  1. Plan from the outline. Each figure the outline calls for in .writing/outline.md should have a one-line claim it supports (fig:cdf-latency → "our system has a 2.4× lower p99 than the baseline at 32 clients"). Check the plan against the house style's figure pattern first (_shared/core/house-style.md §9): the introduction gets one small single-column problem-only figure, the design section gets one full-width figure whose named stages are its subsection spine, and every later method figure reuses one running example. Result plots are supporting figures under that plan, and §8.18 sets their conventions: one published top-venue palette, one colour per entity across the whole deck, captions cut to one identifying sentence in plain words, small single-column plots for one research question stacked as (a) and (b) panels at about 1.5in each with the axes pinned to one rectangle, and the legend above the plot or in an empty corner, never on a curve. For a figure that doubles as the paper's results-storytelling figure (the headline result a reviewer sees first), check tikz-figures/references/figure-rhetoric.md: it covers the three-figure storytelling model, the Figure-1 performance-teaser paradigm and its avoid-condition (do not teaser a marginal gain, it shows the weakness unkindly), and the 30-second comprehension test. That reference is venue-agnostic across our figure skills. When these plots form the full figure deck of a paper, run one editor pass over the whole deck before submission: the per-deck narrative review in figure-rhetoric.md §5 (hook verdict, figure arc, misplaced panels, missing panels, kill list), which is distinct from the per-figure defect hunt in the Final Checklist below. When one figure is itself multi-panel (an ablation grid, a schematic paired with its result), figure-rhetoric.md §6 covers outlining the panels from the claim, drawing each with the matching skill, and reviewing the composed image as one artifact with verify_layout.py. Then pick the chart from references/chart-chooser.md by the question the figure answers, apply its scale remedy and orientation rules, and record the chart as the brief's family.
  2. Write a generator script in .writing/figures/src/<fig_id>.py. The script reads from .writing/figures/data/<fig_id>.{csv,jsonl} and writes .writing/figures/<fig_id>.pdf. This separation lets reviewers (and you) regenerate figures from raw data.
  3. Apply this skill's style at the top of the script — copy the bundled .mplstyle file or use the inline rcParams snippet from Quick Start.
  4. Verify before commit. Open the PDF in a viewer at 100 % zoom and at the column width it will appear at in the paper. If text is cramped at column width, the font sizes are wrong. For a mechanical pre-check, call verify(fig) from scripts/verify_layout.py at the end of the generator script: it flags text that collides with other text or a foreign axes spine and text clipped off the canvas, and, with crop_dir=, writes one PNG per panel so you (or a review agent) run the perceptual pass the geometry check cannot. Open each crop with the Read tool and check contrast, leader crossings, color-identity confusion, and legend binding.
  5. Caption discipline. The figure caption belongs in the .tex file, not on the figure itself. Repeat axes labels in the caption; spell out what error bars represent; state the sample size.

Common pitfalls (CS-specific)

  1. Y-axis in milliseconds for tail latency. A linear axis hides the long tail. Use log y for p99 / p99.9 plots.
  2. Bar chart starting at an arbitrary non-zero value. Misleading. Start at zero, at a named meaningful floor (chance level, baseline score), or mark a broken axis.
  3. One color per algorithm but identical line style. Fails in grayscale. Add markers + line styles.
  4. Legend over data. Use loc='upper left' and verify visually; or place outside with bbox_to_anchor.
  5. Default matplotlib font rendering. Matplotlib's default mathtext uses computer-modern italics; mixed with Arial body text it looks broken. Either set text.usetex: True (slow) or use mathtext.fontset: 'cm' only when you need real LaTeX math.
  6. tight_layout() clipping panel labels. Use constrained_layout=True instead.
  7. DPI confusion. For PDF, dpi only affects rasterized embedded objects. For PNG, set both figure.dpi (display) and savefig.dpi (output) — savefig.dpi: 600 for camera-ready.
  8. plt.show() in a script that runs in CI. Will hang. Use fig.savefig(...) only and skip plt.show() in scripted figure generation.
  9. Forgetting bbox_inches='tight'. Default save leaves margin around the figure. With bbox_inches='tight', the saved PDF crops to the actual content — what you want for \includegraphics.
  10. Reusing colors across figures. Pin one color to one method everywhere. Define a METHOD_COLORS dict in a shared .writing/figures/src/_palette.py.

Bundled resources

Path Purpose
_shared/core/house-style.md The plugin's default house style. §9 fixes what each structural figure shows and how floats land; §8.4 and §8.18 fix caption length, the one-palette-one-entity rule, panel stacking, and the no-\resizebox table rule. A project .claude/CLAUDE.md overrides it.
references/publication_guidelines.md Universal best practices: typography, layout, axes, accessibility, grayscale tests
references/venue_requirements.md Per-venue specs (IEEE, ACM, USENIX, NeurIPS, ICML, ICLR, arXiv) with exact widths, font sizes, and class-file gotchas
references/color_palettes.md Default figures4papers semantic palette with role rules and measured colorblind limits; strict alternatives (Okabe-Ito, Wong, Tol Bright/Muted), sequential (viridis family), diverging (RdBu, PuOr, BrBG); grayscale and colorblind pair checker
references/chart-chooser.md Question-to-chart table (systems patterns plus standard ML charts), scale remedies (broken axis / log / normalized), orientation and series-count rules, and the charts reviewers object to with their replacements
references/matplotlib_examples.md Nineteen runnable patterns — CDF, throughput, training curve, Pareto, ablation, stacked-bar breakdown, heatmap, roofline, box+strip, multi-panel composition, \columnwidth IEEE template, \textwidth ACM template, plus the figures4papers patterns: ablation drop arrows, cumulative ablation ramp, family-shaded comparison row, color × hatch composition, per-spoke radar, event timeline, concept plot
scripts/style_presets.py apply_publication_style(name), set_color_palette(name), configure_for_venue('ieee' / 'acm' / 'usenix' / 'neurips' / 'icml' / 'iclr' / 'arxiv'). Copy into a project to pin the rcParams.
scripts/figure_export.py save_publication_figure() (multi-format), save_for_venue() (per-venue defaults), check_figure_size() (warns when figsize doesn't match the venue's column width).
scripts/verify_layout.py verify(fig): geometric self-check (text/text + text/spine overlap, off-canvas text) plus per-panel crops for the perceptual pass. Call at the end of a generator script before committing the PDF.
assets/color_palettes.py Importable color constants (F4P, F4P_CYCLE, F4P_GREENS, F4P_REDS, Okabe-Ito, Tol) and apply_palette('f4p' / 'okabe_ito' / 'tol_bright' / …).
assets/publication.mplstyle Generic CS publication baseline. Use when no specific venue style applies.
assets/ieee.mplstyle IEEE Transactions / conferences (3.5 in single column, 8 pt body).
assets/acm.mplstyle ACM acmart sigconf / acmsmall (3.33 in single, 7.0 in two-column).
assets/neurips.mplstyle NeurIPS / ICML / ICLR (single column 5.5 in textwidth, 9 pt body).
assets/presentation.mplstyle Larger fonts and thicker lines for posters and slides.

Final Checklist

Frame this as defect-hunting, not confirmation. Before adding \includegraphics{...}, open the rendered PDF at the column width it will print at and actively look for what is wrong, rather than ticking boxes to confirm the figure is fine. Walk the items below, write a short defect list, and tag each finding high / medium / low. Fix every high and every medium you can fix cheaply; list low items but do not block on them. Findings are advisory: surface them to the user and let the user decide, never silently redraw a camera-ready figure or overwrite it.

high: misleads the reader or makes the figure look broken:

  • Non-PDF vector output where vector was expected, or a PNG below 300 DPI going to camera-ready.
  • A truncated / non-zero-baseline axis that exaggerates the gain, with neither a broken-axis indicator nor a named meaningful floor (chance level, baseline score).
  • Fabricated or unsupported data: invented error bars, a synthesized trend, zero-width error bars standing in for "single run".
  • Colorblind-unsafe palette or color-only encoding (jet / rainbow, a light red beside a green with no hatch, dash, or direct label, five or more series told apart by color alone); figure unreadable in grayscale.
  • A concept plot drawn from idealized curves but presented or captioned as measured data.
  • Key labels or tick labels illegible at print size, or text clipped.
  • A figsize whose scale factor to the printed width differs from the other figures in the paper, or leaves text below the minimums once LaTeX scales it.
  • An excluded or failed run (crashed, diverged, OOM'd, cold-start outlier) silently folded into a mean, bar, or error band, or silently dropped with no caption note. Excluded data is omitted or drawn with a distinct marker, never averaged in with the runs you kept.
  • The same quantity carrying two canonical values across figures, caption, and abstract (2.4× in one place, 2.6× in another for "the speedup"). One number per claim, everywhere. See references/publication_guidelines.md → Data Fidelity and Self-Consistency for both of these.

medium: reduces professionalism or comprehension:

  • Chartjunk: 3D effects, decorative gridlines, drop shadows, top / right spines left on.
  • Missing units on axis labels, or inconsistent SI / IEC prefixes.
  • Panel labels missing or inconsistent ((a) (b) (c), lowercase parenthesized).
  • Method colors not pinned consistently across every figure in the paper.
  • Redundant panels in a composite: re-run the multi-panel anti-redundancy checklist in §5.
  • Error-bar definition missing from the caption (or single-run not noted).

low: cosmetic, does not affect comprehension:

  • Minor alignment or spacing imperfections.
  • Palette or typography refinements.
  • Non-embedded fonts where the venue tolerates it (still prefer pdffonts foo.pdf showing "yes" under "emb").

This severity framing aligns with tikz-figures mode-C, which already runs the strongest form of defect-hunting (independent multi-lens adversarial review). For data plots there is no independent reviewer pass; the discipline is the same, but the final oracle is the user looking at the rendered PDF.