Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when generating publication figure code (matplotlib/seaborn): apply the exact journal column widths, the Okabe-Ito palette, and per-journal panel-label case the base does not use by default.
.claude/skills/scientific-figure-conventions/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 100% | 2 |
| Model | Lift | Δ tokens | Δ turns | Cases | Verified |
|---|---|---|---|---|---|
| gemini-3.6-flashbest | +73% | +63% | 0% | 22 | 54d ago |
| gemini-3.5-flash | pending re-run | — | |||
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-13 | ✗→✓ | ▲ Improved | — | — |
| case-16 | ✗→✓ | ▲ Improved | — | — |
| case-10 | ✗→✓ | ▲ Improved | — | — |
| case-09 | ✗→✓ | ▲ Improved | — | — |
| case-17 | ✗→✓ | ▲ Improved | — | — |
When you write matplotlib/seaborn code for a journal-submission figure, emit code that already encodes the journal's house style: the Okabe-Ito categorical palette, the exact per-journal column width in inches, the per-journal panel-label case, perceptually-uniform colormaps, vector export, and sans-serif fonts. Apply this whenever the task names a journal (Nature / Science / Cell) or says "publication", "manuscript", "submission", or "journal figure". Do not substitute library defaults.
For every set of categorical series (lines, bars, groups, hues), assign colors from this exact 8-value list, in order, cycling if there are more than 8 series:
#E69F00 #56B4E9 #009E73 #F0E442 #0072B2 #D55E00 #CC79A7 #000000(orange, sky blue, bluish green, yellow, blue, vermillion, reddish purple, black.) Never fall back to matplotlib's default cycle (C0/C1/C2 = blue/orange/green), tab10, or seaborn's colorblind theme. Set it explicitly per-artist (color=okabe_ito[i]) or globally (plt.rcParams['axes.prop_cycle'] = plt.cycler(color=okabe_ito)).
Set the figsize width to the target journal's column width. Height is free (choose by aspect); width is fixed:
| Journal | Single column | Double column | |---|---|---| | Nature | 89 mm = 3.50 in | 183 mm = 7.20 in | | Science | 55 mm = 2.17 in | 175 mm = 6.89 in | | Cell | 85 mm = 3.35 in | 178 mm = 7.01 in |
Never use the matplotlib default (6.4 in) or a round number like 6, 8, or 10. A "single-column" or unspecified-width request defaults to that journal's single-column value.
Multi-panel figures get bold per-panel letters. The case is journal-specific:
a, b, c, … (bold)A, B, C, … (bold)Render with fontweight='bold' (or weight='bold'), typically via ax.text(-0.15, 1.05, 'a', transform=ax.transAxes, fontweight='bold').
viridis or cividis. (plasma is also acceptableperceptually-uniform.) Never jet or rainbow.
RdBu_ror PuOr, centered at 0 (center=0 for seaborn, or symmetric vmin=-vmax for matplotlib).
Sans-serif, specifically Arial or Helvetica. Sizes tuned for final print size: axis labels 7–9 pt, tick labels 6–8 pt, panel labels 8–12 pt bold. Set via rcParams['font.family'] = 'sans-serif' and rcParams['font.sans-serif'] = ['Arial', 'Helvetica'].
Remove the top and right spines (ax.spines['top'].set_visible(False) and same for 'right', or sns.despine()). Keep left and bottom.
Show error bars and state their meaning (SD, SEM, or 95% CI) in the caption; report sample size n; mark significance with */**/***; overlay individual data points where feasible rather than showing summary statistics alone.
python# BEFORE: matplotlib default cycle (C0 blue, C1 orange, C2 green) ax.plot(x, a, label='Control') ax.plot(x, b, label='Treated') # AFTER: Okabe-Ito, in order okabe_ito = ['#E69F00', '#56B4E9', '#009E73', '#F0E442', '#0072B2', '#D55E00', '#CC79A7', '#000000'] ax.plot(x, a, color=okabe_ito[0], label='Control') # #E69F00 ax.plot(x, b, color=okabe_ito[1], label='Treated') # #56B4E9
python# BEFORE: round, arbitrary size fig, ax = plt.subplots(figsize=(8, 5)) # AFTER: Nature single column = 89 mm = 3.50 in fig, ax = plt.subplots(figsize=(3.5, 2.5))
python# BEFORE: uppercase used for everything ax1.text(-0.15, 1.05, 'A', transform=ax1.transAxes, fontweight='bold') # wrong for Nature # AFTER (Nature → lowercase, bold) ax1.text(-0.15, 1.05, 'a', transform=ax1.transAxes, fontweight='bold') ax2.text(-0.15, 1.05, 'b', transform=ax2.transAxes, fontweight='bold') # AFTER (Cell or Science → uppercase, bold) ax1.text(-0.15, 1.05, 'A', transform=ax1.transAxes, fontweight='bold')
python# BEFORE (sequential): jet im = ax.imshow(M, cmap='jet') # AFTER (sequential): perceptually uniform im = ax.imshow(M, cmap='viridis') fig.colorbar(im, ax=ax, label='Expression (AU)') # BEFORE (diverging): default, not centered sns.heatmap(corr, cmap='coolwarm') # AFTER (diverging): RdBu_r centered at 0 sns.heatmap(corr, cmap='RdBu_r', center=0)
python# BEFORE: JPEG at low DPI fig.savefig('figure1.jpg', dpi=150) # AFTER: vector for a plot fig.savefig('figure1.pdf') # or .eps # AFTER: raster image panel fig.savefig('micrograph.tiff', dpi=300) # TIFF/PNG, ≥300 DPI, never JPEG
python# BEFORE: default DejaVu Sans, all four spines # (no font set; box stays closed) # AFTER import matplotlib as mpl mpl.rcParams['font.family'] = 'sans-serif' mpl.rcParams['font.sans-serif'] = ['Arial', 'Helvetica'] mpl.rcParams['axes.labelsize'] = 9 ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False)
python# BEFORE: bare bars, no uncertainty ax.bar(groups, means) # AFTER: error bars + individual points + significance ax.bar(groups, means, yerr=sems, capsize=3, color=okabe_ito[:len(groups)]) ax.scatter(jittered_x, individual_points, color='black', alpha=0.3, s=8) ax.text(1.5, ymax * 1.05, '***', ha='center') # state "mean ± SEM, n=…" in caption
encoding (line style or marker) so series stay distinguishable beyond color.
89 mm (3.50 in); if it says "full page" / "full width", use that journal's double-column value.
−1..1, log2 fold-changes) → diverging centered at 0; one-directional magnitude → sequential.
axes mislead).
(markers/line styles) for line plots.
(scale=3 ≈ 300 DPI for raster export).
cmap='jet' or 'rainbow'. Always use viridis/cividis (sequential) orRdBu_r/PuOr centered at 0 (diverging).
.jpg/.jpeg. Always PDF/EPS for plots, TIFF/PNG (≥300 DPI) forimages.
Science/Cell, both bold.
figsize=(6.4, …) or a round 8/10. Always the journal's exact column width ininches.
figsize like (8, 6) or (10, 6) instead of the journal column width.jet/coolwarm/rainbow for heatmaps; forgets to center diverging maps at 0..png or .jpg for a line plot instead of vector PDF/EPS.A, B, C panel labels for Nature (Nature wants lowercase).figsize width = journal column width (Nature 3.50/7.20, Science 2.17/6.89, Cell 3.35/7.01 in)| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-13 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +73 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.5-flash | verified | 7/9/2026 | +38% |
Other measured skills in the registry, with their headline benchmark lift.