科研技能库/Matplotlib 科学可视化
visualization
低风险

Matplotlib 科学可视化

使用 Matplotlib 进行科学可视化。适用于用户请求绘制图形、图表或数据可视化。不适用于交互式仪表板或基于 Web 的图表。

文件预览

1 个文件
SKILL.md
5.8 KB · 可预览
---
name: matplotlib-viz
description: "Scientific visualization via Matplotlib. Use when: user asks for plots, charts, or data visualization. NOT for: interactive dashboards or web-based charts."
metadata: { "openclaw": { "emoji": "📊", "requires": { "bins": ["python3"] }, "install": [{ "id": "uv-matplotlib", "kind": "uv", "package": "matplotlib numpy" }] } }
---

# Matplotlib Visualization

Scientific visualization and publication-quality figures using Matplotlib and NumPy.

## When to Use

- Static plots: line, scatter, bar, histogram, heatmap
- Publication-ready scientific figures
- Multi-panel (subplot) layouts
- Saving figures to PNG, SVG, or PDF
- Annotated or styled plots for presentations and papers

## When NOT to Use

- Interactive dashboards (use Plotly or Dash)
- Web-based charts (use D3.js or Chart.js)
- Real-time streaming visualizations
- Geographic/map plots (use Cartopy or Folium)

## Basic Setup

```python
import matplotlib
matplotlib.use('Agg')  # non-interactive backend for saving files
import matplotlib.pyplot as plt
import numpy as np
```

## Line and Scatter Plots

```python
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x), label='sin(x)', linewidth=2)
ax.plot(x, np.cos(x), label='cos(x)', linestyle='--')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('Trigonometric Functions')
ax.legend()
fig.savefig('line_plot.png', dpi=150, bbox_inches='tight')
plt.close(fig)

# Scatter with colormap
fig, ax = plt.subplots()
sc = ax.scatter(x_data, y_data, c=color_values, cmap='viridis', s=50, alpha=0.7)
fig.colorbar(sc, ax=ax, label='Magnitude')
fig.savefig('scatter.png', dpi=150, bbox_inches='tight')
plt.close(fig)
```

## Bar Charts and Histograms

```python
categories = ['A', 'B', 'C', 'D']
values = [23, 45, 12, 67]
fig, ax = plt.subplots()
ax.bar(categories, values, color='steelblue', edgecolor='black')
ax.set_ylabel('Count')
fig.savefig('bar_chart.png', dpi=150, bbox_inches='tight')
plt.close(fig)

# Histogram with KDE overlay
fig, ax = plt.subplots()
ax.hist(data, bins=30, density=True, alpha=0.7, color='skyblue', edgecolor='black')
ax.set_xlabel('Value')
ax.set_ylabel('Density')
fig.savefig('histogram.png', dpi=150, bbox_inches='tight')
plt.close(fig)
```

## Heatmaps

```python
data_matrix = np.random.rand(10, 10)
fig, ax = plt.subplots(figsize=(8, 6))
im = ax.imshow(data_matrix, cmap='coolwarm', aspect='auto')
fig.colorbar(im, ax=ax)
ax.set_xticks(range(10))
ax.set_yticks(range(10))
fig.savefig('heatmap.png', dpi=150, bbox_inches='tight')
plt.close(fig)
```

## Subplots and Multi-Panel Figures

```python
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
axes[0, 0].plot(x, y1)
axes[0, 0].set_title('Panel A')
axes[0, 1].scatter(x, y2, s=10)
axes[0, 1].set_title('Panel B')
axes[1, 0].bar(categories, values)
axes[1, 0].set_title('Panel C')
axes[1, 1].hist(data, bins=20)
axes[1, 1].set_title('Panel D')
fig.tight_layout()
fig.savefig('multi_panel.png', dpi=150, bbox_inches='tight')
plt.close(fig)
```

## Scientific Figure Templates

```python
# Error bars
fig, ax = plt.subplots()
ax.errorbar(x, y_mean, yerr=y_std, fmt='o-', capsize=4, capthick=1.5, label='Experiment')
ax.fill_between(x, y_mean - y_std, y_mean + y_std, alpha=0.2)
fig.savefig('errorbar.png', dpi=300, bbox_inches='tight')
plt.close(fig)

# Box plot
fig, ax = plt.subplots()
bp = ax.boxplot([group1, group2, group3], labels=['Ctrl', 'Treatment A', 'Treatment B'],
                patch_artist=True, showmeans=True)
fig.savefig('boxplot.png', dpi=300, bbox_inches='tight')
plt.close(fig)

# Violin plot
fig, ax = plt.subplots()
vp = ax.violinplot([group1, group2, group3], showmeans=True, showmedians=True)
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['Ctrl', 'Treatment A', 'Treatment B'])
fig.savefig('violin.png', dpi=300, bbox_inches='tight')
plt.close(fig)
```

## Saving Figures

```python
fig.savefig('figure.png', dpi=300, bbox_inches='tight')   # raster
fig.savefig('figure.svg', bbox_inches='tight')              # vector (editable)
fig.savefig('figure.pdf', bbox_inches='tight')              # vector (print-ready)
```

## Journal-Quality Figure Standards

**Sizing presets (width x height):**
- single_column: `(8.5/2.54, 7/2.54)` — 8.5 x 7 cm
- one_half_column: `(12/2.54, 9/2.54)` — 12 x 9 cm
- double_column: `(17.5/2.54, 10/2.54)` — 17.5 x 10 cm
- presentation: `(25/2.54, 18/2.54)` — 25 x 18 cm

**Journal color palettes:**
```python
PALETTES = {
    'NPG': ["#E64B35", "#4DBBD5", "#00A087", "#3C5488", "#F39B7F", "#8491B4", "#91D1C2", "#DC0000", "#7E6148", "#B09C85"],
    'Lancet': ["#00468B", "#ED0000", "#42B540", "#0099B4", "#925E9F", "#FDAF91", "#AD002A", "#ADB6B6"],
    'JCO': ["#0073C2", "#EFC000", "#868686", "#CD534C", "#7AA6DC", "#003C67", "#8F7700", "#3B3B3B"],
    'NEJM': ["#BC3C29", "#0072B5", "#E18727", "#20854E", "#7876B1", "#6F99AD", "#FFDC91", "#EE4C97"],
}
```

**File naming:** Use descriptive names a human can understand months later:
- `km_survival_thbs2_high_vs_low.png` (not `figure1.png`)
- `volcano_plot_deseq2_tumor_vs_normal.png` (not `plot.png`)
- `forest_plot_meta_analysis.pdf` (not `result.pdf`)

## Best Practices

1. Always use `matplotlib.use('Agg')` before importing `pyplot` for headless environments.
2. Use `fig, ax = plt.subplots()` (OO interface) instead of `plt.plot()` (state machine).
3. Call `plt.close(fig)` after saving to free memory.
4. Use `bbox_inches='tight'` to avoid clipped labels.
5. Set `dpi=300` for publication figures, `dpi=150` for screen.
6. Use colormaps from `matplotlib.colormaps` (avoid jet; prefer viridis, coolwarm).
7. **Never save to `/tmp/`.** Save to the project workspace directory for persistence.
8. Always report the full output path after saving so the user can find the file.

SKILL.md

元数据
namematplotlib-viz
description使用 Matplotlib 进行科学可视化。适用于:用户请求绘制图形、图表或数据可视化。不适用于:交互式仪表板或基于 Web 的图表。
metadata{ "openclaw": { "emoji": "📊", "requires": { "bins": ["python3"] }, "install": [{ "id": "uv-matplotlib", "kind": "uv", "package": "matplotlib numpy" }] } }

Matplotlib 可视化

使用 Matplotlib 和 NumPy 进行科学可视化和制作出版级质量的图形。

何时使用

  • 静态图:折线图、散点图、条形图、直方图、热力图
  • 出版级质量的科学图形
  • 多面板(子图)布局
  • 将图形保存为 PNG、SVG 或 PDF
  • 用于演示和论文的带注释或样式化的图形

何时不使用

  • 交互式仪表板(使用 Plotly 或 Dash)
  • 基于 Web 的图表(使用 D3.js 或 Chart.js)
  • 实时流式可视化
  • 地理/地图图形(使用 Cartopy 或 Folium)

基础设置

python
import matplotlib
matplotlib.use('Agg')  # 用于保存文件的非交互式后端
import matplotlib.pyplot as plt
import numpy as np

折线图和散点图

python
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot(x, np.sin(x), label='sin(x)', linewidth=2)
ax.plot(x, np.cos(x), label='cos(x)', linestyle='--')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('三角函数')
ax.legend()
fig.savefig('line_plot.png', dpi=150, bbox_inches='tight')
plt.close(fig)

# 带颜色映射的散点图
fig, ax = plt.subplots()
sc = ax.scatter(x_data, y_data, c=color_values, cmap='viridis', s=50, alpha=0.7)
fig.colorbar(sc, ax=ax, label='幅度')
fig.savefig('scatter.png', dpi=150, bbox_inches='tight')
plt.close(fig)

条形图和直方图

python
categories = ['A', 'B', 'C', 'D']
values = [23, 45, 12, 67]
fig, ax = plt.subplots()
ax.bar(categories, values, color='steelblue', edgecolor='black')
ax.set_ylabel('计数')
fig.savefig('bar_chart.png', dpi=150, bbox_inches='tight')
plt.close(fig)

# 带 KDE 叠加的直方图
fig, ax = plt.subplots()
ax.hist(data, bins=30, density=True, alpha=0.7, color='skyblue', edgecolor='black')
ax.set_xlabel('值')
ax.set_ylabel('密度')
fig.savefig('histogram.png', dpi=150, bbox_inches='tight')
plt.close(fig)

热力图

python
data_matrix = np.random.rand(10, 10)
fig, ax = plt.subplots(figsize=(8, 6))
im = ax.imshow(data_matrix, cmap='coolwarm', aspect='auto')
fig.colorbar(im, ax=ax)
ax.set_xticks(range(10))
ax.set_yticks(range(10))
fig.savefig('heatmap.png', dpi=150, bbox_inches='tight')
plt.close(fig)

子图和多面板图形

python
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
axes[0, 0].plot(x, y1)
axes[0, 0].set_title('面板 A')
axes[0, 1].scatter(x, y2, s=10)
axes[0, 1].set_title('面板 B')
axes[1, 0].bar(categories, values)
axes[1, 0].set_title('面板 C')
axes[1, 1].hist(data, bins=20)
axes[1, 1].set_title('面板 D')
fig.tight_layout()
fig.savefig('multi_panel.png', dpi=150, bbox_inches='tight')
plt.close(fig)

科学图形模板

python
# 误差线
fig, ax = plt.subplots()
ax.errorbar(x, y_mean, yerr=y_std, fmt='o-', capsize=4, capthick=1.5, label='实验')
ax.fill_between(x, y_mean - y_std, y_mean + y_std, alpha=0.2)
fig.savefig('errorbar.png', dpi=300, bbox_inches='tight')
plt.close(fig)

# 箱线图
fig, ax = plt.subplots()
bp = ax.boxplot([group1, group2, group3], labels=['对照组', '处理 A', '处理 B'],
                patch_artist=True, showmeans=True)
fig.savefig('boxplot.png', dpi=300, bbox_inches='tight')
plt.close(fig)

# 小提琴图
fig, ax = plt.subplots()
vp = ax.violinplot([group1, group2, group3], showmeans=True, showmedians=True)
ax.set_xticks([1, 2, 3])
ax.set_xticklabels(['对照组', '处理 A', '处理 B'])
fig.savefig('violin.png', dpi=300, bbox_inches='tight')
plt.close(fig)

保存图形

python
fig.savefig('figure.png', dpi=300, bbox_inches='tight')   # 光栅图
fig.savefig('figure.svg', bbox_inches='tight')              # 矢量图(可编辑)
fig.savefig('figure.pdf', bbox_inches='tight')              # 矢量图(可打印)

期刊级质量图形标准

尺寸预设(宽 x 高):

  • single_column: (8.5/2.54, 7/2.54) — 8.5 x 7 cm
  • one_half_column: (12/2.54, 9/2.54) — 12 x 9 cm
  • double_column: (17.5/2.54, 10/2.54) — 17.5 x 10 cm
  • presentation: (25/2.54, 18/2.54) — 25 x 18 cm

期刊调色板:

python
PALETTES = {
    'NPG': ["#E64B35", "#4DBBD5", "#00A087", "#3C5488", "#F39B7F", "#8491B4", "#91D1C2", "#DC0000", "#7E6148", "#B09C85"],
    'Lancet': ["#00468B", "#ED0000", "#42B540", "#0099B4", "#925E9F", "#FDAF91", "#AD002A", "#ADB6B6"],
    'JCO': ["#0073C2", "#EFC000", "#868686", "#CD534C", "#7AA6DC", "#003C67", "#8F7700", "#3B3B3B"],
    'NEJM': ["#BC3C29", "#0072B5", "#E18727", "#20854E", "#7876B1", "#6F99AD", "#FFDC91", "#EE4C97"],
}

文件命名: 使用几个月后人类仍能理解的描述性名称:

  • km_survival_thbs2_high_vs_low.png(而不是 figure1.png
  • volcano_plot_deseq2_tumor_vs_normal.png(而不是 plot.png
  • forest_plot_meta_analysis.pdf(而不是 result.pdf

最佳实践

  1. 对于无头环境,务必在导入 pyplot 之前使用 matplotlib.use('Agg')
  2. 使用 fig, ax = plt.subplots()(面向对象接口)而不是 plt.plot()(状态机)。
  3. 保存后调用 plt.close(fig) 以释放内存。
  4. 使用 bbox_inches='tight' 避免标签被裁剪。
  5. 出版图形设置 dpi=300,屏幕显示设置 dpi=150
  6. 使用来自 matplotlib.colormaps 的颜色映射(避免 jet;优先使用 viridis、coolwarm)。
  7. 绝不要保存到 /tmp/ 保存到项目工作区目录以确保持久性。
  8. 保存后务必报告完整的输出路径,以便用户找到文件。