ar9av/plotting-agent
Step 2 of the PaperOrchestra pipeline (arXiv:2604.05018). Execute the visualization plan from outline.json — render plots and conceptual diagrams from experimental_log.md and idea.md, optionally refine via VLM critique loop, and produce context-aware captions. Runs in parallel with the literature-review-agent. TRIGGER when the orchestrator delegates Step 2 or when the user asks to "generate the figures for my paper" or "render the plots from this experiment log".
npx skills add https://github.com/Ar9av/PaperOrchestra --skill plotting-agent
Faithful implementation of the Plotting Agent from PaperOrchestra
(Song et al., 2026, arXiv:2604.05018, §4 Step 2 and App. F.1 p.45).
Cost: ~20–30 LLM calls. The paper uses PaperBanana (Zhu et al., 2026) as
the default backbone with a closed-loop VLM-critique refinement. This skill
expresses that loop in host-agent terms: you (the host agent) generate
matplotlib code with your own LLM, render via your Bash/Python tool,
optionally critique the rendered PNG with your vision model, redraw, and
finally caption.
workspace/outline.json — specifically the plotting_plan arrayworkspace/inputs/idea.md and workspace/inputs/experimental_log.md —the source data
workspace/inputs/figures/ — optional pre-existing figures (PlotOn mode)workspace/figures/<figure_id>.png — one PNG per plotting_plan entry(300 DPI, sized to the requested aspect ratio)
workspace/figures/captions.json — {figure_id: caption_text} mapfigure_id)outline.json: {
"figure_id": "fig_main_results",
"title": "Main Results on Dataset X",
"plot_type": "plot",
"data_source": "experimental_log.md",
"objective": "Visual summary (Grouped Bar Chart) demonstrating ...",
"aspect_ratio": "5:4"
}
references/chart-patterns.md (for plot_type=="plot") or
references/diagram-patterns.md (for plot_type=="diagram").
idea.md and/or experimental_log.md(data_source field tells you which) to obtain the numeric values or
conceptual entities the figure needs. For experimental_log.md, the
## 2. Raw Numeric Data section contains markdown tables.
If PAPERBANANA_PATH is set — use the PaperBanana backbone
(Zhu et al., 2026). It runs a Retriever → Planner → Stylist → Visualizer
→ Critic loop and is especially good for plot_type == "diagram".
See references/paperbanana-cookbook.md for setup (needs a Gemini API key).
python skills/plotting-agent/scripts/paperbanana_render.py \
--figure-id <figure_id> \
--caption "<objective from figure spec>" \
--content-file workspace/inputs/idea.md \
--task <diagram|plot> \
--aspect-ratio <aspect_ratio> \
--out workspace/figures/<figure_id>.png
Otherwise — write a matplotlib script and run it via your Bash tool,
or use the bundled helper:
python skills/plotting-agent/scripts/render_matplotlib.py \
--spec spec.json \
--out workspace/figures/<figure_id>.png
The script must apply the academic style from chart-patterns.md, use the
correct pixel size from aspect-ratios.md, save at 300 DPI, and call
plt.close() after savefig.
objective from the outline. Look for:visual artifacts, mislabeled axes, illegible text, color clashes,
misleading scaling, missing legend, overlapping labels.
and re-render. Cap at 3 critique iterations per figure.
PaperBanana. See references/plotting-pipeline.md for the full loop
description.
figure will still render correctly, just without iterative refinement.
references/caption-prompt.md. Inputs to the caption prompt:
task_name — the section the figure belongs to (e.g., "Methodology","Experiments")
raw_content — the surrounding section text (or content_bullets fromthe section_plan if the section isn't drafted yet)
description — the objective field from the figure specfigure_desc — a 1-sentence description of what the rendered figureactually shows (from your VLM critique pass, or from the script's plan
if no vision)
Write the caption to workspace/figures/captions.json keyed by
figure_id. **Captions must NOT contain Figure N: or Caption N:
prefixes** — the LaTeX template handles numbering. Plain text only, no
markdown.
For plot_type == "diagram", prefer PaperBanana when available — its
Retriever grounds the Planner in real published paper diagrams. If
PAPERBANANA_PATH is unset, follow references/diagram-patterns.md.
Patterns include block diagrams, system overviews, flowcharts, and
algorithm-as-graph. The bundled helper:
python skills/plotting-agent/scripts/render_diagram.py \
--spec diagram_spec.json \
--out workspace/figures/<figure_id>.png
handles the simple cases (boxes-and-arrows). For complex Fig-1-style
overview diagrams, write matplotlib patches code yourself.
step on conference templates.
aspect_ratio is one of 12enumerated strings. Use the pixel targets in references/aspect-ratios.md.
chart-patterns.md.Never use matplotlib defaults (too saturated for print).
penalize these.
captions.json. The SectionWriting Agent will fail-stop if a caption is missing for any figure
referenced from the outline.
Figure N: prefix in captions — LaTeX adds it.hallucinate axes, baselines, or trends. Source-of-truth is
experimental_log.md or idea.md.
If workspace/inputs/figures/ is non-empty, check whether any pre-existing
file matches a figure_id in the outline (by filename prefix). If so,
copy it into workspace/figures/ as-is and still generate a caption
using the caption prompt. Only generate from scratch the figure_ids that
have no pre-existing counterpart.
references/caption-prompt.md — verbatim Caption Generation prompt from App. F.1references/plotting-pipeline.md — the full few-shot → render → critique → caption loopreferences/chart-patterns.md — matplotlib style + chart type recipesreferences/diagram-patterns.md — conceptual diagram recipesreferences/aspect-ratios.md — pixel targets for each of the 12 allowed ratios at 300 DPIreferences/paperbanana-cookbook.md — NEW PaperBanana setup, usage, cost notes, attributionscripts/render_matplotlib.py — render a JSON plot spec → PNG (matplotlib fallback)scripts/render_diagram.py — render a JSON diagram spec → PNG (matplotlib fallback)scripts/paperbanana_render.py — NEW PaperBanana backbone wrapper (reads PAPERBANANA_PATH from env)Take ar9av/plotting-agent from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.