zcbot/skills/plot_pub/SKILL.md

169 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: plot_pub
description: 出版级 matplotlib 绘图(论文 / 报告 / 申报书用,中文字体 + viridis 配色 + dpi 设定一键到位)。✅ 触发:用户要画 XRD 谱、TG-DSC 曲线、应力-应变曲线、SEM 标注、多 panel 学术图、要 SVG/PDF 矢量图给论文。⛔ 不触发:PPT 内嵌图(走 `ppt` skill 的 matplotlib 配图流程);只要快速看一眼数据(直接 `df.plot()` 即可,不用本 skill)。
---
# plot_pub
服务建材院的论文 / 申报书 / 调研报告出图。**核心是 `apply_pub_style()` 一键设置 rcParams**(中文字体、viridis 默认、字号、dpi、矢量优先),避免每次手动设置十几行还忘配中文字体。
## 何时用
- 写论文要投 *Cement and Concrete Research* / *J. Am. Ceram. Soc.* / *Construction and Building Materials* 等期刊
- 报告 / 申报书要中文标题 + 中文图例的高 dpi 图
- 多组样本数据对比(XRD 多谱叠图、强度发展曲线、温度场)
- 双 Y 轴(TG-DSC 是典型)
## 何时不用
- PPT 里要嵌图 → 走 `skills/ppt`(那边已经有配色 / 尺寸规范)
- 交互式探查数据 → 用 plotly / 直接 jupyter
- 只要看趋势不出版 → `df.plot()` 一行搞定,不用本 skill 的 ceremony
## 准备
```python
from skills.plot_pub.style import apply_pub_style
import matplotlib.pyplot as plt
import numpy as np
apply_pub_style() # 调一次,后面所有 plt 都按这个 style
```
## `apply_pub_style()` 参数
| 参数 | 默认 | 说明 |
|---|---|---|
| `chinese` | `True` | 加载 SimHei / Microsoft YaHei,中文不显示方块 |
| `dpi` | `150` | 屏幕显示 dpi;保存图用 `savefig(..., dpi=300)` 单独控 |
| `font_size` | `10` | 论文双栏图标准字号 |
| `linewidth` | `1.2` | 线粗,出版图细些显精致 |
| `cmap` | `"viridis"` | 默认 colormap,**审稿人不会喷**(jet 现在是雷区) |
## 典型工作流
### A. XRD pattern(多相叠图 + 标峰)
```python
from skills.plot_pub.style import apply_pub_style
import matplotlib.pyplot as plt
import numpy as np
apply_pub_style()
fig, ax = plt.subplots(figsize=(6, 4))
# 实测谱
ax.plot(two_theta_exp, intensity_exp, "k-", lw=1.0, label="实测")
# 理论谱(各物相,用 pymatgen XRDCalculator 算的)
for phase, pattern in pymatgen_patterns.items():
ax.vlines(pattern.x, 0, pattern.y / pattern.y.max() * intensity_exp.max() * 0.3,
label=phase, alpha=0.7)
ax.set_xlabel(r"$2\theta$ / °")
ax.set_ylabel("强度 / a.u.")
ax.set_xlim(5, 80)
ax.legend(frameon=False, loc="upper right")
fig.tight_layout()
fig.savefig("xrd_compare.pdf", bbox_inches="tight") # PDF 矢量,期刊偏好
fig.savefig("xrd_compare.png", dpi=300, bbox_inches="tight") # PNG 给 PPT
plt.close(fig) # 关键!run_python 多任务下不关会堆 figure 泄漏内存
```
### B. TG-DSC 双 Y 轴
```python
fig, ax_tg = plt.subplots(figsize=(6, 4))
ax_dsc = ax_tg.twinx()
ax_tg.plot(T, tg_mass, "b-", lw=1.2, label="TG")
ax_dsc.plot(T, dsc_flow, "r-", lw=1.2, label="DSC")
ax_tg.set_xlabel("温度 / °C")
ax_tg.set_ylabel("质量 / %", color="b")
ax_dsc.set_ylabel("热流 / mW·mg$^{-1}$", color="r")
ax_tg.tick_params(axis="y", labelcolor="b")
ax_dsc.tick_params(axis="y", labelcolor="r")
# 合并两个 ax 的 legend
lines1, labels1 = ax_tg.get_legend_handles_labels()
lines2, labels2 = ax_dsc.get_legend_handles_labels()
ax_tg.legend(lines1 + lines2, labels1 + labels2, loc="best", frameon=False)
fig.tight_layout()
fig.savefig("tg_dsc.pdf", bbox_inches="tight")
plt.close(fig)
```
### C. 多组样本对比(强度发展曲线)
```python
fig, ax = plt.subplots(figsize=(6, 4))
ages = [3, 7, 14, 28, 56, 90]
# 用 viridis 给多个样本上色,顺序色觉友好
import matplotlib.cm as cm
colors = cm.viridis(np.linspace(0.1, 0.9, len(samples)))
for (label, strengths), c in zip(samples.items(), colors):
ax.plot(ages, strengths, "o-", color=c, lw=1.2, ms=5, label=label)
ax.set_xlabel("龄期 / d")
ax.set_ylabel("抗压强度 / MPa")
ax.set_xscale("log") # 龄期用对数刻度更清楚
ax.legend(frameon=False)
ax.grid(True, ls="--", alpha=0.3)
fig.tight_layout()
fig.savefig("strength_dev.pdf", bbox_inches="tight")
plt.close(fig)
```
### D. 多 panel(2×2 figure,论文 figure 1 标配)
```python
fig, axes = plt.subplots(2, 2, figsize=(10, 7), constrained_layout=True)
axes[0, 0].plot(...) # (a) XRD
axes[0, 1].plot(...) # (b) FTIR
axes[1, 0].plot(...) # (c) TG
axes[1, 1].plot(...) # (d) 强度
# 子图编号(论文图 1 标准做法)
for ax, letter in zip(axes.flat, "abcd"):
ax.text(0.02, 0.95, f"({letter})", transform=ax.transAxes,
fontweight="bold", va="top")
fig.savefig("fig1_characterization.pdf", bbox_inches="tight")
plt.close(fig)
```
## 中文字体配置(Windows 注意)
`apply_pub_style(chinese=True)` 默认按以下顺序找字体:
1. `SimHei`(Windows 自带,黑体)
2. `Microsoft YaHei`(Windows 自带,雅黑)
3. `WenQuanYi Micro Hei`(Linux 兜底)
都没有 → 退回 DejaVu Sans,中文显示方块。装字体方式:Windows 控制面板 → 字体,丢 .ttf 进去。
**LaTeX 公式渲染**:matplotlib 用 `$...$` 自动走 mathtext,中英文混排正常。要更精细的 LaTeX(自定义 macro)就 `plt.rcParams["text.usetex"] = True`,但要本地装 TeX Live。
## 反模式
1. **用 pyplot 状态机不用 OO 接口** —— 写 `plt.plot(); plt.xlabel(...)` 一时爽,多 figure 时变量乱;一律 `fig, ax = plt.subplots()`
2. **不 close figure** —— `run_python` 跑多次会堆 figure 内存涨,必须 `plt.close(fig)` 收尾
3. **用 jet colormap** —— 色觉障碍审稿人会喷,近年期刊都偏 viridis / plasma / cividis
4. **保存图不 `bbox_inches="tight"`** —— legend / 标题被裁掉,反复看图反复改尺寸
5. **同图 dpi 跟 figsize 不匹配** —— figsize=(10,7) dpi=300 给 PPT 嵌入太大,字会很小;论文图 figsize=(6,4) 双栏刚好
6. **PNG 给论文** —— 期刊要矢量,PDF / SVG / EPS 优先;PNG 只给 PPT / 网页
7. **中文显示方块还坚持跑** —— `apply_pub_style()` 失败会 warn,看到 warning 就停下查字体
8. **legend 框线 / 灰底** —— 出版图 `legend(frameon=False)`,干净
9. **轴标签没单位** —— `"温度"` 是错的,`"温度 / °C"` 才对(SI 推荐 `/` 分隔)
10. **`ax.set_xticks([1,2,3,...])` 手动写一堆** —— matplotlib 自动 tick 已经足够,手动覆盖只在特殊场景(对数轴 / 离散类别轴)
## 依赖
matplotlib 已经在 `requirements.txt`(>=3.8.0)。本 skill 无新增依赖。