科研技能库/科研作图标准操作规程
图表可视化
未发现用户侧风险

科研作图标准操作规程

学术图表生成的标准操作规程。包含四种渲染引擎:Python(数据可视化)、Mermaid(流程图)、AI 图像(通过 NanoBanana/OpenRouter 生成复杂图表)、SVG(矢量图)。包括引擎选择决策树、ReAct 自我纠正、NanoBanana 配置、环境检测和学术风格规则。

文件预览

1 个文件
SKILL.md
17.8 KB · 可预览
---
name: Plotting SOP
description: >-
  Standard operating procedure for academic figure generation.
  Four rendering engines: Python (data viz), Mermaid (flowcharts),
  AI Image via NanoBanana/OpenRouter (complex diagrams), SVG (vector).
  Includes engine selection decision tree, ReAct self-correction,
  NanoBanana configuration, environment detection, and academic style rules.
---

# Plotting SOP — 科研作图标准操作规程

<!-- SKILL MAINTENANCE NOTES:
     - This is a SYSTEM-LEVEL skill (lives in research-claw/skills/, NOT research-plugins)
     - Covers all figure generation workflows for academic research
     - NanoBanana = OpenRouter API endpoint for Gemini image generation
     - ReAct pattern: generate → execute → error? → inject error → retry (max 3)
     - References: writing-sop (embeds figures), workspace-sop (saves figures)
     - AGENTS.md §3 Quick Path points here for "画图/作图/figure"
     - Update AGENTS.md pointers when modifying this skill
-->

## When to Read This Skill

Read this skill when the user asks to:
- Draw, plot, or visualize any figure or diagram
- Create charts for a paper (bar, line, scatter, heatmap, radar, etc.)
- Draw flowcharts, architecture diagrams, or concept maps
- Generate figures during academic writing (called from writing-sop Phase 2)
- Convert data into visual representations

---

## §1 Environment Detection (run once per session)

Before generating any figure, **MUST** check available capabilities.
Run these checks silently (do not show output to user unless something fails):

```
Check 1: python3 -c "import matplotlib; print('matplotlib', matplotlib.__version__)"
Check 2: python3 -c "import seaborn; print('seaborn', seaborn.__version__)"
Check 3: which mmdc 2>/dev/null || npx --yes @mermaid-js/mermaid-cli mmdc --version 2>/dev/null
Check 4: python3 -c "import cairosvg; print('cairosvg OK')" 2>/dev/null
```

Record results in session memory. Do NOT repeat these checks for subsequent figures.

**If matplotlib is missing** (common on native macOS/WSL2 installs):
1. Tell user: "Python 科学绘图库未安装。是否允许我运行安装脚本?(约 30 秒)"
2. If user agrees: `bash scripts/setup-plotting-env.sh`
3. If setup script not found: `pip install --user matplotlib seaborn numpy pandas`
4. If user declines: skip Python Engine, use Mermaid or AI Image instead

**If mmdc is missing**: This is normal. Use `npx --yes @mermaid-js/mermaid-cli mmdc` as fallback.
If npx also fails: save `.mmd` file and tell user to paste at https://mermaid.live

---

## §2 Engine Selection Decision Tree

**MUST** follow this decision tree for every figure request. Do NOT skip steps.

```
User requests a figure
  │
  ├─ 1. Is it DATA VISUALIZATION (charts with numbers/statistics)?
  │    YES → §4 Python Engine
  │    Examples: bar chart, line plot, scatter, heatmap, violin, radar, histogram, box plot
  │
  ├─ 2. Is it a SIMPLE STRUCTURED DIAGRAM (≤15 nodes AND aesthetics not critical)?
  │    YES → §5 Mermaid Engine
  │    Examples: simple flowchart, sequence diagram, class diagram, Gantt chart
  │
  ├─ 3. Is it a COMPLEX diagram (>15 nodes OR requires visual polish)?
  │    (architecture diagram, research methodology flow, concept map,
  │     multi-layer system diagram, publication-quality illustration)
  │
  │    → Is NanoBanana/OpenRouter configured?
  │        YES → §6 AI Image Engine (NanoBanana)
  │        NO  → Recommend NanoBanana to user (see §3)
  │              → User provides API key? → §6 AI Image Engine
  │              → User declines?
  │                  → WARN: "本地引擎生成复杂流程图的质量有限,可能需要手动调整。"
  │                  → Fall back to §5 Mermaid Engine (best effort)
  │
  └─ 4. Is it a CUSTOM VECTOR graphic (geometric shapes, coordinate annotations)?
       YES → §7 SVG Engine
```

---

## §3 NanoBanana Configuration Guide

NanoBanana provides access to Gemini's native image generation through OpenRouter.
It is the **only reliable path** for complex, publication-quality academic diagrams
because it generates images directly (pixel-level), bypassing code generation entirely.

### Why recommend NanoBanana

- LLM-generated Mermaid/Python code for complex diagrams **frequently has syntax errors**
- Even when correct, code-rendered diagrams look mechanical and unprofessional
- Gemini image generation produces **visually polished, publication-ready** figures
- **Low-IQ models benefit most**: the API quality is independent of the local model's coding ability

### Configuration

User needs to provide an **OpenRouter API Key**.
Store in MEMORY.md under `## Global > ### Environment`:

```
NanoBanana: configured
OpenRouter API Key: [stored in environment, not in memory]
```

**Recommended model**: `google/gemini-2.5-flash-preview-image-generation`
**Alternative model**: `google/gemini-2.5-pro-preview-image-generation`
**API endpoint**: `https://openrouter.ai/api/v1/chat/completions`

### How to tell the user

When the user requests a complex diagram and NanoBanana is not configured:

> "这类复杂的学术图表,推荐使用 NanoBanana(基于 Gemini 图片生成)来获得最佳效果。
> 您只需提供一个 OpenRouter API Key(https://openrouter.ai/settings/keys)。
> 如果您不想配置,我也可以使用本地工具(Mermaid/Python)尝试生成,但质量可能有限。"

---

## §4 Python Engine — Data Visualization

For charts based on numerical data: bar, line, scatter, heatmap, violin, radar, box, histogram, pie, area, etc.

### Output Path Resolution (MUST set before generating code)

Set `output_path` per §9 naming convention:
```
output_path = "outputs/figures/{topic}-fig{N}.png"
```
Example: `outputs/figures/model-comparison-fig1.png`

### Code Template (MUST follow this structure)

The generated Python code **MUST** include all of the following elements.
Low-IQ models: copy this template exactly, then fill in the plotting section.

```python
import matplotlib
matplotlib.use('Agg')  # Non-interactive backend — MUST be before pyplot import
import matplotlib.pyplot as plt
import numpy as np

# ── Academic style settings ──────────────────────────────────
plt.rcParams.update({
    'font.family': 'sans-serif',
    'font.size': 12,
    'figure.dpi': 300,
    'axes.linewidth': 1.2,
    'axes.grid': True,
    'grid.alpha': 0.3,
    'legend.framealpha': 0.9,
})

fig, ax = plt.subplots(figsize=(10, 6))

# ── [YOUR PLOTTING CODE HERE] ───────────────────────────────
# Generate reasonable example data if user did not provide actual data.
# If using example data, add text annotation: "Example Data" in bottom-right.

# ── Labels and title (ALL ENGLISH) ──────────────────────────
ax.set_xlabel('X Label', fontsize=13)
ax.set_ylabel('Y Label', fontsize=13)
ax.set_title('Chart Title', fontsize=14, fontweight='bold')

# ── Save ─────────────────────────────────────────────────────
plt.tight_layout()
plt.savefig('{output_path}', format='png', dpi=300, bbox_inches='tight')
plt.close()
print('OK')
```

### Execution Protocol

1. **Generate code** following the template above
2. Save code to temp file: `system.run` with inline Python or write to `/tmp/rc_plot_{hash}.py`
3. **Execute**: `python3 /tmp/rc_plot_{hash}.py`
4. **Check result**:
   - Exit code 0 AND "OK" in stdout AND output file exists → **SUCCESS**
   - Otherwise → **FAILURE** → enter ReAct loop

### ReAct Self-Correction (max 3 attempts)

If execution fails:

**Attempt 2-3**: Inject the previous code and error into your next generation:

```
## Previous attempt FAILED. Fix the code.

### Previous code:
[paste the code that failed]

### Error output:
[paste stderr, truncated to 500 chars]

### Fix instructions:
- Analyze the error carefully
- Fix syntax errors, indentation, missing imports
- Ensure matplotlib.use('Agg') is BEFORE pyplot import
- Ensure savefig path is correct: {output_path}
- Do NOT use libraries that are not installed (stick to matplotlib, numpy, pandas, seaborn)
```

If all 3 attempts fail → inform user: "Python 作图失败。请检查数据格式或简化图表要求。"

### Color Palettes (academic standard)

| Use case | Palette | Code |
|----------|---------|------|
| Categorical (≤10) | tab10 | `plt.cm.tab10` |
| Categorical (≤8) | Set2 | `plt.cm.Set2` |
| Sequential | viridis | `cmap='viridis'` |
| Diverging | RdYlBu | `cmap='RdYlBu'` |
| Colorblind-safe | Paired | `plt.cm.Paired` |

**NEVER** use red-green only contrast. Always use colorblind-safe palettes.

### Chart Type Quick Reference

| User says | Chart type | Key code |
|-----------|-----------|----------|
| 柱状图/bar chart | Grouped bar | `ax.bar(x, y)` |
| 折线图/line chart | Line plot | `ax.plot(x, y)` |
| 散点图/scatter | Scatter | `ax.scatter(x, y)` |
| 热力图/heatmap | Heatmap | `import seaborn as sns; sns.heatmap(data)` |
| 箱线图/box plot | Box | `ax.boxplot(data)` or `sns.boxplot()` |
| 小提琴图/violin | Violin | `sns.violinplot()` |
| 雷达图/radar | Radar | Custom with `ax = fig.add_subplot(111, polar=True)` |
| 饼图/pie | Pie | `ax.pie(sizes, labels=labels)` |
| 直方图/histogram | Histogram | `ax.hist(data, bins=30)` |
| 面积图/area | Stacked area | `ax.stackplot(x, y1, y2)` |

---

## §5 Mermaid Engine — Structured Diagrams

For flowcharts, sequence diagrams, class diagrams, state machines, Gantt charts.

### Supported Diagram Types

| Type | Keyword | Best for |
|------|---------|----------|
| Flowchart (vertical) | `flowchart TD` | Process flows, decision trees |
| Flowchart (horizontal) | `flowchart LR` | Pipelines, architectures |
| Sequence diagram | `sequenceDiagram` | API calls, message passing |
| Class diagram | `classDiagram` | OOP design, data models |
| State diagram | `stateDiagram-v2` | State machines, lifecycle |
| Gantt chart | `gantt` | Project timelines |

### Syntax Rules (critical for low-IQ models)

1. Node IDs: use simple letters — `A`, `B`, `C` (NOT Chinese, NOT spaces)
2. Labels: wrap in `[]` — `A[Start Process]`
3. Arrows: `-->` or `-->|label|`
4. **NEVER** use these characters inside labels: `&`, `<`, `>`
5. For decision nodes (diamond shape): use single braces — `C{Is valid?}`
6. Keep diagrams **≤15 nodes AND aesthetics not critical**. For larger or visually polished diagrams → recommend NanoBanana (§6).

### Rendering Protocol

1. **Generate** Mermaid code
2. Save to temp file: `/tmp/rc_mermaid_{hash}.mmd`
3. **Render** (try in order):
   - `mmdc -i /tmp/rc_mermaid_{hash}.mmd -o {output_path} -w 1920 -H 1080 --backgroundColor white`
   - `npx --yes @mermaid-js/mermaid-cli -i /tmp/rc_mermaid_{hash}.mmd -o {output_path}`
   - Both fail → save `.mmd` file to workspace + tell user: "Mermaid 渲染工具未安装。已保存源文件,请粘贴到 https://mermaid.live 查看。"
4. **Check result**: file exists + size > 1KB → SUCCESS

### ReAct for Mermaid

If mmdc returns an error:
- Parse the error message (usually "Parse error on line N")
- Fix the syntax issue (often: special characters in labels, missing brackets)
- Retry (max 3 attempts)

---

## §6 AI Image Engine — NanoBanana (Complex Diagrams)

For complex academic diagrams that require visual polish: architecture diagrams,
research methodology flows, concept maps, multi-layer system diagrams.

### When to Use

- Diagram has >15 nodes or complex spatial layout
- User wants "美观/professional/publication-ready" quality
- User explicitly requests AI-generated figure
- Low-IQ model is active (AI Image quality is model-independent)

### API Call Protocol

**Step 0 — Confirm with user** before calling the API (costs money):
> "即将调用 NanoBanana (Gemini) 生成图片,预计消耗约 $0.01 API 额度。是否继续?"
Wait for user confirmation. If user declines → fall back to §5 Mermaid.

**Step 1 — Generate and execute** a Python script via `system.run`:

```python
import requests, base64, sys, os

API_KEY = os.environ.get('OPENROUTER_API_KEY', '')
if not API_KEY:
    print('ERROR: OPENROUTER_API_KEY not set', file=sys.stderr)
    sys.exit(1)

resp = requests.post(
    'https://openrouter.ai/api/v1/chat/completions',
    headers={
        'Authorization': f'Bearer {API_KEY}',
        'Content-Type': 'application/json',
    },
    json={
        'model': 'google/gemini-2.5-flash-preview-image-generation',
        'messages': [{
            'role': 'user',
            'content': 'Generate a professional academic diagram: {description}.\n\n'
                       'Style: clean, minimal, publication-ready, white background, '
                       'no watermark, clear English labels, professional color scheme '
                       '(blues, grays, muted tones), high resolution for academic paper.'
        }],
    },
    timeout=120,
)
resp.raise_for_status()
data = resp.json()

# Extract image from multimodal response
content = data['choices'][0]['message']['content']
b64_data = None
if isinstance(content, list):
    for part in content:
        if part.get('type') == 'image_url':
            url = part['image_url']['url']
            b64_data = url.split(',', 1)[1]
            break
        elif part.get('type') == 'image' and 'data' in part:
            b64_data = part['data']
            break
elif isinstance(content, str) and 'data:image' in content:
    b64_data = content.split(',', 1)[1]

if not b64_data:
    print('ERROR: No image found in API response', file=sys.stderr)
    sys.exit(1)

with open('{output_path}', 'wb') as f:
    f.write(base64.b64decode(b64_data))
print('OK')
```

**Step 2 — Check**: file exists + size > 1KB → SUCCESS.

**If API call fails** (timeout, auth error, quota exceeded):
- Log the error
- **WARN user**: "NanoBanana API 调用失败。降级到 Mermaid 引擎。"
- Fall back to §5 Mermaid Engine

---

## §7 SVG Engine — Custom Vector Graphics

For geometric shapes, coordinate-annotated diagrams, simple custom illustrations.

### Generation Method

Generate Python code using `svgwrite`:

```python
import svgwrite

dwg = svgwrite.Drawing('{output_path}', size=('800px', '600px'))
dwg.add(dwg.rect(insert=(0, 0), size=('100%', '100%'), fill='white'))

# [YOUR SVG ELEMENTS HERE]

dwg.save()
print('OK')
```

If `svgwrite` is not available, generate raw SVG XML and save directly.

**PNG conversion** (optional):
- Try: `python3 -c "import cairosvg; cairosvg.svg2png(url='{svg_path}', write_to='{png_path}', dpi=300)"`
- If cairosvg unavailable: keep `.svg` file, inform user

---

## §8 Quality Checklist (run after EVERY figure)

After generating a figure, **MUST** verify:

| # | Check | How to verify | If FAIL |
|---|-------|---------------|---------|
| 1 | File exists | `ls -la {output_path}` | Re-run generation |
| 2 | File size > 1KB | Same command | File is corrupt → regenerate |
| 3 | Labels in English | Review generated code | Fix labels → re-run |
| 4 | DPI ≥ 300 (Python) | Check savefig params in code | Fix → re-run |
| 5 | No overlapping text | Visual inspection if possible | Add `tight_layout()` or adjust |

If checks fail → fix and re-run (counts as one ReAct iteration).

---

## §9 Academic Figure Standards

### File Naming

Save all figures to: `outputs/figures/{topic}-fig{N}.{ext}`

Examples:
- `outputs/figures/transformer-fig1.png`
- `outputs/figures/model-comparison-fig2.png`
- `outputs/figures/methodology-flow-fig3.png`

### Caption Rule

Every figure **MUST** have an English caption. Present to user as:

> **Figure {N}.** {Caption text describing what the figure shows.}

### Citation Format

When embedding in text: "as shown in Figure {N}" or "see Figure {N}".

### Style Rules

- **Font**: sans-serif (Arial, Helvetica), ≥ 10pt for all text
- **DPI**: 300 minimum (publication standard)
- **Background**: white (no transparency)
- **Colors**: colorblind-safe palettes (viridis, Set2, tab10, Paired)
- **Borders**: thin axis lines (1-1.5pt), no box frames around plots
- **Grid**: light gray (alpha 0.3), optional but recommended for data plots
- **Legend**: positioned to avoid overlapping data; semi-transparent background

---

## §10 Integration with Writing SOP

When called from **writing-sop Phase 2** (first draft generation):

1. Writing-sop identifies a section needs a figure
2. It invokes this skill (plotting-sop) with the figure description
3. This skill generates the figure → `workspace_save` to `outputs/figures/`
4. Return to writing-sop with: figure path + caption
5. Writing-sop embeds the figure reference in the draft

**Pattern for inline invocation:**
```
[Writing-sop Phase 2, writing Methods section]
→ "This section needs a methodology flowchart"
→ [Load plotting-sop] → Engine selection → Generate → Save
→ [Return to writing-sop] → "See Figure 1" inserted in text
```

---

## RC Local Tools Reference

| Task | Tool | Example |
|:-----|:-----|:--------|
| Run Python plot | `system.run` | `python3 /tmp/rc_plot_abc.py` |
| Run Mermaid compile | `system.run` | `npx --yes @mermaid-js/mermaid-cli -i input.mmd -o output.png` |
| Call NanoBanana API | `system.run` | Python requests POST to OpenRouter endpoint |
| Save figure | `workspace_save` | `outputs/figures/{name}.png` |
| Check file | `system.run` | `ls -la outputs/figures/{name}.png` |
| Install deps (if needed) | `system.run` | `pip install matplotlib seaborn` |

SKILL.md

元数据
namePlotting SOP
description学术图表生成的标准操作规程。 四种渲染引擎:Python(数据可视化)、Mermaid(流程图)、 AI 图像(通过 NanoBanana/OpenRouter 生成复杂图表)、SVG(矢量图)。 包括引擎选择决策树、ReAct 自我纠正、 NanoBanana 配置、环境检测和学术风格规则。

Plotting SOP — 科研作图标准操作规程

<!-- 技能维护说明: - 这是一个系统级技能(位于 research-claw/skills/,而不是 research-plugins) - 覆盖所有科研图表生成流程 - NanoBanana = OpenRouter API 端点,用于 Gemini 图像生成 - ReAct 模式:生成 → 执行 → 错误? → 注入错误 → 重试(最多 3 次) - 参考:writing-sop(内嵌图表)、workspace-sop(保存图表) - AGENTS.md §3 快捷路径指向此处,用于“画图/作图/figure” - 修改本技能时请更新 AGENTS.md 指针 -->

何时阅读本技能

当用户要求以下操作时阅读本技能:

  • 绘制任何图表或图示
  • 为论文创建图表(柱状图、折线图、散点图、热力图、雷达图等)
  • 绘制流程图、架构图或概念图
  • 在学术写作过程中生成图表(由 writing-sop Phase 2 调用)
  • 将数据转换为可视化表示

§1 环境检测(每个会话运行一次)

生成任何图形之前,必须检查可用能力。 静默运行以下检查(除非有失败,否则不向用户显示输出):

text
Check 1: python3 -c "import matplotlib; print('matplotlib', matplotlib.__version__)"
Check 2: python3 -c "import seaborn; print('seaborn', seaborn.__version__)"
Check 3: which mmdc 2>/dev/null || npx --yes @mermaid-js/mermaid-cli mmdc --version 2>/dev/null
Check 4: python3 -c "import cairosvg; print('cairosvg OK')" 2>/dev/null

将会话记录结果。后续图表无需重复这些检查。

如果缺少 matplotlib(在原生 macOS/WSL2 安装中常见):

  1. 告诉用户:“Python 科学绘图库未安装。是否允许我运行安装脚本?(约 30 秒)”
  2. 如果用户同意:bash scripts/setup-plotting-env.sh
  3. 如果未找到安装脚本:pip install --user matplotlib seaborn numpy pandas
  4. 如果用户拒绝:跳过 Python 引擎,改用 Mermaid 或 AI 图像

如果缺少 mmdc:这是正常的。使用 npx --yes @mermaid-js/mermaid-cli mmdc 作为备选。 如果 npx 也失败:保存 .mmd 文件,并告知用户粘贴到 https://mermaid.live 查看


§2 引擎选择决策树

对于每个图表请求,必须遵循此决策树。不要跳过步骤。

text
用户请求图表
  │
  ├─ 1. 是数据可视化(包含数字/统计的图表)吗?
  │    是 → §4 Python 引擎
  │    示例:柱状图、折线图、散点图、热力图、小提琴图、雷达图、直方图、箱线图
  │
  ├─ 2. 是简单结构化图表(节点 ≤15 且美观性不关键)吗?
  │    是 → §5 Mermaid 引擎
  │    示例:简单流程图、时序图、类图、甘特图
  │
  ├─ 3. 是复杂图表(节点 >15 或需要视觉美化)吗?
  │    (架构图、研究方法流程、概念图、
  │     多层系统图、出版级插图)
  │
  │    → NanoBanana/OpenRouter 是否已配置?
  │        是 → §6 AI 图像引擎(NanoBanana)
  │        否  → 向用户推荐 NanoBanana(参见 §3)
  │              → 用户提供 API 密钥? → §6 AI 图像引擎
  │              → 用户拒绝?
  │                  → 警告:“本地引擎生成复杂流程图的质量有限,可能需要手动调整。”
  │                  → 回退到 §5 Mermaid 引擎(尽力而为)
  │
  └─ 4. 是定制矢量图形(几何形状、坐标注释)吗?
       是 → §7 SVG 引擎

§3 NanoBanana 配置指南

NanoBanana 通过 OpenRouter 提供对 Gemini 原生图像生成功能的访问。 它是生成复杂、出版级学术图表的唯一可靠途径, 因为它直接生成图像(像素级),完全绕过代码生成。

为什么推荐 NanoBanana

  • LLM 生成的 Mermaid/Python 代码用于复杂图表经常出现语法错误
  • 即使正确,代码渲染的图表也显得呆板、不专业
  • Gemini 图像生成能生成视觉精美、可直接出版的图表
  • 低智商模型受益最大:API 的质量与本地模型的编码能力无关

配置

用户需要提供一个 OpenRouter API 密钥。 存储在 MEMORY.md 的 ## Global > ### Environment 下:

text
NanoBanana: 已配置
OpenRouter API 密钥:[存储在环境中,而非内存中]

推荐模型:google/gemini-2.5-flash-preview-image-generation 替代模型:google/gemini-2.5-pro-preview-image-generation API 端点:https://openrouter.ai/api/v1/chat/completions

如何告知用户

当用户请求复杂图表且 NanoBanana 未配置时:

“这类复杂的学术图表,推荐使用 NanoBanana(基于 Gemini 图片生成)来获得最佳效果。 您只需提供一个 OpenRouter API Key(https://openrouter.ai/settings/keys)。 如果您不想配置,我也可以使用本地工具(Mermaid/Python)尝试生成,但质量可能有限。”


§4 Python 引擎 — 数据可视化

适用于基于数值数据的图表:柱状图、折线图、散点图、热力图、小提琴图、雷达图、箱线图、直方图、饼图、面积图等。

输出路径解析(生成代码前必须设置)

根据 §9 命名规范设置 output_path:

text
output_path = "outputs/figures/{topic}-fig{N}.png"

示例:outputs/figures/model-comparison-fig1.png

代码模板(必须遵循此结构)

生成的 Python 代码必须包含以下所有元素。 低智商模型:一字不差地复制此模板,然后填入绘图部分。

python
import matplotlib
matplotlib.use('Agg')  # 非交互后端 — 必须在导入 pyplot 之前
import matplotlib.pyplot as plt
import numpy as np

# ── 学术样式设置 ──────────────────────────────────
plt.rcParams.update({
    'font.family': 'sans-serif',
    'font.size': 12,
    'figure.dpi': 300,
    'axes.linewidth': 1.2,
    'axes.grid': True,
    'grid.alpha': 0.3,
    'legend.framealpha': 0.9,
})

fig, ax = plt.subplots(figsize=(10, 6))

# ── [你的绘图代码在此] ───────────────────────────────
# 如果用户未提供实际数据,则生成合理的示例数据。
# 如果使用示例数据,请在右下角添加文字注释:“示例数据”。

# ── 标签与标题(全部英文) ──────────────────────────
ax.set_xlabel('X Label', fontsize=13)
ax.set_ylabel('Y Label', fontsize=13)
ax.set_title('Chart Title', fontsize=14, fontweight='bold')

# ── 保存 ─────────────────────────────────────────────────────
plt.tight_layout()
plt.savefig('{output_path}', format='png', dpi=300, bbox_inches='tight')
plt.close()
print('OK')

执行协议

  1. 生成代码,遵循上述模板
  2. 将代码保存到临时文件:system.run 使用内联 Python 或写入 /tmp/rc_plot_{hash}.py
  3. 执行:python3 /tmp/rc_plot_{hash}.py
  4. 检查结果:
    • 退出代码 0 且 stdout 中有“OK”且输出文件存在 → 成功
    • 否则 → 失败 → 进入 ReAct 循环

ReAct 自我纠正(最多 3 次尝试)

如果执行失败:

尝试 2-3:将上一次的代码和错误注入到你的下一次生成中:

text
## 上一次尝试失败。请修正代码。

### 上一次的代码:
[粘贴失败的代码]

### 错误输出:
[粘贴 stderr,截断到 500 字符]

### 修正指令:
- 仔细分析错误
- 修正语法错误、缩进、缺失的导入
- 确保 matplotlib.use('Agg') 在导入 pyplot 之前
- 确保 savefig 路径正确:{output_path}
- 不要使用未安装的库(仅限于 matplotlib、numpy、pandas、seaborn)

如果所有 3 次尝试均失败 → 告知用户:“Python 作图失败。请检查数据格式或简化图表要求。”

配色方案(学术标准)

用途调色板代码
分类(≤10)tab10plt.cm.tab10
分类(≤8)Set2plt.cm.Set2
顺序viridiscmap='viridis'
发散RdYlBucmap='RdYlBu'
色盲安全Pairedplt.cm.Paired

绝对不要仅使用红绿对比。始终使用色盲安全的调色板。

图表类型快速参考

用户说图表类型关键代码
柱状图/bar chart分组柱状图ax.bar(x, y)
折线图/line chart折线图ax.plot(x, y)
散点图/scatter散点图ax.scatter(x, y)
热力图/heatmap热力图import seaborn as sns; sns.heatmap(data)
箱线图/box plot箱线图ax.boxplot(data) 或 sns.boxplot()
小提琴图/violin小提琴图sns.violinplot()
雷达图/radar雷达图自定义,使用 ax = fig.add_subplot(111, polar=True)
饼图/pie饼图ax.pie(sizes, labels=labels)
直方图/histogram直方图ax.hist(data, bins=30)
面积图/area堆叠面积图ax.stackplot(x, y1, y2)

§5 Mermaid 引擎 — 结构化图表

适用于流程图、时序图、类图、状态机、甘特图。

支持的图表类型

类型关键字最适合
流程图(垂直)flowchart TD流程、决策树
流程图(水平)flowchart LR管道、架构
时序图sequenceDiagramAPI 调用、消息传递
类图classDiagramOOP 设计、数据模型
状态图stateDiagram-v2状态机、生命周期
甘特图gantt项目时间线

语法规则(对低智商模型至关重要)

  1. 节点 ID:使用简单字母 — A、B、C(不能用中文,不能有空格)
  2. 标签:用 [] 包裹 — A[开始处理]
  3. 箭头:--> 或 -->|标签|
  4. 绝对不要在标签中使用这些字符:&、<、>
  5. 决策节点(菱形):使用单层花括号 — C{是否有效?}
  6. 保持图表节点 ≤15 且美观性不关键。对于更大或需要视觉美化的图表 → 推荐 NanoBanana(§6)。

渲染协议

  1. 生成 Mermaid 代码
  2. 保存到临时文件:/tmp/rc_mermaid_{hash}.mmd
  3. 渲染(按顺序尝试):
    • mmdc -i /tmp/rc_mermaid_{hash}.mmd -o {output_path} -w 1920 -H 1080 --backgroundColor white
    • npx --yes @mermaid-js/mermaid-cli -i /tmp/rc_mermaid_{hash}.mmd -o {output_path}
    • 两者均失败 → 保存 .mmd 文件到工作区 + 告知用户:“Mermaid 渲染工具未安装。已保存源文件,请粘贴到 https://mermaid.live 查看。”
  4. 检查结果:文件存在且大小 > 1KB → 成功

Mermaid 的 ReAct

如果 mmdc 返回错误:

  • 解析错误信息(通常是“第 N 行解析错误”)
  • 修正语法问题(通常是标签中的特殊字符、缺失的括号)
  • 重试(最多 3 次尝试)

§6 AI 图像引擎 — NanoBanana(复杂图表)

适用于需要视觉美化的复杂学术图表:架构图、研究方法流程、概念图、多层系统图。

何时使用

  • 图表节点 >15 或空间布局复杂
  • 用户希望“美观/专业/可直接出版”质量
  • 用户明确要求 AI 生成的图形
  • 低智商模型处于活跃状态(AI 图像质量与模型无关)

API 调用协议

步骤 0 — 与用户确认(调用 API 前,因为需要花钱):

“即将调用 NanoBanana (Gemini) 生成图片,预计消耗约 $0.01 API 额度。是否继续?” 等待用户确认。如果用户拒绝 → 回退到 §5 Mermaid。

步骤 1 — 生成并执行 Python 脚本,通过 system.run:

python
import requests, base64, sys, os

API_KEY = os.environ.get('OPENROUTER_API_KEY', '')
if not API_KEY:
    print('ERROR: OPENROUTER_API_KEY not set', file=sys.stderr)
    sys.exit(1)

resp = requests.post(
    'https://openrouter.ai/api/v1/chat/completions',
    headers={
        'Authorization': f'Bearer {API_KEY}',
        'Content-Type': 'application/json',
    },
    json={
        'model': 'google/gemini-2.5-flash-preview-image-generation',
        'messages': [{
            'role': 'user',
            'content': '生成一张专业的学术图表:{description}.\n\n'
                       '风格:简洁、极简、可直接出版、白色背景、'
                       '无水印、清晰的英文标签、专业的配色方案 '
                       '(蓝色、灰色、柔和色调)、学术论文所需的高分辨率。'
        }],
    },
    timeout=120,
)
resp.raise_for_status()
data = resp.json()

# 从多模态响应中提取图像
content = data['choices'][0]['message']['content']
b64_data = None
if isinstance(content, list):
    for part in content:
        if part.get('type') == 'image_url':
            url = part['image_url']['url']
            b64_data = url.split(',', 1)[1]
            break
        elif part.get('type') == 'image' and 'data' in part:
            b64_data = part['data']
            break
elif isinstance(content, str) and 'data:image' in content:
    b64_data = content.split(',', 1)[1]

if not b64_data:
    print('ERROR: No image found in API response', file=sys.stderr)
    sys.exit(1)

with open('{output_path}', 'wb') as f:
    f.write(base64.b64decode(b64_data))
print('OK')

步骤 2 — 检查:文件存在且大小 > 1KB → 成功。

如果 API 调用失败(超时、认证错误、配额超出):

  • 记录错误
  • 警告用户:“NanoBanana API 调用失败。降级到 Mermaid 引擎。”
  • 回退到 §5 Mermaid 引擎

§7 SVG 引擎 — 定制矢量图形

适用于几何形状、坐标注释图、简单的自定义插图。

生成方法

使用 svgwrite 生成 Python 代码:

python
import svgwrite

dwg = svgwrite.Drawing('{output_path}', size=('800px', '600px'))
dwg.add(dwg.rect(insert=(0, 0), size=('100%', '100%'), fill='white'))

# [你的 SVG 元素在此]

dwg.save()
print('OK')

如果 svgwrite 不可用,生成原始 SVG XML 并直接保存。

PNG 转换(可选):

  • 尝试:python3 -c "import cairosvg; cairosvg.svg2png(url='{svg_path}', write_to='{png_path}', dpi=300)"
  • 如果 cairosvg 不可用:保留 .svg 文件,告知用户

§8 质量检查清单(每张图表生成后执行)

生成图表后,必须验证:

#检查项如何验证如果失败
1文件存在ls -la {output_path}重新生成
2文件大小 > 1KB同上文件损坏 → 重新生成
3英文标签检查生成的代码修正标签 → 重新运行
4DPI ≥ 300(Python)检查代码中的 savefig 参数修正 → 重新运行
5无重叠文本可能的话进行视觉检查添加 tight_layout() 或调整

如果检查失败 → 修正并重新运行(计为一次 ReAct 迭代)。


§9 学术图表标准

文件命名

所有图表保存到:outputs/figures/{topic}-fig{N}.{ext}

示例:

  • outputs/figures/transformer-fig1.png
  • outputs/figures/model-comparison-fig2.png
  • outputs/figures/methodology-flow-fig3.png

标题规则

每张图表必须有英文标题。呈现给用户的方式:

图 {N}. {描述图表内容的标题文本。}

引用格式

在正文中引用时:“as shown in Figure {N}” 或 “see Figure {N}”。

样式规则

  • 字体:无衬线体(Arial、Helvetica),所有文字 ≥ 10pt
  • DPI:最低 300(出版标准)
  • 背景:白色(无透明度)
  • 颜色:色盲安全调色板(viridis、Set2、tab10、Paired)
  • 边框:细轴线(1-1.5pt),图表周围不要加方框
  • 网格:浅灰色(透明度 0.3),对于数据图推荐但可选
  • 图例:放置位置避免遮挡数据;使用半透明背景

§10 与写作 SOP 的集成

当从 writing-sop Phase 2(初稿生成)调用时:

  1. Writing-sop 识别某个部分需要图表
  2. 它调用本技能(plotting-sop)并传入图表描述
  3. 本技能生成图表 → workspace_save 到 outputs/figures/
  4. 返回给 writing-sop:图表路径 + 标题
  5. Writing-sop 在草稿中嵌入图表引用

内联调用模式:

text
[Writing-sop Phase 2,正在撰写 Methods 部分]
→ “本部分需要方法流程图”
→ [加载 plotting-sop] → 引擎选择 → 生成 → 保存
→ [返回 writing-sop] → 在文本中插入“见图 1”

RC 本地工具参考

任务工具示例
运行 Python 绘图system.runpython3 /tmp/rc_plot_abc.py
运行 Mermaid 编译system.runnpx --yes @mermaid-js/mermaid-cli -i input.mmd -o output.png
调用 NanoBanana APIsystem.run使用 requests 向 OpenRouter 端点发送 POST 请求的 Python 脚本
保存图表workspace_saveoutputs/figures/{name}.png
检查文件system.runls -la outputs/figures/{name}.png
安装依赖(如有必要)system.runpip install matplotlib seaborn