PaperOrchestra 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".
git clone https://github.com/Ar9av/PaperOrchestra
T=$(mktemp -d) && git clone --depth=1 https://github.com/Ar9av/PaperOrchestra "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/plotting-agent" ~/.claude/skills/ar9av-paperorchestra-plotting-agent && rm -rf "$T"
skills/plotting-agent/SKILL.mdPlotting Agent (Step 2)
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.
Inputs
— specifically theworkspace/outline.json
arrayplotting_plan
andworkspace/inputs/idea.md
— the source dataworkspace/inputs/experimental_log.md
— optional pre-existing figures (workspace/inputs/figures/
mode)PlotOn
Outputs
— one PNG perworkspace/figures/<figure_id>.png
entry (300 DPI, sized to the requested aspect ratio)plotting_plan
—workspace/figures/captions.json
map{figure_id: caption_text}
Workflow
Per figure (executed independently per figure_id
)
figure_id-
Read the figure spec from
: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" } -
Few-shot retrieval (visual planning): pick the matching pattern from
(forreferences/chart-patterns.md
) orplot_type=="plot"
(forreferences/diagram-patterns.md
).plot_type=="diagram" -
Extract data: parse
and/oridea.md
(experimental_log.md
field tells you which) to obtain the numeric values or conceptual entities the figure needs. Fordata_source
, theexperimental_log.md
section contains markdown tables.## 2. Raw Numeric Data -
Render:
If
is set — use the PaperBanana backbone (Zhu et al., 2026). It runs a Retriever → Planner → Stylist → Visualizer → Critic loop and is especially good forPAPERBANANA_PATH
. Seeplot_type == "diagram"
for setup (needs a Gemini API key).references/paperbanana-cookbook.mdpython 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>.pngOtherwise — 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>.pngThe script must apply the academic style from
, use the correct pixel size fromchart-patterns.md
, save at 300 DPI, and callaspect-ratios.md
afterplt.close()
.savefig -
VLM critique loop (optional, only if your host has vision):
- Reload the rendered PNG as a multimodal input to your LLM.
- Critique it against the figure's
from the outline. Look for: visual artifacts, mislabeled axes, illegible text, color clashes, misleading scaling, missing legend, overlapping labels.objective - If problems are found, regenerate the matplotlib script with corrections and re-render. Cap at 3 critique iterations per figure.
- This is the closed-loop refinement step the paper inherits from
PaperBanana. See
for the full loop description.references/plotting-pipeline.md - If your host has no vision input, skip this step entirely. The figure will still render correctly, just without iterative refinement.
-
Generate the caption using the verbatim Caption Generation prompt at
. Inputs to the caption prompt:references/caption-prompt.md
— the section the figure belongs to (e.g., "Methodology", "Experiments")task_name
— the surrounding section text (or content_bullets from the section_plan if the section isn't drafted yet)raw_content
— thedescription
field from the figure specobjective
— a 1-sentence description of what the rendered figure actually shows (from your VLM critique pass, or from the script's plan if no vision)figure_desc
Write the caption to
keyed byworkspace/figures/captions.json
. Captions must NOT containfigure_id
orFigure N:
prefixes — the LaTeX template handles numbering. Plain text only, no markdown.Caption N:
Conceptual diagrams
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.
Hard rules
- 300 DPI for every figure. Lower DPI gets rejected at the LaTeX compile step on conference templates.
- Aspect ratio is exact. The figure spec's
is one of 12 enumerated strings. Use the pixel targets inaspect_ratio
.references/aspect-ratios.md - Hide top and right spines for plots. (Diagrams: no spines at all.)
- Muted academic colors only. The palette is in
. Never use matplotlib defaults (too saturated for print).chart-patterns.md - No 3D, no pie charts, no decorative visuals. The paper's evaluators penalize these.
- Every figure MUST have a caption in
. The Section Writing Agent will fail-stop if a caption is missing for any figure referenced from the outline.captions.json - No
prefix in captions — LaTeX adds it.Figure N: - Never describe data you didn't plot. The Plotting Agent must not
hallucinate axes, baselines, or trends. Source-of-truth is
orexperimental_log.md
.idea.md
Pre-existing figures (PlotOn mode)
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.
Resources
— verbatim Caption Generation prompt from App. F.1references/caption-prompt.md
— the full few-shot → render → critique → caption loopreferences/plotting-pipeline.md
— matplotlib style + chart type recipesreferences/chart-patterns.md
— conceptual diagram recipesreferences/diagram-patterns.md
— pixel targets for each of the 12 allowed ratios at 300 DPIreferences/aspect-ratios.md
— NEW PaperBanana setup, usage, cost notes, attributionreferences/paperbanana-cookbook.md
— render a JSON plot spec → PNG (matplotlib fallback)scripts/render_matplotlib.py
— render a JSON diagram spec → PNG (matplotlib fallback)scripts/render_diagram.py
— NEW PaperBanana backbone wrapper (readsscripts/paperbanana_render.py
from env)PAPERBANANA_PATH