论文级图表示例 · 可直接复制的 matplotlib 模板 · 配色与工具素材
按论文结构分四块:A 组基础模板与顶会案例、B 组主实验对比、C 组消融分析。卡片默认折叠,点标题展开图例与完整 matplotlib 代码,复制即用。配色统一采用 Okabe-Ito 色盲友好方案。
分组直达:A · 方法与流程B · 实验结果C · 消融与分析绘制方法论
论文 Method 章节的流程图与架构图,用 matplotlib 的 Patch 与箭头即可画,无需切换到其他工具。
方法章节的门面。横向四到六个模块最顺口,核心创新模块用主题色描边提亮,数据规模写进框内,读者十秒看懂全流程。
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
stages = [
("Raw QA Pairs", "858 pairs", False),
("Rule Filtering", "schema rules", True),
("Ontology Align", "KG mapping", True),
("SFT Dataset", "611 pairs", False),
]
fig, ax = plt.subplots(figsize=(7.16, 1.9))
ax.set_xlim(0, 10)
ax.set_ylim(0, 3)
ax.axis("off")
for i, (title, sub, hot) in enumerate(stages):
x = 0.25 + i * 2.55
ax.add_patch(FancyBboxPatch(
(x, 1.0), 1.9, 1.0, boxstyle="round,pad=0.06",
facecolor="#e9f3fa" if hot else "#f6f8fa",
edgecolor="#0072B2" if hot else "#d0d7de",
linewidth=1.5 if hot else 1.0))
ax.text(x + 0.95, 1.66, title, ha="center", fontsize=9.5)
ax.text(x + 0.95, 1.30, sub, ha="center", fontsize=7.5,
color="#57606a")
if i < 3:
ax.annotate("", xy=(x + 2.52, 1.5), xytext=(x + 2.02, 1.5),
arrowprops=dict(arrowstyle="-|>",
color="#57606a", lw=1.2))
fig.savefig("fig_pipeline.pdf")
模型结构用纵向堆叠最直观,数据流自下而上。重复层收进虚线框加 ×N,左侧标注张量形状,结构与维度变化一图说完。
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, Rectangle
def block(ax, x, y, w, h, text, fc="#f6f8fa", ec="#d0d7de"):
ax.add_patch(FancyBboxPatch((x, y), w, h,
boxstyle="round,pad=0.05",
facecolor=fc, edgecolor=ec))
ax.text(x + w / 2, y + h / 2, text,
ha="center", va="center", fontsize=9.5)
fig, ax = plt.subplots(figsize=(3.5, 4.6))
ax.set_xlim(0, 6)
ax.set_ylim(0, 9)
ax.axis("off")
block(ax, 1.8, 0.3, 2.4, 0.62, "Input Tokens")
block(ax, 1.8, 1.5, 2.4, 0.62, "Token + Position Embedding")
ax.add_patch(Rectangle((1.55, 2.75), 2.9, 3.2, fill=False,
edgecolor="#8b949e", linestyle="--"))
block(ax, 1.8, 4.9, 2.4, 0.8, "Multi-Head Attention",
fc="#e9f3fa", ec="#0072B2")
block(ax, 1.8, 3.15, 2.4, 0.8, "Feed-Forward Network",
fc="#e9f3fa", ec="#0072B2")
ax.text(4.65, 4.35, "× N", fontsize=12, style="italic")
block(ax, 1.8, 6.6, 2.4, 0.62, "LM Head + Softmax")
ax.text(3.0, 8.35, "Next-token Probabilities",
ha="center", fontsize=9.5, color="#57606a")
for y0, y1 in [(0.92, 1.5), (2.12, 2.75), (5.95, 6.6), (7.22, 8.1)]:
ax.annotate("", xy=(3.0, y1), xytext=(3.0, y0),
arrowprops=dict(arrowstyle="-|>",
color="#57606a", lw=1.2))
for y, s in [(0.61, "B × L"), (1.81, "B × L × d"),
(5.3, "B × L × d"), (6.91, "B × L × V")]:
ax.text(1.5, y, s, ha="right", va="center",
fontsize=7.5, color="#8b949e")
fig.savefig("fig_arch.pdf")
以下十张是简化重绘的示意图(原图版权归属各论文),分析只谈绘图技法:构图、流向、配色、抽象粒度。所有手法都能用 matplotlib 或 draw.io 复现。
👉 想看 原始论文里的真图?已整理 14 张案例库 · 按构图类型分组 →
RLHF 三阶段图是近年被引用最多的 pipeline 图之一,结构极简却信息完整。
预训练与微调画成左右镜像双子图,用「图元复用」表达参数共享,是双阶段方法的标准画法。
被引超十万的架构图。对称构图中唯一的斜线就是创新点,值得逐像素学习。
双流编码加相似度矩阵的构图被后续所有对比学习论文沿用,矩阵本身就是结果的可视化。
扩散模型的链式图把「状态随时间演化」直接演在节点里,前向与反向两个过程零交叉共存。
「一张图等于 16×16 个词」的成名图:把二维图像折叠成一维 token 序列,矩阵到序列的降维全靠图元平铺表达。
few-shot 缩放的招牌图:同构坐标的小面板平铺,一张图同时回答「规模涨有没有用」与「不同任务涨幅差多少」。
回应「你的算法太复杂」最有力的方式:上下两栏管线图,上栏 RLHF 框多线绕,下栏 DPO 一条线走完,复杂度对比不证自明。
稀疏 MoE 的入门图:token 进 Router,从一排同构 expert 里点亮一个,其余保持灰虚线,「每 token 只走一条路」由图面自明。
一道食堂算术题左右开箱:左边标准提示一步答错,右边思维链分步答对,CoT 的全部卖点压缩在两个输出框的高度差里。
主实验章节的对比图,回答「我的方法比基线好多少」。
多方法对比的主图。主线用实线加置信带,基线用虚线压低视觉权重,读者一眼锁定你的方法。
import numpy as np
import matplotlib.pyplot as plt
epochs = np.arange(0, 51)
okc = 34.4 - (34.4 - 15.6) * (1 - np.exp(-epochs / 8))
qa = 34.4 - 6.4 * (1 - np.exp(-epochs / 20))
base = np.full_like(epochs, 34.4)
fig, ax = plt.subplots(figsize=(3.5, 2.6))
ax.fill_between(epochs, okc - 1.2, okc + 1.2,
color="#0072B2", alpha=0.15, linewidth=0)
ax.plot(epochs, okc, color="#0072B2", lw=1.8, label="OKC-SFT (ours)")
ax.plot(epochs, qa, color="#E69F00", lw=1.4, label="QA-SFT baseline")
ax.plot(epochs, base, color="#999999", lw=1.1, ls="--", label="Base model")
ax.set_xlabel("Training Steps (epoch)")
ax.set_ylabel("Hallucination Rate (%)")
ax.set_ylim(10, 38)
ax.spines[["top", "right"]].set_visible(False)
ax.grid(axis="y", lw=0.6, color="#e5e9ee")
ax.set_axisbelow(True)
ax.legend(loc="upper right")
fig.savefig("fig1_curve.pdf")
离散指标对比的首选。柱顶直接标数值,读者不用回头对着 y 轴估读;组内顺序在全篇论文中保持一致。
import numpy as np
import matplotlib.pyplot as plt
metrics = ["Accuracy", "Coverage", "Integrity", "Executability"]
scores = {
"OKC-SFT": [92, 74, 99.8, 98],
"QA-SFT": [85, 68, 97, 90],
"Base": [71, 52, 90, 64],
}
colors = ["#0072B2", "#E69F00", "#BBBBBB"]
x = np.arange(len(metrics))
width = 0.26
fig, ax = plt.subplots(figsize=(3.5, 2.6))
for i, (name, vals) in enumerate(scores.items()):
bars = ax.bar(x + (i - 1) * width, vals, width,
label=name, color=colors[i])
ax.bar_label(bars, fmt="%.4g", padding=2, fontsize=7)
ax.set_ylabel("Score (%)")
ax.set_xticks(x, metrics)
ax.set_ylim(0, 112)
ax.spines[["top", "right"]].set_visible(False)
ax.grid(axis="y", lw=0.6, color="#e5e9ee")
ax.set_axisbelow(True)
ax.legend(loc="upper right", ncols=3, columnspacing=0.9)
fig.savefig("fig2_bar.pdf")
两个对象五维以内时清晰好用。维度超过六个或对象超过三个就该换柱状图,面积重叠会失去可读性。
import numpy as np
import matplotlib.pyplot as plt
dims = ["Capability", "Preference", "Context", "Cost Eff.", "Speed"]
model_a = [0.90, 0.60, 0.85, 0.50, 0.70]
model_b = [0.70, 0.85, 0.60, 0.80, 0.55]
angles = np.linspace(0, 2 * np.pi, len(dims), endpoint=False)
angles = np.concatenate([angles, angles[:1]])
fig, ax = plt.subplots(figsize=(3.2, 3.0),
subplot_kw=dict(polar=True))
ax.set_theta_offset(np.pi / 2)
ax.set_theta_direction(-1)
for vals, color, name in [(model_a, "#0072B2", "Model A"),
(model_b, "#E69F00", "Model B")]:
v = np.concatenate([vals, vals[:1]])
ax.plot(angles, v, color=color, lw=1.6, label=name)
ax.fill(angles, v, color=color, alpha=0.15)
ax.set_xticks(angles[:-1], dims)
ax.set_ylim(0, 1)
ax.set_yticks([0.25, 0.5, 0.75, 1.0])
ax.set_yticklabels([])
ax.grid(lw=0.6, color="#e5e9ee")
ax.spines["polar"].set_color("#e5e9ee")
ax.legend(loc="upper right", bbox_to_anchor=(1.35, 1.1))
fig.savefig("fig4_radar.pdf")
参数量与指标的幂律关系是对数轴散点的经典场景。散点给原始观测,直线给拟合趋势,log-log 坐标下幂律天然呈直线。
import numpy as np
import matplotlib.pyplot as plt
params = np.array([0.3, 1, 3, 10, 30, 90])
loss_a = np.array([3.60, 3.20, 2.90, 2.65, 2.45, 2.30])
loss_b = np.array([3.90, 3.60, 3.30, 3.05, 2.85, 2.70])
def fit_line(p, l):
k, b = np.polyfit(np.log10(p), l, 1)
xs = np.logspace(np.log10(p.min()), np.log10(p.max()), 50)
return xs, k * np.log10(xs) + b
fig, ax = plt.subplots(figsize=(3.5, 2.6))
ax.scatter(params, loss_a, s=16, color="#0072B2", zorder=3,
label="Compute-optimal")
ax.scatter(params, loss_b, s=16, marker="s", color="#E69F00",
zorder=3, label="Under-trained")
ax.plot(*fit_line(params, loss_a), color="#0072B2", lw=1.4)
ax.plot(*fit_line(params, loss_b), color="#E69F00", lw=1.4)
ax.set_xscale("log")
ax.set_xlabel("Parameters (B)")
ax.set_ylabel("Validation Loss")
ax.set_ylim(2.0, 4.1)
ax.spines[["top", "right"]].set_visible(False)
ax.grid(axis="y", lw=0.6, color="#e5e9ee")
ax.set_axisbelow(True)
ax.legend(loc="lower left")
fig.savefig("fig_scaling.pdf")
消融、稳定性与敏感性分析章节的配图,回答「每个部件是否有用、结果是否稳健」。
矩阵类数据的标配。单色渐变比彩虹色更专业,数值直接写进格子,色条只作辅助参照。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
cm = np.array([
[0.92, 0.04, 0.02, 0.01, 0.01],
[0.06, 0.85, 0.05, 0.03, 0.01],
[0.03, 0.07, 0.88, 0.02, 0.00],
[0.01, 0.03, 0.04, 0.90, 0.02],
[0.01, 0.01, 0.02, 0.05, 0.91],
])
cmap = LinearSegmentedColormap.from_list(
"paper", ["#f6f8fa", "#0072B2"])
fig, ax = plt.subplots(figsize=(3.2, 2.8))
im = ax.imshow(cm, cmap=cmap, vmin=0, vmax=1)
for i in range(5):
for j in range(5):
ax.text(j, i, f"{cm[i, j]:.2f}", ha="center", va="center",
fontsize=7,
color="white" if cm[i, j] > 0.5 else "#57606a")
ax.set_xticks(range(5), list("ABCDE"))
ax.set_yticks(range(5), list("ABCDE"))
ax.set_xlabel("Predicted Class")
ax.set_ylabel("True Class")
fig.colorbar(im, ax=ax, shrink=0.85)
fig.savefig("fig3_heatmap.pdf")
只报一个数没有说服力。跑 5 到 30 个种子画箱线图,中位数、离散程度与离群点一图讲清,比文字罗列均值方差直观得多。
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(42)
data = {
"Base": rng.normal(88.0, 2.5, 30),
"+Aug": rng.normal(86.5, 3.0, 30),
"+OKC": rng.normal(90.5, 1.8, 30),
"Full": rng.normal(92.5, 1.2, 30),
}
fig, ax = plt.subplots(figsize=(3.5, 2.6))
bp = ax.boxplot(data.values(), widths=0.5, patch_artist=True,
flierprops=dict(marker="o", markersize=3,
markerfacecolor="white",
markeredgecolor="#8b949e"))
colors = ["#BBBBBB", "#E69F00", "#0072B2", "#009E73"]
for patch, c in zip(bp["boxes"], colors):
patch.set(facecolor=c, alpha=0.85, edgecolor="none")
for med in bp["medians"]:
med.set(color="white", linewidth=1.5)
ax.set_xticklabels(data.keys())
ax.set_ylabel("Accuracy (%)")
ax.set_xlabel("Method")
ax.grid(axis="y", linewidth=0.5, alpha=0.4)
ax.set_axisbelow(True)
ax.spines[["top", "right"]].set_visible(False)
fig.savefig("fig_stability_boxplot.pdf")
审稿人常问「结果对超参有多敏感」。共享坐标轴的 2x2 小倍数图,一眼看出最优区间是否宽、峰值出现在哪。共享 y 轴让四个面板可以直接横向比较。
import numpy as np
import matplotlib.pyplot as plt
lrs = [1e-4, 3e-4, 1e-3, 3e-3, 1e-2]
accs = {
"depth 12": [85.1, 86.8, 87.9, 86.2, 83.5],
"depth 18": [85.8, 87.9, 89.1, 87.4, 84.0],
"depth 24": [85.9, 88.4, 89.8, 87.0, 83.2],
"depth 30": [85.2, 87.6, 88.9, 85.8, 81.4],
}
fig, axes = plt.subplots(2, 2, figsize=(7.16, 4.4),
sharex=True, sharey=True)
for ax, (name, acc) in zip(axes.flat, accs.items()):
ax.plot(lrs, acc, marker="o", markersize=3.5,
linewidth=1.4, color="#0072B2")
best = int(np.argmax(acc))
ax.plot(lrs[best], acc[best], marker="o", markersize=7,
markerfacecolor="none", markeredgecolor="#D55E00",
markeredgewidth=1.4)
ax.set_xscale("log")
ax.set_title(name, fontsize=9)
ax.grid(linewidth=0.5, alpha=0.4)
ax.set_axisbelow(True)
fig.supxlabel("Learning Rate (log scale)")
fig.supylabel("Accuracy (%)")
fig.tight_layout()
fig.savefig("fig_sensitivity_panels.pdf")
部署场景的标准叙事图。前沿线上的模型才有资格进对比表,灰色区域的点被直接淘汰。左上是更好的方向,阴影标出被支配区域。
import numpy as np
import matplotlib.pyplot as plt
# (latency_ms, accuracy)
models = [
(40, 88.0), (60, 90.0), (90, 91.5), (150, 92.8), (260, 93.5),
(120, 89.0), (180, 90.5), (230, 91.0), (100, 87.0), (300, 92.0),
]
def pareto_front(points):
front, best = [], -np.inf
for x, y in sorted(points):
if y > best:
front.append((x, y))
best = y
return front
front = pareto_front(models)
fx, fy = zip(*front)
lat = [m[0] for m in models]
acc = [m[1] for m in models]
fig, ax = plt.subplots(figsize=(3.5, 2.8))
ax.fill_between(fx, fy, 86, color="#f0f1f3", zorder=1)
ax.scatter(lat, acc, s=26, c="#BBBBBB", zorder=2,
label="Dominated")
ax.plot(fx, fy, ls="--", color="#D55E00",
linewidth=1.2, zorder=3)
ax.scatter(fx, fy, s=36, c="#0072B2", zorder=4,
label="Pareto front")
ax.set_xlabel("Latency (ms)")
ax.set_ylabel("Accuracy (%)")
ax.set_ylim(86, 94.5)
ax.legend(loc="lower right")
ax.grid(linewidth=0.5, alpha=0.4)
ax.set_axisbelow(True)
ax.spines[["top", "right"]].set_visible(False)
fig.savefig("fig_pareto.pdf")
上面的图例与案例解剖回答「好图长什么样」,这一节回答「怎么亲手画出来」。覆盖从白纸到投稿成稿的全过程,所有纪律与数据均有出处,来源附在节末。
想看真实论文原图(顶会截图)按构图类型分组的案例库,见 /pipeline/(15 张真图案例库)。
以 P1(InstructGPT 风格)为例,五步走一遍,照抄即可迁移到自己的方法图。
| 工具 | 最适合 | 优点 | 代价与导出 |
|---|---|---|---|
| draw.io | pipeline 框图 | 免费、图形库全、XML 可入 git 管理 | 精细排版能力一般;导出 SVG / PDF |
| PowerPoint | 快速出稿、组会图复用 | 上手零成本,大量顶会图出自 PPT | 对齐与复用弱;导 PDF 注意字体嵌入 |
| Figma | 双流对称结构、多人协作 | 组件复用、自动布局 | 需要账号;导出 SVG / PDF |
| TikZ | 需要嵌公式的图 | LaTeX 原生、精确、纯文本可 diff | 学习曲线陡、迭代慢 |
| matplotlib | 数据驱动图、简单框图 | 代码可复现、与实验图同源 | 复杂框图布局繁琐;导出 PDF / SVG |
| Inkscape | SVG 后处理、多图拼接 | 免费开源、路径编辑强 | 不适合从零起稿;导出 PDF / SVG |
| Excalidraw | 讨论期草图 | 手绘风上手最快 | 不适合成稿;导出 SVG / PNG |
pdf.fonttype=42。放在每个绘图脚本开头,所有图自动获得统一的论文级外观。
import matplotlib.pyplot as plt
plt.rcParams.update({
"font.family": "serif",
"font.serif": ["Times New Roman", "Songti SC"],
"mathtext.fontset": "stix",
"font.size": 9,
"axes.linewidth": 0.8,
"axes.labelsize": 9,
"xtick.labelsize": 8,
"ytick.labelsize": 8,
"xtick.direction": "in",
"ytick.direction": "in",
"legend.fontsize": 8,
"legend.frameon": False,
"figure.dpi": 150,
"savefig.dpi": 300,
"savefig.bbox": "tight",
"pdf.fonttype": 42, # 嵌入 TrueType,避免 Type 3 被期刊拒收
"ps.fonttype": 42,
})
| 项目 | 规范 | 说明 |
|---|---|---|
| 单栏图宽 | figsize=(3.5, h) | IEEE / ACM 单栏 3.5 in(约 8.9 cm) |
| 双栏图宽 | figsize=(7.16, h) | 通栏大图 7.16 in(约 18.2 cm) |
| 图高上限 | ≤ 9.2 in | 超过会被排版系统压缩 |
| 线图格式 | .pdf / .svg | 矢量优先,缩放不失真 |
| 位图分辨率 | dpi=300 | 热图、照片类 300 起步,投稿常要求 600 |
| 字体嵌入 | pdf.fonttype=42 | Type 3 字体会被多数出版方拒收 |
| 图内字号 | 7 ~ 9 pt | 与正文 caption 字号一致,插入后不再缩放 |
figsize 锁定最终插入论文的尺寸,字号就不会在排版时缩放失真。spines),网格只留 y 方向细线并压到数据层下方(set_axisbelow(True))。fill_between 画置信区间比 errorbar 的密针脚干净得多。\caption{},图内标题一律省略。点击色块复制 HEX。前四色即可覆盖绝大多数对比场景。
| 工具 | 用途 |
|---|---|
| matplotlib | Python 绘图底座,论文图的主力 |
| SciencePlots | pip install SciencePlots,一行 plt.style.use('science') 获得 Nature / IEEE 风格 |
| seaborn | 统计图封装,分布图与热力图出图快 |
| plotly | 交互图,适合网页展示与答辩 demo |
| draw.io | 架构图与流程图,导出 SVG 后可进 Illustrator 微调 |
| ColorBrewer | 地图与分组数据的经典配色生成器,附色盲安全标注 |