$npx -y skills add Ar9av/PaperOrchestra --skill plotting-agentStep 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 wi
| 1 | # Plotting Agent (Step 2) |
| 2 | |
| 3 | Faithful implementation of the Plotting Agent from PaperOrchestra |
| 4 | (Song et al., 2026, arXiv:2604.05018, §4 Step 2 and App. F.1 p.45). |
| 5 | |
| 6 | **Cost: ~20–30 LLM calls.** The paper uses PaperBanana (Zhu et al., 2026) as |
| 7 | the default backbone with a closed-loop VLM-critique refinement. This skill |
| 8 | expresses that loop in host-agent terms: you (the host agent) generate |
| 9 | matplotlib code with your own LLM, render via your Bash/Python tool, |
| 10 | optionally critique the rendered PNG with your vision model, redraw, and |
| 11 | finally caption. |
| 12 | |
| 13 | ## Inputs |
| 14 | |
| 15 | - `workspace/outline.json` — specifically the `plotting_plan` array |
| 16 | - `workspace/inputs/idea.md` and `workspace/inputs/experimental_log.md` — |
| 17 | the source data |
| 18 | - `workspace/inputs/figures/` — optional pre-existing figures (`PlotOn` mode) |
| 19 | |
| 20 | ## Outputs |
| 21 | |
| 22 | - `workspace/figures/<figure_id>.png` — one PNG per `plotting_plan` entry |
| 23 | (300 DPI, sized to the requested aspect ratio) |
| 24 | - `workspace/figures/captions.json` — `{figure_id: caption_text}` map |
| 25 | |
| 26 | ## Workflow |
| 27 | |
| 28 | ### Per figure (executed independently per `figure_id`) |
| 29 | |
| 30 | 1. **Read the figure spec** from `outline.json`: |
| 31 | ```json |
| 32 | { |
| 33 | "figure_id": "fig_main_results", |
| 34 | "title": "Main Results on Dataset X", |
| 35 | "plot_type": "plot", |
| 36 | "data_source": "experimental_log.md", |
| 37 | "objective": "Visual summary (Grouped Bar Chart) demonstrating ...", |
| 38 | "aspect_ratio": "5:4" |
| 39 | } |
| 40 | ``` |
| 41 | |
| 42 | 2. **Few-shot retrieval (visual planning)**: pick the matching pattern from |
| 43 | `references/chart-patterns.md` (for `plot_type=="plot"`) or |
| 44 | `references/diagram-patterns.md` (for `plot_type=="diagram"`). |
| 45 | |
| 46 | 3. **Extract data**: parse `idea.md` and/or `experimental_log.md` |
| 47 | (`data_source` field tells you which) to obtain the numeric values or |
| 48 | conceptual entities the figure needs. For `experimental_log.md`, the |
| 49 | `## 2. Raw Numeric Data` section contains markdown tables. |
| 50 | |
| 51 | 4. **Render**: |
| 52 | |
| 53 | **If `PAPERBANANA_PATH` is set** — use the PaperBanana backbone |
| 54 | (Zhu et al., 2026). It runs a Retriever → Planner → Stylist → Visualizer |
| 55 | → Critic loop and is especially good for `plot_type == "diagram"`. |
| 56 | See `references/paperbanana-cookbook.md` for setup (needs a Gemini API key). |
| 57 | |
| 58 | ```bash |
| 59 | python skills/plotting-agent/scripts/paperbanana_render.py \ |
| 60 | --figure-id <figure_id> \ |
| 61 | --caption "<objective from figure spec>" \ |
| 62 | --content-file workspace/inputs/idea.md \ |
| 63 | --task <diagram|plot> \ |
| 64 | --aspect-ratio <aspect_ratio> \ |
| 65 | --out workspace/figures/<figure_id>.png |
| 66 | ``` |
| 67 | |
| 68 | **Otherwise** — write a matplotlib script and run it via your Bash tool, |
| 69 | or use the bundled helper: |
| 70 | ```bash |
| 71 | python skills/plotting-agent/scripts/render_matplotlib.py \ |
| 72 | --spec spec.json \ |
| 73 | --out workspace/figures/<figure_id>.png |
| 74 | ``` |
| 75 | The script must apply the academic style from `chart-patterns.md`, use the |
| 76 | correct pixel size from `aspect-ratios.md`, save at 300 DPI, and call |
| 77 | `plt.close()` after `savefig`. |
| 78 | |
| 79 | 5. **VLM critique loop (optional, only if your host has vision)**: |
| 80 | - Reload the rendered PNG as a multimodal input to your LLM. |
| 81 | - Critique it against the figure's `objective` from the outline. Look for: |
| 82 | visual artifacts, mislabeled axes, illegible text, color clashes, |
| 83 | misleading scaling, missing legend, overlapping labels. |
| 84 | - If problems are found, regenerate the matplotlib script with corrections |
| 85 | and re-render. Cap at 3 critique iterations per figure. |
| 86 | - This is the closed-loop refinement step the paper inherits from |
| 87 | PaperBanana. See `references/plotting-pipeline.md` for the full loop |
| 88 | description. |
| 89 | - **If your host has no vision input, skip this step entirely.** The |
| 90 | figure will still render correctly, just without iterative refinement. |
| 91 | |
| 92 | 6. **Generate the caption** using the verbatim Caption Generation prompt at |
| 93 | `references/caption-prompt.md`. Inputs to the caption prompt: |
| 94 | - `task_name` — the section the figure belongs to (e.g., "Methodology", |
| 95 | "Experiments") |
| 96 | - `raw_content` — the surrounding section text (or content_bullets from |
| 97 | the section_plan if the section isn't drafted yet) |
| 98 | - `description` — the `objective` field from the figure spec |
| 99 | - `figure_desc` — a 1-sentence description of what the rendered figure |
| 100 | actually shows (from your VLM critique pass, or from the script's plan |
| 101 | if no vision) |
| 102 | |
| 103 | Write the caption to `workspace/figures/captions.json` keyed by |
| 104 | `figure_id`. **Captions must NOT contain `Figu |