
Academic Plotting
- 493 installs
- 11.2k repo stars
- Updated June 16, 2026
- orchestra-research/ai-research-skills
Academic Plotting is a Claude skill that generates publication-ready machine-learning paper figures using matplotlib and seaborn defaults, palettes, and layout patterns for developers who need polished charts instead of
About
Academic Plotting is a pattern library skill from orchestra-research/ai-research-skills for producing polished ML paper figures with matplotlib and seaborn. The skill ships serif publication defaults—Times New Roman, DejaVu Serif, tuned axis and legend sizes—and reusable layout recipes for experiment plots researchers reuse across papers. Developers invoke it when notebook charts look generic or fail venue formatting expectations and they want consistent typography, tick formatters, and color palettes without re-deriving rcParams each project. The workflow centers on Python imports, rcParams updates, and seaborn integration to export camera-ready figures suitable for arXiv, conference submissions, or internal research memos.
- Complete pattern library for polished, distinctive ML paper figures
- Publication rcParams block: 300 DPI, serif fonts, subtle grid, spine styling
- Default Ocean Dusk color palette with named teal and companion hues
- Seaborn and matplotlib tick/legend conventions tuned for print
- Copy-paste setup imports for numpy, mpl, and FuncFormatter formatters
Academic Plotting by the numbers
- 493 all-time installs (skills.sh)
- +49 installs in the week ending Jul 26, 2026 (Skillselion tracking)
- Ranked #442 of 2,066 Data Science & ML skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/orchestra-research/ai-research-skills --skill academic-plottingAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 493 |
|---|---|
| repo stars | ★ 11.2k |
| Security audit | 3 / 3 scanners passed |
| Last updated | June 16, 2026 |
| Repository | orchestra-research/ai-research-skills ↗ |
How do you style matplotlib figures for ML papers?
Generate publication-ready ML paper figures with matplotlib/seaborn defaults, palettes, and layout patterns instead of generic chart styling.
Who is it for?
ML engineers and researchers exporting experiment charts who need consistent, venue-quality matplotlib styling without hand-tuning rcParams every figure.
Skip if: Interactive dashboard visualization, D3 or Plotly web charts, or automated figure generation pipelines without Python notebooks.
When should I use this skill?
A developer asks for publication-ready plots, ML paper figures, matplotlib rcParams defaults, or seaborn styling for research output.
What you get
Publication-ready matplotlib/seaborn figures with serif fonts, tuned axes, and conference-grade layouts.
- Publication-ready figure code
- Configured rcParams block
- Styled experiment plots
By the numbers
- Base font size set to 10pt with axis titles at 11pt
- Tick and legend labels tuned to 8.5pt
Files
Academic Plotting for ML Papers
Generate publication-quality figures for ML/AI conference papers. Two distinct workflows:
1. Diagram figures (architecture, system design, workflows, pipelines) — AI image generation via Gemini 2. Data figures (line charts, bar charts, scatter plots, heatmaps, ablations) — matplotlib/seaborn
When to Use Which Workflow
| Figure Type | Tool | Why |
|---|---|---|
| Architecture / system diagram | Gemini (Workflow 1) | Complex spatial layouts with boxes, arrows, labels |
| Workflow / pipeline / lifecycle | Gemini (Workflow 1) | Multi-step processes with connections |
| Bar chart, line plot, scatter | matplotlib (Workflow 2) | Precise numerical data, reproducible |
| Heatmap, confusion matrix | matplotlib/seaborn (Workflow 2) | Structured grid data |
| Ablation table as chart | matplotlib (Workflow 2) | Grouped bars or line comparisons |
| Pie / donut chart | matplotlib (Workflow 2) | Proportional data (use sparingly in ML papers) |
| Training curves | matplotlib (Workflow 2) | Loss/accuracy over steps/epochs |
Rule of thumb: If the figure has numerical axes, use matplotlib. If the figure has boxes and arrows, use Gemini.
---
Step 0: Context Analysis & Extraction
The user will typically provide one of these inputs — not a ready-made specification:
| Input Type | Example | What to Extract |
|---|---|---|
| Full paper / section draft | "Here's our method section..." | System components, their relationships, data flow |
| Description paragraph | "Our system has three layers that..." | Key entities, hierarchy, connections |
| Raw results / data table | "MMLU: 85.2, HumanEval: 72.1..." | Metrics, methods, comparison structure |
| CSV / JSON data | Experiment log files | Variables, trends, grouping dimensions |
| Vague request | "Make a figure for the overview" | Read surrounding paper context to infer content |
Extraction Workflow
For diagrams (research context → architecture figure):
1. Read the provided context — paper section, abstract, or description paragraph 2. Identify visual entities — What are the main components/modules/stages?
- Look for: nouns that represent system parts, named modules, layers, stages
- Count them: if >8 top-level entities, consider grouping into sections
3. Identify relationships — How do components connect?
- Look for: verbs describing data flow ("sends to", "queries", "feeds into")
- Classify: data flow (solid arrow), control flow (gray), error path (dashed red)
4. Determine layout pattern:
- Sequential pipeline → left-to-right flow
- Layered architecture → horizontal bands stacked vertically
- Hub-and-spoke → central node with radiating connections
- Hierarchical → top-down tree
5. Assign colors — One accent color per logical group/layer 6. Write every label exactly — Extract exact terminology from the paper text
For data charts (results → figure):
1. Read the provided data — table, paragraph with numbers, CSV, or JSON 2. Identify dimensions:
- What is being compared? (methods, models, configurations) → categorical axis
- What is the metric? (accuracy, loss, latency, F1) → value axis
- Is there a time/step dimension? → line plot
- Are there multiple metrics? → multi-panel or grouped bars
3. Choose chart type automatically using this priority:
- Has a step/time axis → line plot
- Comparing N methods on M benchmarks → grouped bar chart
- Single ranking → horizontal bar (leaderboard)
- Correlation between two continuous variables → scatter plot
- Square matrix of values → heatmap
- Proportional breakdown → stacked bar (avoid pie charts)
4. Determine figure sizing — Single column vs full width based on data density 5. Highlight "our method" — Identify which entry is the paper's contribution and give it a distinct color
Auto-Detection Examples
Context → Diagram: "Our system has a Planner, Executor, and Verifier. Planner sends plans to Executor, Executor returns results to Verifier, Verifier feeds back to Planner on failure." → 3 entities, cycle layout, dashed feedback arrow → Workflow 1 (Gemini)
Data → Chart: "GPT-4: MMLU 86.4, HumanEval 67.0. Ours: 88.1, 71.2. Llama-3: 79.3, 62.1." → 3 methods × 2 benchmarks → Workflow 2 (grouped bar), highlight "Ours" in coral
---
Workflow 1: Architecture & System Diagrams (AI Image Generation)
Use Gemini 3 Pro Image Preview to generate diagrams. Choose a visual style first — this is the single biggest factor in whether the figure looks professional or generic.
Visual Styles
Pick one style per paper (all figures should be consistent):
Style A: "Sketch / 简笔画" (Hand-Drawn)
Warm, approachable, memorable. Ideal for overview figures and system introductions. Looks like a whiteboard sketch refined by a designer.
VISUAL STYLE — HAND-DRAWN SKETCH:
- Slightly irregular, hand-drawn line quality — lines wobble gently, not perfectly straight
- Rounded, soft shapes with visible pen strokes (like drawn with a thick felt-tip marker)
- Warm off-white background (#FAFAF7), NOT pure white
- Fill colors are soft watercolor-like washes: muted blue (#D6E4F0), soft peach (#F5DEB3),
light sage (#D4E6D4), pale lavender (#E6DFF0)
- Borders are dark charcoal (#2C2C2C) with 2-3px line weight, slightly uneven
- Arrows are hand-drawn with slight curves, ending in simple open arrowheads (not filled triangles)
- Text uses a rounded sans-serif font (like Comic Neue or Architects Daughter feel)
- Small doodle-style icons inside boxes: a tiny gear ⚙ for processing, a lightbulb 💡 for ideas,
a magnifying glass 🔍 for search — rendered as simple line drawings, NOT emoji
- Overall feel: a carefully drawn whiteboard diagram, clean but with personality
- NO clip art, NO stock icons, NO photorealistic elementsStyle B: "Modern Minimal" (Clean & Bold)
Confident, authoritative. Best for method figures where precision matters.
VISUAL STYLE — MODERN MINIMAL:
- Ultra-clean geometric shapes with crisp edges
- Bold color blocks as backgrounds for sections — NOT just accent bars, but full section fills
using desaturated tones: slate blue (#E8EDF2), warm sand (#F5F0E8), cool mint (#E8F2EE)
- Component boxes have ROUNDED CORNERS (12px radius), NO visible border — they float on
the section background using subtle shadow (1px, 4px blur, rgba(0,0,0,0.06))
- ONE accent color per section used sparingly on key elements: Deep blue (#2563EB),
Emerald (#059669), Amber (#D97706), Rose (#E11D48)
- Arrows are thin (1.5px), dark gray (#6B7280), with small filled circle at source
and clean arrowhead at target — NOT thick colored arrows
- Typography: Inter or system sans-serif, title 600 weight, body 400 weight
- Labels INSIDE boxes, not beside them
- Generous whitespace — at least 24px between elements
- NO decorative elements, NO icons — let the structure speakStyle C: "Illustrated Technical" (Icon-Rich)
Engaging, explanatory. Good for tutorial-style papers and figures that need to be self-explanatory.
VISUAL STYLE — ILLUSTRATED TECHNICAL:
- Each major component has a small MEANINGFUL ICON drawn in a consistent line-art style
(single color, 2px stroke, ~24x24px): brain icon for reasoning, database cylinder for storage,
arrow-loop for iteration, network nodes for communication
- Components sit inside soft rounded rectangles with a LEFT COLOR STRIP (4px wide)
- Background is pure white, but each logical group has a very faint colored region behind it
(#F8FAFC for blue group, #FFF8F0 for orange group)
- Connections use CURVED bezier paths (not straight lines), colored by SOURCE component
- Key data flows are THICKER (3px) than secondary flows (1px, dashed)
- Small annotation badges on arrows: "×N" for repeated operations, "optional" in italics
- Title labels are ABOVE each section in small caps, letter-spaced
- Overall: like a well-designed API documentation diagramStyle D: "Accent Bar" (Classic Academic)
The default academic style. Safe for any venue, works well in grayscale.
VISUAL STYLE — CLASSIC ACCENT BAR:
- Horizontal section bands stacked vertically, pale gray (#F7F7F5) fill
- Thick colored LEFT ACCENT BAR (8px) distinguishes each section
- Content boxes: white fill, thin #DDD border, 4px rounded corners
- Section palette: Blue #4A90D9, Teal #5BA58B, Amber #D4A252, Slate #7B8794
- Sans-serif typography (Helvetica/Arial), bold titles, regular body
- Colored arrows match their SOURCE section
- Clean, flat, zero decorationCurated Color Palettes
"Ocean Dusk" (professional, calming — default recommendation): #264653 deep teal, #2A9D8F teal, #E9C46A gold, #F4A261 sandy orange, #E76F51 burnt coral
"Ink & Wash" (for 简笔画 style): #2C2C2C charcoal ink, #D6E4F0 washed blue, #F5DEB3 washed wheat, #D4E6D4 washed sage, #E6DFF0 washed lavender
"Nord" (for modern minimal): #2E3440 polar night, #5E81AC frost blue, #A3BE8C aurora green, #EBCB8B aurora yellow, #BF616A aurora red
"Okabe-Ito" (universal colorblind-safe, required for data charts): #E69F00 orange, #56B4E9 sky blue, #009E73 green, #F0E442 yellow, #0072B2 blue, #D55E00 vermillion, #CC79A7 pink
Checklist
- [ ] Extract from context: Read paper/description, identify entities and relationships
- [ ] Choose visual style (A/B/C/D) — match the paper's tone and venue
- [ ] Choose color palette — or use one consistent with existing paper figures
- [ ] Obtain Gemini API key (
GEMINI_API_KEYenv var) - [ ] Write a detailed prompt: style block + layout + connections + constraints
- [ ] Generate script at
figures/gen_fig_<name>.py, run for 3 attempts - [ ] Review, select best, save as
figures/fig_<name>.png
Prompt Structure (6 Sections)
Every Gemini prompt must include these sections in order:
1. FRAMING (5 lines): "Create a [STYLE_NAME]-style technical diagram for a
[VENUE] paper. The diagram should feel [ADJECTIVES]..."
2. VISUAL STYLE (20-30 lines): Copy the full style block from above (A/B/C/D).
This is the most important section — it determines the entire visual character.
3. COLOR PALETTE (10 lines): Exact hex codes for every color used.
4. LAYOUT (50-150 lines): Every component, box, section — exact text, spatial
arrangement, and grouping. Be exhaustively specific.
5. CONNECTIONS (30-80 lines): Every arrow individually — source, target, style,
label, routing direction.
6. CONSTRAINTS (10 lines): What NOT to include. Adapt per style — e.g., sketch
style allows slight irregularity but still no clip art.Generation Script Template
#!/usr/bin/env python3
"""Generate [FIGURE_NAME] diagram using Gemini image generation."""
import os, sys, time
from google import genai
API_KEY = os.environ.get("GEMINI_API_KEY")
if not API_KEY:
print("ERROR: Set GEMINI_API_KEY environment variable.")
print(" Get a key at: https://aistudio.google.com/apikey")
sys.exit(1)
MODEL = "gemini-3-pro-image-preview"
OUTPUT_DIR = os.path.dirname(os.path.abspath(__file__))
client = genai.Client(api_key=API_KEY)
PROMPT = """
[PASTE YOUR 6-SECTION PROMPT HERE]
"""
def generate_image(prompt_text, attempt_num):
print(f"\n{'='*60}\nAttempt {attempt_num}\n{'='*60}")
try:
response = client.models.generate_content(
model=MODEL,
contents=prompt_text,
config=genai.types.GenerateContentConfig(
response_modalities=["IMAGE", "TEXT"],
),
)
output_path = os.path.join(OUTPUT_DIR, f"fig_NAME_attempt{attempt_num}.png")
for part in response.candidates[0].content.parts:
if part.inline_data:
with open(output_path, "wb") as f:
f.write(part.inline_data.data)
print(f"Saved: {output_path} ({os.path.getsize(output_path):,} bytes)")
return output_path
elif part.text:
print(f"Text: {part.text[:300]}")
print("WARNING: No image in response")
return None
except Exception as e:
print(f"ERROR: {e}")
return None
def main():
results = []
for i in range(1, 4):
if i > 1:
time.sleep(2)
path = generate_image(PROMPT, i)
if path:
results.append(path)
if not results:
print("All attempts failed!")
sys.exit(1)
print(f"\nGenerated {len(results)} attempts. Review and pick the best.")
if __name__ == "__main__":
main()Key Rules
- Always 3 attempts — quality varies significantly between runs
- Style block is mandatory — without it, Gemini defaults to generic corporate look
- Never hardcode API keys — use
os.environ.get("GEMINI_API_KEY") - Save generation scripts — reproducibility is critical
- Specify every label exactly — Gemini may misspell or rearrange text
Full prompt examples per style: See references/diagram-generation.md
---
Workflow 2: Data-Driven Charts (matplotlib/seaborn)
For any figure with numerical data, axes, or quantitative comparisons.
Checklist
- [ ] Extract from context: Parse results/data, identify methods, metrics, and comparison structure
- [ ] Auto-select chart type based on data dimensions (see decision guide below)
- [ ] Prepare data (CSV, dict, or inline arrays)
- [ ] Apply publication styling (fonts, colors, sizes)
- [ ] Highlight "our method" with a distinct color
- [ ] Export as both PDF (vector) and PNG (300 DPI)
- [ ] Verify LaTeX font compatibility
- [ ] Save script at
figures/gen_fig_<name>.py
Chart Type Decision Guide
| Data Pattern | Best Chart | Notes |
|---|---|---|
| Trend over time/steps | Line plot | Training curves, scaling laws |
| Comparing categories | Grouped bar chart | Model comparisons, ablations |
| Distribution | Violin / box plot | Score distributions across methods |
| Correlation | Scatter plot | Embedding analysis, metric correlation |
| Grid of values | Heatmap | Attention maps, confusion matrices |
| Part of whole | Stacked bar (not pie) | Prefer stacked bar over pie in ML papers |
| Many methods, one metric | Horizontal bar | Leaderboard-style comparisons |
Publication Styling Template
import matplotlib.pyplot as plt
import numpy as np
# --- Publication defaults (polished, not generic) ---
plt.rcParams.update({
"font.family": "serif", "font.serif": ["Times New Roman", "DejaVu Serif"],
"font.size": 10, "axes.titlesize": 11, "axes.titleweight": "bold",
"axes.labelsize": 10, "legend.fontsize": 8.5, "legend.frameon": False,
"figure.dpi": 300, "savefig.dpi": 300, "savefig.bbox": "tight",
"axes.spines.top": False, "axes.spines.right": False,
"axes.grid": True, "grid.alpha": 0.15, "grid.linestyle": "-",
"lines.linewidth": 1.8, "lines.markersize": 5,
})
# --- "Ocean Dusk" palette (professional, distinctive, colorblind-safe) ---
COLORS = ["#264653", "#2A9D8F", "#E9C46A", "#F4A261", "#E76F51",
"#0072B2", "#56B4E9", "#8C8C8C"]
OUR_COLOR = "#E76F51" # coral — warm, stands out
BASELINE_COLOR = "#B0BEC5" # cool gray — recedes
FIG_SINGLE, FIG_FULL = (3.25, 2.5), (6.75, 2.8)Common Chart Patterns
Line plot (training curves) — with markers and confidence bands:
fig, ax = plt.subplots(figsize=FIG_SINGLE)
markers = ["o", "s", "^", "D", "v"]
for i, (method, (mean, std)) in enumerate(results.items()):
color = OUR_COLOR if method == "Ours" else COLORS[i]
ax.plot(steps, mean, label=method, color=color,
marker=markers[i % 5], markevery=max(1, len(steps)//8),
markersize=4, zorder=3)
ax.fill_between(steps, mean - std, mean + std, color=color, alpha=0.12)
ax.set_xlabel("Training Steps")
ax.set_ylabel("Accuracy (%)")
ax.legend(loc="lower right")
fig.savefig("figures/fig_training.pdf")
fig.savefig("figures/fig_training.png", dpi=300)Grouped bar chart (ablation) — with value labels:
fig, ax = plt.subplots(figsize=FIG_FULL)
x = np.arange(len(categories))
n = len(methods)
width = 0.7 / n
for i, (method, scores) in enumerate(methods.items()):
color = OUR_COLOR if method == "Ours" else COLORS[i]
offset = (i - n / 2 + 0.5) * width
bars = ax.bar(x + offset, scores, width * 0.9, label=method, color=color,
edgecolor="white", linewidth=0.5)
for bar, s in zip(bars, scores):
ax.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.3,
f"{s:.1f}", ha="center", va="bottom", fontsize=7, color="#444")
ax.set_xticks(x)
ax.set_xticklabels(categories)
ax.set_ylabel("Score")
ax.legend(ncol=min(n, 4))
fig.savefig("figures/fig_ablation.pdf")Heatmap — with diverging colormap and clean borders:
import seaborn as sns
fig, ax = plt.subplots(figsize=(4, 3.5))
sns.heatmap(matrix, annot=True, fmt=".2f", cmap="YlOrRd", ax=ax,
cbar_kws={"shrink": 0.75, "aspect": 20},
linewidths=1.5, linecolor="white",
annot_kws={"size": 8, "weight": "medium"})
ax.set_xlabel("Predicted")
ax.set_ylabel("Actual")
fig.savefig("figures/fig_confusion.pdf")Horizontal bar (leaderboard) — with "our method" highlight:
fig, ax = plt.subplots(figsize=FIG_SINGLE)
y_pos = np.arange(len(models))
colors = [BASELINE_COLOR] * len(models)
colors[our_idx] = OUR_COLOR
bars = ax.barh(y_pos, scores, color=colors, height=0.55,
edgecolor="white", linewidth=0.5)
ax.set_yticks(y_pos)
ax.set_yticklabels(models)
ax.set_xlabel("Accuracy (%)")
ax.invert_yaxis()
for bar, s in zip(bars, scores):
ax.text(bar.get_width() + 0.3, bar.get_y() + bar.get_height()/2,
f"{s:.1f}", va="center", fontsize=8, color="#444")
fig.savefig("figures/fig_leaderboard.pdf")Full pattern library (scaling laws, violin plots, multi-panel, radar): See references/data-visualization.md
---
Publication Style Quick Reference
| Venue | Single Col | Full Width | Font |
|---|---|---|---|
| NeurIPS | 5.5 in | 5.5 in | Times |
| ICML | 3.25 in | 6.75 in | Times |
| ICLR | 5.5 in | 5.5 in | Times |
| ACL | 3.3 in | 6.8 in | Times |
| AAAI | 3.3 in | 7.0 in | Times |
Always export PDF for vector quality. PNG only for AI-generated diagrams.
Venue-specific details, LaTeX integration, font matching, accessibility checklist: See references/style-guide.md
---
Common Issues
| Issue | Solution |
|---|---|
| Fonts look wrong in LaTeX | Export PDF, set text.usetex=True, or use font.family=serif |
| Figure too large for column | Check venue width limits, use figsize in inches |
| Colors indistinguishable in print | Use colorblind-safe palette + different line styles/markers |
| Gemini misspells labels | Spell out every label exactly in prompt, add "SPELL EXACTLY" constraint |
| Gemini ignores style | Add more negative constraints, be more specific about hex colors |
| Blurry figures in PDF | Export as PDF (vector), not PNG; or use 300+ DPI for PNG |
| Legend overlaps data | Use bbox_to_anchor, loc="upper left", or external legend |
| Too many tick labels | Use ax.xaxis.set_major_locator(MaxNLocator(5)) |
When to Use vs Alternatives
| Need | This Skill | Alternative |
|---|---|---|
| Architecture diagrams | Gemini generation | TikZ (manual), draw.io (interactive), Mermaid (simple) |
| Data charts | matplotlib/seaborn | Plotly (interactive), R/ggplot2 (statistics-heavy) |
| Full paper writing | Use with ml-paper-writing | — |
| Poster figures | Larger fonts, wider | latex-posters skill |
| Presentation figures | Larger text, fewer details | PowerPoint/Keynote export |
---
Quick Reference: File Naming Convention
figures/
├── gen_fig_<name>.py # Generation script (always save for reproducibility)
├── fig_<name>.pdf # Final vector output (for LaTeX)
├── fig_<name>.png # Raster output (300 DPI, for AI-generated or fallback)
└── fig_<name>_attempt*.png # Gemini attempts (keep for comparison)Data Visualization Patterns for ML Papers
Complete pattern library for generating polished, distinctive figures.
Setup and Imports
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import seaborn as sns
from matplotlib.ticker import MaxNLocator, FuncFormatter
# --- Publication defaults (polished, not generic) ---
plt.rcParams.update({
"font.family": "serif",
"font.serif": ["Times New Roman", "DejaVu Serif"],
"font.size": 10,
"axes.titlesize": 11,
"axes.titleweight": "bold",
"axes.labelsize": 10,
"axes.labelweight": "medium",
"xtick.labelsize": 8.5,
"ytick.labelsize": 8.5,
"legend.fontsize": 8.5,
"legend.frameon": False,
"figure.dpi": 300,
"savefig.dpi": 300,
"savefig.bbox": "tight",
"savefig.pad_inches": 0.08,
"axes.spines.top": False,
"axes.spines.right": False,
"axes.linewidth": 0.8,
"xtick.major.width": 0.8,
"ytick.major.width": 0.8,
"axes.grid": True,
"grid.alpha": 0.15, # Very subtle — guides the eye without competing
"grid.linewidth": 0.6,
"grid.linestyle": "-", # Solid but faint, not dashed (less visual noise)
"lines.linewidth": 1.8,
"lines.markersize": 5,
"patch.edgecolor": "white", # White borders between bars (cleaner look)
"patch.linewidth": 0.5,
})Color Palettes
"Ocean Dusk" (default — professional, distinctive)
COLORS = {
"teal": "#264653", # deep, authoritative
"cyan": "#2A9D8F", # fresh, modern
"gold": "#E9C46A", # warm accent
"orange": "#F4A261", # energetic
"coral": "#E76F51", # standout (use for "our method")
"blue": "#0072B2", # Okabe-Ito accessible blue
"sky": "#56B4E9", # Okabe-Ito accessible sky
"gray": "#8C8C8C", # neutral baseline
}
COLOR_LIST = list(COLORS.values())
# Semantic colors for highlighting
OUR_COLOR = "#E76F51" # coral — warm, draws attention
BASELINE_COLOR = "#B0BEC5" # cool gray — recedes
BEST_BASELINE = "#264653" # deep teal — strongest competitor"Okabe-Ito" (maximum colorblind safety)
OKABE_ITO = ["#E69F00", "#56B4E9", "#009E73", "#F0E442",
"#0072B2", "#D55E00", "#CC79A7", "#000000"]Sequential Palettes (for heatmaps)
# Warm sequential (more interesting than plain Blues)
cmap_warm = sns.color_palette("YlOrRd", as_cmap=True)
# Cool sequential (clean, professional)
cmap_cool = sns.light_palette("#264653", as_cmap=True)
# Diverging (for correlation/difference, centered at 0)
cmap_div = sns.color_palette("RdBu_r", as_cmap=True)
# Perceptually uniform (for continuous scientific data)
cmap_viridis = plt.cm.viridisMaking Charts Visually Distinctive
Common mistakes that make charts look "boring" and their fixes:
| Boring Default | Better Version |
|---|---|
| Black lines, no markers | Colored lines + distinct markers per method |
| No shading around lines | Confidence bands with fill_between(alpha=0.12) |
| Generic blue bars | "Ocean Dusk" palette + white edge between bars |
| All same color baselines | Gray baselines + coral highlight for "ours" |
| Dashed grid lines | Very faint solid grid (alpha=0.15) |
| Default tight spacing | pad_inches=0.08, generous axis margins |
| No value labels on bars | Small value text above each bar |
| Box legend with frame | Frameless legend, positioned inside plot area |
Figure Sizes by Venue
# NeurIPS / ICLR (single column, 5.5in text width)
FIG_NEURIPS_SINGLE = (5.5, 3.5)
FIG_NEURIPS_HALF = (2.65, 2.5)
# ICML (two column, 6.75in text width)
FIG_ICML_SINGLE = (3.25, 2.5)
FIG_ICML_FULL = (6.75, 2.5)
# ACL (two column, 6.8in text width)
FIG_ACL_SINGLE = (3.3, 2.5)
FIG_ACL_FULL = (6.8, 3.0)
# General safe default
FIG_DEFAULT = (5, 3.5)Chart Type 1: Training Curves (Line Plot)
The most common figure in ML papers. Shows loss/accuracy over training steps.
def plot_training_curves(data, metric="Loss", save_path="figures/fig_training.pdf"):
"""
data: dict of {method_name: (steps_array, values_array)}
"""
fig, ax = plt.subplots(figsize=FIG_ICML_SINGLE)
markers = ["o", "s", "^", "D", "v", "P"]
for i, (method, (steps, values)) in enumerate(data.items()):
ax.plot(steps, values,
label=method,
color=COLOR_LIST[i],
linewidth=1.5,
marker=markers[i % len(markers)],
markevery=max(1, len(steps) // 8),
markersize=4)
ax.set_xlabel("Training Steps")
ax.set_ylabel(metric)
ax.legend(frameon=False, loc="best")
# Log scale for loss (common)
if "loss" in metric.lower():
ax.set_yscale("log")
fig.savefig(save_path)
fig.savefig(save_path.replace(".pdf", ".png"), dpi=300)
plt.close(fig)Shaded Confidence Intervals
ax.plot(steps, mean_values, color=COLOR_LIST[0], linewidth=1.5, label="Our Method")
ax.fill_between(steps, mean_values - std_values, mean_values + std_values,
color=COLOR_LIST[0], alpha=0.2)Chart Type 2: Grouped Bar Chart (Ablation / Comparison)
def plot_ablation(categories, methods_data, ylabel="Accuracy (%)",
save_path="figures/fig_ablation.pdf"):
"""
categories: list of benchmark names
methods_data: dict of {method_name: list_of_scores}
"""
fig, ax = plt.subplots(figsize=FIG_ICML_FULL)
n_methods = len(methods_data)
n_cats = len(categories)
width = 0.8 / n_methods
x = np.arange(n_cats)
for i, (method, scores) in enumerate(methods_data.items()):
offset = (i - n_methods / 2 + 0.5) * width
bars = ax.bar(x + offset, scores, width * 0.9,
label=method, color=COLOR_LIST[i])
# Value labels on top
for bar, score in zip(bars, scores):
ax.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.3,
f"{score:.1f}", ha="center", va="bottom", fontsize=7)
ax.set_xticks(x)
ax.set_xticklabels(categories, rotation=0)
ax.set_ylabel(ylabel)
ax.legend(frameon=False, ncol=min(n_methods, 4), loc="upper right")
ax.set_ylim(bottom=0)
fig.savefig(save_path)
plt.close(fig)Chart Type 3: Heatmap (Attention / Confusion Matrix)
def plot_heatmap(matrix, xlabels, ylabels, title="",
save_path="figures/fig_heatmap.pdf", fmt=".2f", cmap="Blues"):
"""
matrix: 2D numpy array
"""
fig, ax = plt.subplots(figsize=(max(4, len(xlabels) * 0.6), max(3, len(ylabels) * 0.5)))
sns.heatmap(matrix, annot=True, fmt=fmt, cmap=cmap, ax=ax,
xticklabels=xlabels, yticklabels=ylabels,
cbar_kws={"shrink": 0.8}, linewidths=0.5, linecolor="white",
annot_kws={"size": 8})
ax.set_xticklabels(ax.get_xticklabels(), rotation=45, ha="right")
if title:
ax.set_title(title, pad=12)
fig.savefig(save_path)
plt.close(fig)Diverging Heatmap (correlation)
sns.heatmap(corr_matrix, annot=True, fmt=".2f", cmap="RdBu_r",
center=0, vmin=-1, vmax=1, ax=ax)Chart Type 4: Scatter Plot
def plot_scatter(x, y, labels=None, xlabel="", ylabel="",
save_path="figures/fig_scatter.pdf"):
fig, ax = plt.subplots(figsize=FIG_ICML_SINGLE)
scatter = ax.scatter(x, y, c=COLOR_LIST[0], s=30, alpha=0.7, edgecolors="white", linewidth=0.5)
if labels is not None:
for i, label in enumerate(labels):
ax.annotate(label, (x[i], y[i]), fontsize=7,
xytext=(5, 5), textcoords="offset points")
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
fig.savefig(save_path)
plt.close(fig)Scatter with regression line
from scipy import stats
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
line_x = np.linspace(min(x), max(x), 100)
ax.plot(line_x, slope * line_x + intercept, color=COLOR_LIST[1],
linestyle="--", linewidth=1, label=f"$R^2$={r_value**2:.3f}")Chart Type 5: Horizontal Bar (Leaderboard)
def plot_leaderboard(models, scores, highlight_idx=-1, xlabel="Score",
save_path="figures/fig_leaderboard.pdf"):
"""highlight_idx: index of 'our method' to highlight"""
fig, ax = plt.subplots(figsize=FIG_ICML_SINGLE)
y_pos = np.arange(len(models))
colors = [COLORS["gray"]] * len(models)
if highlight_idx >= 0:
colors[highlight_idx] = COLORS["red"]
bars = ax.barh(y_pos, scores, color=colors, height=0.6)
ax.set_yticks(y_pos)
ax.set_yticklabels(models)
ax.set_xlabel(xlabel)
ax.invert_yaxis()
# Value labels
for bar, score in zip(bars, scores):
ax.text(bar.get_width() + 0.3, bar.get_y() + bar.get_height() / 2,
f"{score:.1f}", va="center", fontsize=8)
fig.savefig(save_path)
plt.close(fig)Chart Type 6: Multi-Panel Figure
def plot_multi_panel(data_per_panel, panel_titles, save_path="figures/fig_panels.pdf"):
"""Create a 1xN figure with shared styling."""
n = len(data_per_panel)
fig, axes = plt.subplots(1, n, figsize=(3.25 * n, 2.5), sharey=True)
if n == 1:
axes = [axes]
for ax, data, title in zip(axes, data_per_panel, panel_titles):
# Plot each panel (customize per use case)
ax.set_title(title, fontsize=10, fontweight="bold")
# Only label left y-axis
axes[0].set_ylabel("Metric")
# Shared x-label
fig.supxlabel("Training Steps", fontsize=11)
fig.tight_layout()
fig.savefig(save_path)
plt.close(fig)Subplot label convention (a, b, c)
for i, ax in enumerate(axes):
ax.text(-0.12, 1.05, f"({chr(97 + i)})", transform=ax.transAxes,
fontsize=12, fontweight="bold", va="top")Chart Type 7: Violin / Box Plot (Distribution)
def plot_distributions(data_dict, ylabel="Score",
save_path="figures/fig_distributions.pdf"):
"""data_dict: {method_name: array_of_values}"""
fig, ax = plt.subplots(figsize=FIG_ICML_SINGLE)
positions = range(len(data_dict))
parts = ax.violinplot(list(data_dict.values()), positions=positions,
showmeans=True, showmedians=True)
for i, pc in enumerate(parts["bodies"]):
pc.set_facecolor(COLOR_LIST[i])
pc.set_alpha(0.7)
ax.set_xticks(positions)
ax.set_xticklabels(list(data_dict.keys()))
ax.set_ylabel(ylabel)
fig.savefig(save_path)
plt.close(fig)Chart Type 8: Stacked Horizontal Bar
Preferred over pie charts in ML papers for showing proportions:
def plot_stacked_bar(categories, segments, segment_labels, colors=None,
save_path="figures/fig_stacked.pdf"):
"""
categories: list of row labels
segments: list of lists (each inner list = values per segment)
"""
fig, ax = plt.subplots(figsize=FIG_ICML_FULL)
y_pos = np.arange(len(categories))
colors = colors or COLOR_LIST
left = np.zeros(len(categories))
for i, (seg_values, label) in enumerate(zip(segments, segment_labels)):
ax.barh(y_pos, seg_values, left=left, height=0.6,
label=label, color=colors[i])
# Percentage labels
for j, v in enumerate(seg_values):
if v > 5: # Only label segments > 5%
ax.text(left[j] + v / 2, y_pos[j], f"{v:.0f}%",
ha="center", va="center", fontsize=7, color="white")
left += seg_values
ax.set_yticks(y_pos)
ax.set_yticklabels(categories)
ax.set_xlabel("Percentage (%)")
ax.legend(frameon=False, loc="upper right", ncol=2)
ax.invert_yaxis()
fig.savefig(save_path)
plt.close(fig)Chart Type 9: Scaling Law Plot (Log-Log)
Common in LLM papers for compute/data/parameter scaling:
def plot_scaling(sizes, metrics, fit_line=True, xlabel="Parameters",
ylabel="Loss", save_path="figures/fig_scaling.pdf"):
fig, ax = plt.subplots(figsize=FIG_ICML_SINGLE)
ax.scatter(sizes, metrics, color=COLOR_LIST[0], s=40, zorder=5)
if fit_line:
log_sizes = np.log(sizes)
log_metrics = np.log(metrics)
coeffs = np.polyfit(log_sizes, log_metrics, 1)
fit_x = np.linspace(min(log_sizes), max(log_sizes), 100)
ax.plot(np.exp(fit_x), np.exp(np.polyval(coeffs, fit_x)),
color=COLOR_LIST[1], linestyle="--", linewidth=1.5,
label=f"$L \\propto N^{{{coeffs[0]:.2f}}}$")
ax.set_xscale("log")
ax.set_yscale("log")
ax.set_xlabel(xlabel)
ax.set_ylabel(ylabel)
if fit_line:
ax.legend(frameon=False)
fig.savefig(save_path)
plt.close(fig)Export Best Practices
Always Export Both Formats
# PDF for LaTeX (vector, crisp at any zoom)
fig.savefig("figures/fig_name.pdf", bbox_inches="tight", pad_inches=0.05)
# PNG as backup (raster, for README/slides)
fig.savefig("figures/fig_name.png", dpi=300, bbox_inches="tight", pad_inches=0.05)LaTeX Font Matching
# Option A: Use LaTeX renderer (requires texlive installation)
plt.rcParams["text.usetex"] = True
plt.rcParams["font.family"] = "serif"
# Option B: Match sans-serif style without LaTeX
plt.rcParams["text.usetex"] = False
plt.rcParams["font.family"] = "sans-serif"
plt.rcParams["font.sans-serif"] = ["Helvetica", "Arial", "DejaVu Sans"]
# Option C: Computer Modern (default LaTeX font, no LaTeX needed)
plt.rcParams["font.family"] = "serif"
plt.rcParams["font.serif"] = ["cmr10"]
plt.rcParams["axes.formatter.use_mathtext"] = TrueMath in Labels
# LaTeX math in labels (works with text.usetex=True)
ax.set_xlabel(r"$\alpha$ (learning rate)")
ax.set_ylabel(r"$\mathcal{L}$ (loss)")
# Without usetex, use mathtext
ax.set_xlabel(r"$\alpha$ (learning rate)") # Still works for simple mathSeaborn Integration
Seaborn is built on matplotlib and useful for statistical plots:
# Use seaborn styling with matplotlib control
sns.set_theme(style="whitegrid", font_scale=0.9, rc={
"axes.spines.top": False,
"axes.spines.right": False,
})
# Pair plot (for exploratory analysis, not usually in papers)
g = sns.pairplot(df, hue="method", palette=COLOR_LIST[:3])
# Joint plot (scatter + marginal distributions)
g = sns.jointplot(data=df, x="param_count", y="accuracy",
kind="reg", color=COLOR_LIST[0])Reproducibility Script Template
Every figure should have a self-contained generation script:
#!/usr/bin/env python3
"""Generate Figure X: [description].
Usage: python figures/gen_fig_name.py
Output: figures/fig_name.pdf, figures/fig_name.png
"""
import matplotlib.pyplot as plt
import numpy as np
import os
# --- Publication styling ---
plt.rcParams.update({...}) # Full rcParams block
# --- Data ---
# Either inline data or load from CSV
data = {...}
# --- Plot ---
fig, ax = plt.subplots(figsize=(3.25, 2.5))
# ... plotting code ...
# --- Save ---
out_dir = os.path.dirname(os.path.abspath(__file__))
fig.savefig(os.path.join(out_dir, "fig_name.pdf"))
fig.savefig(os.path.join(out_dir, "fig_name.png"), dpi=300)
plt.close(fig)
print("Saved: fig_name.pdf, fig_name.png")AI-Powered Diagram Generation Guide
Complete prompt engineering reference for generating distinctive, publication-quality diagrams.
Why Prompts Matter More Than Anything
The same Gemini model produces wildly different results depending on prompt quality:
- Generic prompt → boring corporate flowchart with random colors
- Style-specific prompt → distinctive, memorable figure with consistent visual identity
The style block at the top of your prompt is the single most important factor.
Model Selection
| Model | Best For | Notes |
|---|---|---|
gemini-3-pro-image-preview | All technical diagrams | Best text rendering, highest structural fidelity |
| DALL-E 3 | Conceptual illustrations | Better aesthetics, worse at precise text placement |
Prompt Architecture (6 Sections)
Section 1: Framing (5-10 lines)
Set the tone and context. This shapes the model's entire approach.
For Sketch/简笔画 style:
Create a warm, hand-drawn-style technical diagram for a NeurIPS machine learning
paper. The diagram should feel like a carefully drawn whiteboard sketch —
approachable and clear, with personality in the line work, but still precise
enough for a top venue. Think: the kind of diagram a brilliant researcher would
draw during a coffee chat to explain their system.For Modern Minimal style:
Create an ultra-clean, modern technical architecture diagram for an ICML paper.
The diagram should feel like a premium design system — confident, spacious, and
authoritative. Think: Apple's developer documentation meets a Nature paper.
Every element earns its space. No visual noise.For Illustrated Technical style:
Create a richly illustrated technical diagram for an ICLR paper. Each component
should have a small, meaningful line-art icon that helps the reader instantly
understand its purpose. The diagram should be self-explanatory — a reader should
grasp the system architecture just by looking at the figure, before reading the
caption. Think: the best technical documentation you've ever seen.Section 2: Visual Style (20-40 lines)
This is the MOST important section. Copy the full style block from SKILL.md and expand with more detail. Be extremely specific about visual characteristics.
Key principle: Describe the feeling and materiality, not just the geometry.
Good: "Lines should wobble gently like drawn with a thick felt-tip marker on smooth paper" Bad: "Lines should be slightly irregular"
Good: "Fill colors are soft watercolor-like washes — imagine diluted ink bleeding into damp paper" Bad: "Use light colors"
Good: "Components float on the background with barely-there shadows (1px offset, 6px blur, 3% opacity)" Bad: "Add subtle shadows"
Section 3: Color Palette (10-15 lines)
Always specify exact hex codes. Never leave color to the model's discretion.
"Ocean Dusk" palette (professional, calming):
COLOR PALETTE (use EXACTLY these colors, no substitutions):
- Primary components: Deep Teal #264653
- Secondary components: Teal #2A9D8F
- Accent / highlights: Gold #E9C46A
- Warm connections: Sandy Orange #F4A261
- Alert / error paths: Burnt Coral #E76F51
- Backgrounds: Warm off-white #FAFAF7
- Text primary: Nearly black #1A1A2E
- Text secondary: Warm gray #6B7280
- Borders (if any): Soft gray #E5E7EB"Ink & Wash" palette (for 简笔画):
COLOR PALETTE — INK AND WASH:
- All outlines and text: Charcoal ink #2C2C2C
- Wash fill 1: Diluted blue #D6E4F0 (like watercolor blue, very soft)
- Wash fill 2: Warm wheat #F5DEB3 (like tea-stained paper)
- Wash fill 3: Soft sage #D4E6D4 (like pale green ink wash)
- Wash fill 4: Faint lavender #E6DFF0 (like diluted purple ink)
- Background: Warm paper #FAFAF7 (NOT pure white — should feel like quality drawing paper)
- Accent marks: Terracotta #C0725E (used sparingly for emphasis)"Nord" palette (for modern minimal):
COLOR PALETTE — NORD:
- Primary: Polar Night #2E3440
- Section fills: Snow Storm #ECEFF4, #E5E9F0, #D8DEE9
- Accent Blue: Frost #5E81AC
- Accent Green: Aurora #A3BE8C
- Accent Yellow: Aurora #EBCB8B
- Accent Red: Aurora #BF616A
- Text: Polar Night #2E3440
- Subtle text: #4C566ASection 4: Layout Description (50-150 lines)
Be exhaustively specific. This is where most prompts fail — they're too vague.
Rules for writing layout descriptions: 1. Name every box with exact text content 2. Specify spatial relationships explicitly ("Box A is to the LEFT of Box B") 3. Include subtitles/descriptions for each component 4. Describe grouping ("These 3 boxes are inside a section labeled X") 5. Specify dimensions relatively ("roughly 2:1 width-to-height ratio")
Example (Sketch/简笔画 style):
LAYOUT — THREE-STAGE PIPELINE (left to right):
The diagram flows LEFT to RIGHT across three main stages, with a feedback loop
curving back from right to left at the bottom.
STAGE 1 — "Observe" (left third of diagram):
- Draw a rounded blob (not a rectangle!) with soft blue wash fill (#D6E4F0)
- Inside the blob: hand-drawn icon of an EYE (simple line drawing, 3 curved lines)
- Below the icon: "Observe" in bold charcoal
- Below that: "Gather signals from environment" in smaller text
- A small stack of paper sheets icon to the lower-right of the blob,
labeled "Raw Data" with a tiny arrow pointing into the blob
STAGE 2 — "Hypothesize" (middle third):
- Draw a rounded blob with warm wheat wash fill (#F5DEB3)
- Inside: hand-drawn LIGHTBULB icon (simple: circle + filament lines + base)
- Below: "Hypothesize" in bold
- Below: "Form testable predictions" in smaller text
- Two small thought-bubble circles trailing from the blob upward,
suggesting the thinking process
STAGE 3 — "Verify" (right third):
- Draw a rounded blob with sage wash fill (#D4E6D4)
- Inside: hand-drawn CHECKMARK icon (a satisfying thick check)
- Below: "Verify" in bold
- Below: "Test against evidence" in smaller text
FEEDBACK LOOP:
- A long curved dashed arrow from "Verify" back to "Observe",
curving BELOW the three stages
- Label on the arrow: "refine & iterate" in italic
- The arrow should feel like a casual hand-drawn curve, not a geometric arcSection 5: Connections (30-80 lines)
Describe every arrow individually. Arrows carry the semantic meaning of diagrams.
Per-arrow specification template:
ARROW [N]: [Source] → [Target]
- Style: [solid / dashed / dotted]
- Color: [hex code]
- Weight: [thin 1px / medium 2px / thick 3px]
- Routing: [straight / curves UP / curves DOWN / bezier around X]
- Label: "[text]" in [italic / bold], positioned [above / below / alongside]
- Arrowhead: [filled triangle / open chevron / circle dot]Style-specific arrow conventions:
| Style | Arrow Character |
|---|---|
| Sketch/简笔画 | Hand-drawn curves, open arrowheads, labels in casual handwriting |
| Modern Minimal | Thin gray (#6B7280) straight lines, small filled dot at source, clean chevron at target |
| Illustrated | Colored bezier curves matching source, medium weight, label badges |
| Classic Academic | Solid colored lines matching source section, filled triangle heads |
Section 6: Constraints (10-15 lines)
Adapt constraints to the chosen style:
For Sketch/简笔画:
CONSTRAINTS:
- Lines should look HAND-DRAWN but still legible — wobbly, not chaotic
- NO clip art, NO stock icons, NO photorealistic elements
- NO emoji — icons must be simple LINE DRAWINGS in charcoal
- NO figure numbers, NO captions, NO watermarks
- Background is warm off-white #FAFAF7, NOT pure white
- Overall composition should feel warm and inviting, like a sketchbook page
- Every text label spelled EXACTLY as specified
- Publication quality — this is for NeurIPS, not a napkin sketchFor Modern Minimal:
CONSTRAINTS:
- ZERO decoration — no icons, no illustrations, no ornaments
- NO visible borders on component boxes — they float using subtle shadow only
- NO thick colored lines — all connections are thin gray
- NO gradients, NO patterns, NO textures
- Whitespace is a design element — at least 24px between all elements
- NO figure numbers, NO captions, NO watermarks
- Background pure white #FFFFFF
- Every text label spelled EXACTLY as specifiedComplete Prompt Examples
Example 1: Agent System (Sketch/简笔画 Style)
Create a warm, hand-drawn-style technical diagram for a NeurIPS paper showing
an autonomous research agent system. The diagram should feel like a carefully
drawn whiteboard sketch — approachable yet precise.
VISUAL STYLE — HAND-DRAWN SKETCH:
- Slightly irregular, hand-drawn line quality — lines wobble gently, not perfectly straight
- Rounded, soft shapes with visible pen strokes (like drawn with a thick felt-tip marker)
- Warm off-white background (#FAFAF7)
- Fill colors are soft watercolor washes: blue #D6E4F0, wheat #F5DEB3, sage #D4E6D4
- Borders are charcoal #2C2C2C, 2-3px, slightly uneven
- Arrows hand-drawn with natural curves, open arrowheads
- Small doodle-style line-art icons inside each component (NOT emoji, NOT clip art)
- Text in rounded sans-serif, warm and readable
COLOR PALETTE — INK AND WASH:
- Outlines/text: Charcoal #2C2C2C
- Planner fill: Blue wash #D6E4F0
- Executor fill: Wheat wash #F5DEB3
- Verifier fill: Sage wash #D4E6D4
- Background: Warm paper #FAFAF7
- Failure/retry: Terracotta #C0725E
LAYOUT — TRIANGULAR ARRANGEMENT:
Three rounded blob shapes arranged in a triangle:
TOP CENTER — "Planner" blob:
- Blue wash fill (#D6E4F0)
- Line-art icon: a small COMPASS or MAP (simple 2D line drawing)
- Bold label: "Planner"
- Subtitle: "Decomposes research questions"
BOTTOM LEFT — "Executor" blob:
- Wheat wash fill (#F5DEB3)
- Line-art icon: a small GEAR or WRENCH
- Bold label: "Executor"
- Subtitle: "Runs experiments & tools"
BOTTOM RIGHT — "Verifier" blob:
- Sage wash fill (#D4E6D4)
- Line-art icon: a small MAGNIFYING GLASS
- Bold label: "Verifier"
- Subtitle: "Checks results & evidence"
ARROWS:
1. Planner → Executor: curved arrow going DOWN-LEFT, charcoal, solid
Label: "task plan" (italic, small)
2. Executor → Verifier: curved arrow going RIGHT, charcoal, solid
Label: "raw results" (italic, small)
3. Verifier → Planner: curved arrow going UP-LEFT, terracotta #C0725E, DASHED
Label: "needs revision" (italic, small)
This is the feedback/retry path — dashed to show it's conditional
CENTER of triangle: small text "Shared Memory" with a tiny notebook icon
CONSTRAINTS:
- Hand-drawn feel but still publication quality for NeurIPS
- NO clip art, NO stock icons — only simple line drawings
- NO figure numbers, NO captions
- Warm off-white background, NOT pure white
- Every label spelled EXACTLY as writtenExample 2: Training Pipeline (Modern Minimal Style)
Create an ultra-clean, modern technical architecture diagram for an ICML paper.
Confident, spacious, authoritative. Think: Apple developer docs meets Nature paper.
VISUAL STYLE — MODERN MINIMAL:
- Ultra-clean geometric shapes with crisp edges
- Bold color blocks as section fills using desaturated tones
- Component boxes: 12px rounded corners, NO visible border, float on section
background with subtle shadow (1px, 4px blur, rgba(0,0,0,0.06))
- ONE accent color per section, used on section header only
- Arrows: thin 1.5px, dark gray #6B7280, small filled circle at source,
clean open chevron at target
- Typography: system sans-serif, titles 600 weight, body 400 weight
- Labels INSIDE boxes, generous whitespace (24px+ between elements)
COLOR PALETTE — NORD:
- Deep text: #2E3440
- Section 1 fill: #EEF1F6 (blue tint), accent: #5E81AC
- Section 2 fill: #EDF3ED (green tint), accent: #A3BE8C
- Section 3 fill: #F5F2EA (yellow tint), accent: #EBCB8B
- Box fill: White #FFFFFF
- Arrows: #6B7280
LAYOUT — THREE HORIZONTAL SECTIONS:
Three wide horizontal bands, stacked vertically with 16px gaps.
Each section is a full-width rounded rectangle (8px corners).
[SECTION 1 — "Data" — blue tint background #EEF1F6]
- Small section header top-left: "DATA" in #5E81AC, small caps, letter-spaced
- Three white floating boxes in a row:
Box: "Corpus" / "1.2T tokens"
Box: "Filter" / "Quality + dedup"
Box: "Tokenize" / "BPE 32K"
[SECTION 2 — "Train" — green tint background #EDF3ED]
- Header: "TRAIN" in #A3BE8C
- Three white floating boxes:
Box: "Model" / "7B · 32 layers"
Box: "Optimize" / "AdamW · cosine"
Box: "Checkpoint" / "Every 1K steps"
[SECTION 3 — "Evaluate" — yellow tint background #F5F2EA]
- Header: "EVALUATE" in #EBCB8B
- Three white floating boxes:
Box: "Benchmark" / "MMLU · HumanEval"
Box: "Analyze" / "Scaling curves"
Box: "Report" / "Camera-ready"
ARROWS:
1. "Tokenize" → "Model": thin gray #6B7280, vertical, label "feeds"
2. "Checkpoint" → "Benchmark": thin gray, vertical, label "evaluate"
3. "Analyze" → "Report": thin gray, horizontal, label "publish"
CONSTRAINTS:
- ZERO decoration — no icons, no illustrations
- NO visible box borders — shadow only
- Generous whitespace between all elements
- NO figure numbers, NO captions, NO watermarks
- Background: pure white #FFFFFF
- All labels EXACTLY as written
- Publication quality for ICML 2026Multi-Attempt Evaluation Rubric
Rate each attempt on these 5 dimensions (1-5 scale):
| Dimension | What to Check | Weight |
|---|---|---|
| Style fidelity | Does it match the requested visual style? (e.g., hand-drawn feel, clean minimal) | 30% |
| Text accuracy | All labels spelled correctly, no phantom text? | 25% |
| Layout fidelity | Spatial arrangement matches prompt? | 20% |
| Color accuracy | Colors match hex codes? Consistent? | 15% |
| Connection accuracy | All arrows present, correct routing and labels? | 10% |
If style fidelity fails: Strengthen the style block with more sensory descriptions. Add "The overall aesthetic should resemble [specific reference]."
If text fails: Add CRITICAL: The word "[exact word]" must appear EXACTLY. Do not abbreviate, do not change capitalization.
If layout fails: Add explicit coordinates or grid references. "Box A is at position (left: 10%, top: 20%)."
TikZ Alternative (for LaTeX-native diagrams)
Use when the diagram is simple enough for deterministic output:
\begin{tikzpicture}[
box/.style={draw=#1, fill=#1!8, rounded corners=6pt, minimum width=2.8cm,
minimum height=1cm, font=\small\sffamily, line width=0.8pt},
lbl/.style={font=\scriptsize\sffamily\itshape, text=#1},
arr/.style={-{Stealth[length=5pt]}, line width=0.8pt, color=#1},
]
\node[box=teal] (plan) at (0,0) {Planner};
\node[box=orange] (exec) at (4,0) {Executor};
\node[box=olive] (veri) at (8,0) {Verifier};
\draw[arr=gray] (plan) -- (exec) node[midway, above, lbl=gray] {task plan};
\draw[arr=gray] (exec) -- (veri) node[midway, above, lbl=gray] {results};
\draw[arr=red!60, dashed] (veri) to[bend right=30]
node[midway, below, lbl=red!60] {revise} (plan);
\end{tikzpicture}Mermaid for Quick Prototyping
Sketch the logical flow before investing in Gemini generation:
graph LR
A[Observe] --> B[Hypothesize]
B --> C[Verify]
C -.->|refine| AValidate the structure is correct, then write the full Gemini prompt.
Publication Style Guide for ML Paper Figures
Standards for figure styling across major ML/AI conferences.
Universal Rules
1. Vector format preferred — Export PDF for LaTeX, PNG only for AI-generated diagrams 2. 300 DPI minimum for raster images 3. Colorblind-safe palettes — Never rely on color alone; add markers, patterns, or labels 4. Consistent style — All figures in a paper must share fonts, colors, and styling 5. Self-contained — Every figure must be understandable without reading the caption first 6. No decorative elements — No shadows, 3D effects, gradients, or clip art
Venue-Specific Figure Dimensions
NeurIPS
| Layout | Width | Notes |
|---|---|---|
| Single column | 5.5 in | NeurIPS is single-column |
| Half width | 2.65 in | Side-by-side within column |
| Max height | 9 in | Full page |
Template: \usepackage[final]{neurips_2025}
ICML
| Layout | Width | Notes |
|---|---|---|
| Single column | 3.25 in | ICML is two-column |
| Full width | 6.75 in | \begin{figure*} |
| Max height | 9.25 in | Full page |
Template: \usepackage{icml2026}
ICLR
| Layout | Width | Notes |
|---|---|---|
| Single column | 5.5 in | ICLR is single-column |
| Max height | 9 in | Full page |
Template: \usepackage{iclr2026_conference}
ACL / EMNLP
| Layout | Width | Notes |
|---|---|---|
| Single column | 3.3 in | ACL is two-column |
| Full width | 6.8 in | \begin{figure*} |
Template: \usepackage[hyperref]{acl2025}
AAAI
| Layout | Width | Notes |
|---|---|---|
| Single column | 3.3 in | AAAI is two-column |
| Full width | 7.0 in | \begin{figure*} |
Color Palettes
Recommended Colorblind-Safe Palette
This palette is distinguishable under all forms of color vision deficiency:
# "deep" variant — high contrast, good for lines and bars
PALETTE_DEEP = [
"#4C72B0", # blue
"#DD8452", # orange
"#55A868", # green
"#C44E52", # red
"#8172B3", # purple
"#937860", # brown
"#DA8BC3", # pink
"#8C8C8C", # gray
]Two-Color Schemes (ours vs. baseline)
# High contrast pair
OURS = "#C44E52" # red — stands out
BASELINE = "#8C8C8C" # gray — recedes
# Alternative pair
OURS = "#4C72B0" # blue
BASELINE = "#DD8452" # orangeGradient Schemes (for heatmaps / continuous data)
| Use Case | Colormap | Code |
|---|---|---|
| Single variable (0 to max) | Blues | cmap="Blues" |
| Diverging (negative to positive) | RdBu_r | cmap="RdBu_r" |
| Perceptually uniform | viridis | cmap="viridis" |
| Correlation matrix | coolwarm | cmap="coolwarm" |
| Attention weights | YlOrRd | cmap="YlOrRd" |
Colors to Avoid
- Pure red + pure green — indistinguishable for ~8% of males
- Rainbow/jet colormap — perceptually non-uniform, misleading
- Light yellow on white — insufficient contrast
- Neon/saturated colors — look unprofessional in academic papers
Typography
Font Matching LaTeX Documents
| Conference | Document Font | Figure Font Setting |
|---|---|---|
| NeurIPS | Times | font.family: serif, font.serif: Times New Roman |
| ICML | Times | Same as NeurIPS |
| ICLR | Times | Same as NeurIPS |
| ACL | Times | Same as NeurIPS |
| AAAI | Times | Same as NeurIPS |
Font Size Guidelines
| Element | Size | Rationale |
|---|---|---|
| Axis labels | 10-11pt | Must be readable at print size |
| Tick labels | 8-9pt | Smaller but legible |
| Legend text | 8-9pt | Compact but readable |
| Title (if any) | 11-12pt | Usually omitted (caption serves as title) |
| Annotations | 7-8pt | Smallest readable size |
Rule: No text in figures smaller than 7pt at final print size.
Math Typesetting
# For inline math
ax.set_xlabel(r"Number of parameters $N$")
# For display math
ax.set_ylabel(r"Loss $\mathcal{L}(\theta)$")
# Greek letters
ax.set_xlabel(r"Learning rate $\alpha$")
# Subscripts/superscripts
ax.set_ylabel(r"$R^2$ score")Layout Conventions
Legend Placement
Priority order: 1. Inside the plot (upper-left or upper-right) if space allows 2. Below the plot with bbox_to_anchor=(0.5, -0.15), loc="upper center", ncol=N 3. To the right with bbox_to_anchor=(1.05, 1), loc="upper left" (takes extra width)
# Clean legend (no frame, no extra spacing)
ax.legend(frameon=False, loc="upper left", handlelength=1.5)
# External legend below
ax.legend(frameon=False, bbox_to_anchor=(0.5, -0.15),
loc="upper center", ncol=4)Grid Lines
# Subtle grid (recommended)
ax.grid(True, alpha=0.3, linestyle="--", linewidth=0.5)
# Major grid only (for log-scale plots)
ax.grid(True, which="major", alpha=0.3, linestyle="--")
ax.grid(True, which="minor", alpha=0.1, linestyle=":")Axis Styling
# Remove top and right spines (clean look)
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
# Reduce tick padding
ax.tick_params(axis="both", which="major", pad=3)Multi-Panel Labels
# Standard (a), (b), (c) labels
for i, ax in enumerate(axes.flat):
ax.set_title(f"({chr(97 + i)})", loc="left", fontweight="bold", fontsize=11)
# Or as text annotation
ax.text(-0.1, 1.05, "(a)", transform=ax.transAxes,
fontsize=12, fontweight="bold", va="top")Diagram Style Standards
For AI-generated architecture/system diagrams:
Professional Diagram Palette
Section accents: Blue #4A90D9, Teal #5BA58B, Amber #D4A252, Slate #7B8794
Failure/error: Red #D94A4A (dashed lines)
Section fill: #F7F7F5 (very pale warm gray)
Box borders: #DDDDDD
Box fill: #FFFFFF
Primary text: #333333
Secondary text: #666666
Background: #FFFFFFLayout Patterns for Diagrams
| Pattern | When to Use | Description |
|---|---|---|
| Horizontal bands | Layered architectures | Sections stacked vertically, boxes horizontal |
| Left-to-right flow | Sequential pipelines | Input → Processing → Output |
| Hub-and-spoke | Central component | Central node with radiating connections |
| Grid | Matrix of components | Regular arrangement for comparison |
| Tree | Hierarchical decisions | Top-down branching structure |
Arrow Conventions
| Arrow Type | Style | Usage |
|---|---|---|
| Data flow | Solid, colored by source | Normal information passing |
| Control flow | Solid, gray | Orchestration signals |
| Error/failure | Dashed, red | Failure paths, refutation |
| Optional | Dotted, gray | Conditional paths |
| Bidirectional | Double-headed | Mutual dependencies |
LaTeX Integration
Basic Figure Inclusion
\begin{figure}[t]
\centering
\includegraphics[width=\linewidth]{figures/fig_name.pdf}
\caption{Clear description of what the figure shows. Best viewed in color.}
\label{fig:name}
\end{figure}Full-Width Figure (two-column venues)
\begin{figure*}[t]
\centering
\includegraphics[width=\textwidth]{figures/fig_overview.pdf}
\caption{System overview showing the three main components.}
\label{fig:overview}
\end{figure*}Side-by-Side Subfigures
\begin{figure}[t]
\centering
\begin{subfigure}[b]{0.48\linewidth}
\centering
\includegraphics[width=\linewidth]{figures/fig_a.pdf}
\caption{Training loss}
\label{fig:a}
\end{subfigure}
\hfill
\begin{subfigure}[b]{0.48\linewidth}
\centering
\includegraphics[width=\linewidth]{figures/fig_b.pdf}
\caption{Evaluation accuracy}
\label{fig:b}
\end{subfigure}
\caption{Training dynamics. (a) Loss decreases steadily. (b) Accuracy plateaus after 50K steps.}
\label{fig:training}
\end{figure}Caption Best Practices
- First sentence: What the figure shows (standalone understanding)
- Key takeaway: What the reader should notice
- Color note: "Best viewed in color" if color carries meaning
- No "Figure X shows..." — the figure number is already there
Good: "Training loss across model sizes. Larger models converge faster and to lower final loss." Bad: "Figure 3 shows the training loss for different model sizes."
Accessibility Checklist
- [ ] Figures readable in grayscale (print-friendly)
- [ ] No text smaller than 7pt at final print size
- [ ] Colorblind-safe palette used
- [ ] Different line styles/markers in addition to colors
- [ ] High contrast between data and background
- [ ] Axis labels present and readable
- [ ] Legend clear and non-overlapping
Related skills
How it compares
Pick Academic Plotting for static ML paper figures with matplotlib conventions rather than interactive analytics dashboards or non-Python charting stacks.
FAQ
Which libraries does Academic Plotting use?
Academic Plotting centers on matplotlib and seaborn with numpy for data handling. The skill configures plt.rcParams for serif fonts, axis sizes, and legend typography, and uses matplotlib.ticker helpers like MaxNLocator and FuncFormatter.
What font settings does Academic Plotting recommend?
Academic Plotting sets font.family to serif with Times New Roman and DejaVu Serif fallbacks at 10pt base size. Axis titles use 11pt bold, labels 10pt medium, and tick or legend text around 8.5pt for paper-ready density.
Is Academic Plotting safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.