当前位置:首页>python>用Python做科研级画图——哑铃图

用Python做科研级画图——哑铃图

  • 2026-09-24 22:21:37
用Python做科研级画图——哑铃图

大家好,我是你们的小帅学长。

有一种场景,在论文和报告里出现频率极高:改进前 vs 改进后、实验组 vs 对照组、男 vs 女、模型A vs 模型B……

这时候你真正想表达的,其实不是“各自多高”,而是它们差多少。但很多人还是会用分组柱状图。结果是什么?读者/审稿人要先看左柱,再看右柱,再自己在脑子里做减法。

而有一种图,可以把“减法”直接画出来:哑铃图(Dumbbell plot)。两个点,一条线。差异就在那条线的长度里。

01.为什么哑铃图更直观?

柱状图强调的是“绝对值”。哑铃图强调的是“差值”。

在视觉感知上,柱状图是比较两根长度;哑铃图是比较一条线的长度。

而人类对“线段长度差异”的判断,远比对“面积差异”更敏感。

02.哑铃图适合什么场景?

场景 1:前后变化

政策实施前后、模型优化前后、训练前后指标变化……

哑铃图可以清楚表达“增长”还是“下降”。

场景 2:两组对比

男 vs 女、城市 vs 农村、方法A vs 方法B……

尤其当类别很多时(比如 8–15 个),哑铃图会比柱状图清爽得多。

场景 3:强调改进幅度

如果你想表达:新方法整体提升明显,那哑铃图能把“提升方向”视觉化。

03.哑铃图的结构逻辑

一张标准的哑铃图包含:左点(组1)、右点(组2)、中间连接线(差异)

它本质上是:横向点图 + 连线

如果你熟悉上一期的Dot plot,那你会发现哑铃图只是“多一个点+一条线”。

04.哑铃图模板(排序 + 水平布局)

import osimport numpy as npimport matplotlib as mplimport matplotlib.pyplot as pltfrom matplotlib import font_manager as fmfrom matplotlib.ticker import MaxNLocator, FormatStrFormatter# == 字体设置 ==win_fonts = r"C:\Windows\Fonts"for p in [          os.path.join(win_fonts, "times.ttf"),         os.path.join(win_fonts, "timesbd.ttf"),          os.path.join(win_fonts, "timesi.ttf"),          os.path.join(win_fonts, "simsun.ttc"),]:      if os.path.exists(p):                    try:                             fm.fontManager.addfont(p)                    except Exception:                            passmpl.rcParams["font.family"] = ["Times New Roman", "SimSun"]mpl.rcParams["axes.unicode_minus"] = FalseOUT_DIR = r"D:\py_figs "os.makedirs(OUT_DIR, exist_ok=True)# == 示例数据 ==labels = [        "Model A / 模型A",         "Model B / 模型B",         "Model C / 模型C",         "Model D / 模型D",       "Model E / 模型E"]before = np.array([0.78, 0.82, 0.75, 0.80, 0.77])after  = np.array([0.86, 0.88, 0.83, 0.85, 0.84])# == 按差值排序 ==diff = after - beforeorder = np.argsort(diff)[::-1]labels_s = [labels[i] for i in order]before_s = before[order]after_s  = after[order]fig, ax = plt.subplots(figsize=(7.2, 4.2))y = np.arange(len(labels_s))# 连接线for yi, b, a in zip(y, before_s, after_s):    ax.plot([b, a], [yi, yi], linewidth=1.5)# 两端点ax.scatter(before_s, y, s=70, label="Before / 优化前")ax.scatter(after_s,  y, s=70, label="After / 优化后")ax.set_yticks(y)ax.set_yticklabels(labels_s, fontsize=11)ax.set_xlabel("Accuracy / 准确率", fontsize=12)ax.set_title("Dumbbell Plot:两组差异一眼看清", fontsize=14)ax.invert_yaxis()ax.set_xlim(left=0.7)ax.xaxis.set_major_locator(MaxNLocator(nbins=6))ax.xaxis.set_major_formatter(FormatStrFormatter("%.2f"))ax.legend(frameon=False)out_path = os.path.join(OUT_DIR, "dumbbell_plot_basic.jpg")fig.savefig(out_path, dpi=300, bbox_inches="tight", pad_inches=0.05)plt.close(fig)print("Saved:", out_path)

05.哑铃图 vs 分组柱:谁更好?

情况
推荐
强调绝对值规模
分组柱
强调两组差异
哑铃图
类别很多
哑铃图
想要更清爽版面

哑铃图

分组柱强调“两个柱子”,哑铃图强调“中间那条线”。

如果你真正关心的是“差多少”,就不要再让读者自己做减法——把差异画出来。哑铃图让对比更诚实,也更直接。

下一篇我们进入分布表达:《直方图》。很多人画直方图时最头疼的问题是:bin 到底该设多少?太少看不出结构,太多全是噪声。下一篇,我会给你一套清晰可用的 bin 选择规则,而不是“凭感觉”。

——期待你的关注——

往期内容:

用Python做科研级画图——点图替代柱状

用Python做科研级画图——分组对比

用Python做科研级画图——折线图基础模板

用Python做科研级画图——配色与色带:连续离散怎么选

用Python做科研级画图——标注与强调:箭头/框/高亮怎么用

最新文章

随机文章