大数跨境

Python科研绘图——5类高频图型 × 从matplotlib默认样式到期刊级出图

Python科研绘图——5类高频图型 × 从matplotlib默认样式到期刊级出图 Ai尚研修
2026-11-10
2
导读:关注Ai尚研修公众号加星标🌟,不错过每一次学术干货!

许多科研工作者在使用 Matplotlib 绘图时,常面临“代码跑通但图表粗糙”的困境:线条偏细、配色单调、字号过小。这并非工具缺陷,而是其默认样式侧重于“快速预览”而非“论文投稿”。Matplotlib 支持高度自定义,本文针对科研场景,通过五类高频图表(折线图、柱状图、散点拟合、分布面积图、等高线图),演示“全局定调+局部微调”的专业绘图流程,所有代码均固定随机种子以确保结果可复现。

一、建立规范的科研绘图工作流

科研绘图的核心在于“数据驱动”与“可重复性”。面对数据更新或期刊模板调整,建议将绘图逻辑脚本化,实现数据与样式的彻底分离。推荐工作流如下:

图 0 科研绘图推荐工作流:脚本化 + 模板化 + 矢量导出
  • 数据统计分离:先使用 Pandas/NumPy 计算均值、SEM 等统计量,再导入绘图脚本;
  • 样式模板化:将字号、线宽、配色封装为 rcParams 模板,全局复用;
  • 参数化出图:尺寸、布局、配色定义为变量,实现“改一处,全局生效”;
  • 规范导出:投稿首选 PDF/SVG/EPS 矢量格式,汇报使用 600 dpi TIFF,网页展示使用 PNG。

二、配置全局样式模板

为避免重复设置,建议预先定义全局配置。以下模板去除了上右边框,统一了刻度与网格样式,符合多数期刊的“安全基线”要求:

import matplotlib.pyplot as plt

plt.rcParams.update({
    'font.size': 11,            # 正文字号,与论文正文协调
    'axes.linewidth': 1.2,      # 坐标轴线宽
    'axes.spines.top': False,   # 去掉上、右边框
    'axes.spines.right': False,
    'lines.linewidth': 2.0,     # 默认线宽
    'xtick.direction': 'out',   # 刻度朝外
    'ytick.direction': 'out',
    'grid.linestyle': '--',     # 网格虚线
    'grid.alpha': 0.25,
    'legend.frameon': False,    # 图例无边框
    'figure.dpi': 150,          # 屏幕显示分辨率
    'savefig.bbox': 'tight',    # 保存时去除白边
})

注:英文期刊常用 Arial 或 Helvetica,中文图注可用宋体。若期刊指定 Times New Roman,只需在模板中增加 font.family 设置即可全局生效。

三、案例实战

案例 1:多曲线折线图(对比实验的时间/剂量响应)

折线图是论文中最常见的图型。默认样式往往线条过细且缺乏区分度。优化策略包括:加粗线条、使用不同形状标记、并为标记添加白色描边以提升层次感。

图 1-1 Matplotlib 默认效果:线细、无标记、难以区分

import numpy as np
import matplotlib.pyplot as plt

PAL = ['#0F4C81', '#E4572E', '#F2A104'] # 自建配色
np.random.seed(7) # 固定随机种子

x = np.linspace(0, 2*np.pi, 120)
y1 = np.sin(2*x) * np.exp(-x/6) # 阻尼振荡
y2 = np.cos(x) * x / np.pi
y3 = np.tanh(x - np.pi) * 2.2

fig, ax = plt.subplots(figsize=(6.5, 4.5))
markers = ['o', 's', '^']
labels = ['damped sin(2x)·e$^{-x/6}$', 'x·cos(x)/$\pi$', '2.2·tanh(x−$\pi)$']

for y, m, lab, c in zip([y1, y2, y3], markers, labels, PAL):
    ax.plot(x, y, color=c, lw=2.2, marker=m, markevery=12, ms=8,
            mfc=c, mec='white', mew=1.2, label=lab) # 白描边标记

ax.set(xlim=(0, 2*np.pi), xlabel='X-Label', ylabel='Y-Label',
       title='Polished line chart')
ax.grid(True); ax.legend()
fig.savefig('line.pdf') # 矢量导出

图 1-2 期刊级效果:加粗线条 + 形状区分 + 白描边标记

  • markevery=12:每隔12个数据点放置一个标记,避免密集重叠;
  • mec='white':标记加白色描边,确保曲线交叉处清晰可辨;
  • 标记形状与颜色双重编码,即使黑白打印也能有效区分。

案例 2:分组柱状图 + 误差棒 + 原始散点

越来越多的期刊要求展示“均值 ± 误差”的同时叠加原始数据点。Matplotlib 可兼容 bar() 与 scatter(),实现数据透明化展示。

图 2-1 Matplotlib 默认效果:样式单调、无原始数据

np.random.seed(11)
cats = ['Cat-A', 'Cat-B', 'Cat-C', 'Cat-D']
base = np.array([[3.2, 2.9, 2.7, 2.8],
                 [1.8, 2.2, 1.7, 1.5],
                 [4.3, 4.1, 3.8, 4.9]])

# 生成模拟数据
raw = np.stack([np.random.normal(base[g], 0.42, size=(6, 4)) for g in range(3)])
mean = raw.mean(axis=1)
sem = raw.std(axis=1, ddof=1) / np.sqrt(raw.shape) # SEM

fig, ax = plt.subplots(figsize=(7, 4.8))
w, xp = 0.24, np.arange(4)

for g in range(3):
    # 绘制柱状图与误差棒
    ax.bar(xp + (g-1)*w, mean[g], width=w*0.92, yerr=sem[g],
           capsize=5, color=PAL[g], edgecolor='black', lw=0.8,
           error_kw=dict(lw=1.2, capthick=1.2), label=f'Group-{g+1}', zorder=3)
    
    # 绘制原始散点(带抖动)
    xs = np.concatenate([np.full(6, xp[c] + (g-1)*w) for c in range(4)])
    xs = xs + np.random.normal(0, 0.035, size=xs.shape) # 水平抖动
    ax.scatter(xs, raw[g].T.flatten(), s=22, facecolor='white',
               edgecolor='black', lw=0.9, zorder=4)

ax.set_xticks(xp); ax.set_xticklabels(cats)
ax.set(xlim=(-0.5, 3.5), ylim=(0, 6.2), xlabel='X-Label',
       ylabel='Y-Label', title='Bar chart with SEM & raw points')
ax.grid(True, axis='y'); ax.legend()
fig.savefig('bar.pdf')

图 2-2 期刊级效果:分组配色 + SEM 误差棒 + 原始散点叠加

  • 务必在图注中注明误差棒类型(SEM 或 SD),二者含义不同;
  • 散点添加小幅水平抖动(jitter),既展示分布又不遮挡柱体;
  • 白底黑边散点在彩色柱体上对比强烈,是期刊插图的常见做法。

案例 3:散点 + 线性拟合 + 95% 置信带

在相关性分析中,“散点 + 拟合直线”比单纯的相关系数更直观。通过 scipy.stats.linregress 完成最小二乘拟合,并计算置信带,可将 R² 和 p 值直接标注于图中。

图 3-1 Matplotlib 默认效果:拟合信息缺失、样式平淡

from scipy import stats
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(23)
groups = [dict(x0=2.0, x1=3.6, slope=1.6, intercept=3.5, noise=2.6, n=48),
          dict(x0=3.6, x1=5.6, slope=2.8, intercept=-8.0, noise=2.2, n=60),
          dict(x0=5.0, x1=7.2, slope=0.9, intercept=0.5,  noise=2.4, n=55)]

PAL = ['#0F4C81', '#E4572E', '#F2A104']
fig, ax = plt.subplots(figsize=(7, 5))

for i, g in enumerate(groups):
    xs = np.random.uniform(g['x0'], g['x1'], g['n'])
    ys = g['slope']*xs + g['intercept'] + np.random.normal(0, g['noise'], g['n'])
    
    res = stats.linregress(xs, ys) # 最小二乘拟合
    xx = np.linspace(xs.min(), xs.max(), 200)
    yy = res.slope*xx + res.intercept
    
    # 计算 95% 置信带
    n, xmean = len(xs), xs.mean()
    se = np.sqrt(np.sum((ys-(res.slope*xs+res.intercept))**2)/(n-2))
    ci = stats.t.ppf(0.975, n-2)*se*np.sqrt(1/n+(xx-xmean)**2/np.sum((xs-xmean)**2))
    
    ax.fill_between(xx, yy-ci, yy+ci, color=PAL[i], alpha=0.15, lw=0)
    ax.plot(xx, yy, color=PAL[i], lw=2.5)
    ax.scatter(xs, ys, s=38, color=PAL[i], alpha=0.55, edgecolor='white', lw=0.6)
    
    # 标注统计量
    ptxt = 'p < 0.001' if res.pvalue < 0.001 else f"p = {res.pvalue:.3f}"
    ax.text(0.97, 0.93-i*0.07, f"Dataset-{i+1}:  R$^2$ = {res.rvalue**2:.3f},  {ptxt}",
            transform=ax.transAxes, ha='right', fontsize=11, color=PAL[i])

ax.set(xlabel='X-Label', ylabel='Y-Label', title='Scatter with OLS fit & 95% CI')
ax.grid(True)
fig.savefig('fit.pdf')

图 3-2 期刊级效果:拟合线 + 95% 置信带 + 统计量图上直标

  • 置信带越窄,说明拟合参数确定度越高;带宽随远离均值区域变宽是回归固有特性;
  • R² 与 p 值直接标注,便于审稿人快速评估统计显著性;
  • 散点使用半透明填充(alpha≈0.55),重叠区域颜色自然加深,隐含密度信息。

案例 4:分布面积图(多组数据形态对比)

比较粒径分布、响应强度等数据形态时,面积图比直方图更平滑。核心技巧是先画轮廓线,再填充半透明色。

图 4-1 Matplotlib 默认效果:配色生硬、无轮廓线

x = np.linspace(-8, 12, 400)
def gauss(x, mu, s, a=1.0): return a*np.exp(-(x-mu)**2/(2*s**2))

curves = [gauss(x, 5, 4.0), 
          0.6*gauss(x, 0, 1.0) + 0.4*gauss(x, 3.5, 1.8), 
          gauss(x, -3, 1.6, 0.85)]
labels = ['Normal(5, 4$^2$)', '0.6·N(0,1$^2$)+0.4·N(3.5,1.8$^2$)', '0.85·N(−3, 1.6$^2$)']
PAL = ['#0F4C81', '#E4572E', '#F2A104']

fig, ax = plt.subplots(figsize=(7, 4.6))
for c, lab, col in zip(curves, labels, PAL):
    ax.plot(x, c, color=col, lw=1.8)          # 先画轮廓线
    ax.fill_between(x, c, color=col, alpha=0.28, label=lab) # 再半透明填充

ax.set(xlim=(-8, 12), ylim=(0, None), xlabel='X-Label',
       ylabel='Y-Label', title='Filled distribution curves')
ax.grid(True); ax.legend(fontsize=9)
fig.savefig('area.pdf')

图 4-2 期刊级效果:轮廓线 + 半透明填充,分布形态一目了然

  • 填充透明度建议设置在 0.2–0.35,确保多条曲线叠加处仍可辨识;
  • 混合分布(如双峰)可用加权高斯叠加生成,比真实采样曲线更光滑,适合示意图。

案例 5:填充等高线(二维场分布可视化)

温度场、浓度场等二维数据,推荐使用 contourf 填充配合 contour 白线标注。注意保持坐标轴等比例(aspect='equal'),防止场结构变形。

图 5-1 Matplotlib 默认效果:色带突兀、无等高线

gx = np.linspace(-5, 5, 300); gy = np.linspace(-5, 5, 300)
X, Y = np.meshgrid(gx, gy)
# 三个高斯源项叠加模拟场分布
Z = (3.6*np.exp(-((X+2.2)**2/5 + (Y+1.2)**2/3))
     - 3.0*np.exp(-((X-2.0)**2/4.5 + (Y-1.8)**2/4))
     + 2.2*np.exp(-((X-3.0)**2/7 + (Y+3.0)**2/5))
     + 0.8*np.sin(X)*np.cos(Y))

fig, ax = plt.subplots(figsize=(7, 5.2))
cs = ax.contourf(X, Y, Z, levels=22, cmap='YlGnBu') # 渐变填充
ax.contour(X, Y, Z, levels=11, colors='white', lw=0.7, alpha=0.85) # 等高线

fig.colorbar(cs, ax=ax, pad=0.02, label='Z-Value')
ax.set(xlabel='X-Label', ylabel='Y-Label', title='Filled contour map')
ax.set_aspect('equal') # 关键:保持比例
fig.savefig('contour.pdf')

图 5-2 期刊级效果:YlGnBu 色盲友好渐变 + 白色等高线叠加

  • 推荐使用 YlGnBu、viridis 等色盲友好且黑白打印不失真的 colormap;
  • 填充层数 levels=22 可使色带过渡平滑,白线等高线辅助精确读数;
  • Colorbar 的 label 需注明单位和物理含义。

四、投稿前的导出设置

高质量的图表需要正确的导出方式支撑:

  • 矢量优先:PDF/SVG/EPS 在排版时可任意缩放不失真,是绝大多数期刊的首选;
  • 位图保底:使用 savefig('fig.tiff', dpi=600) 生成 600 dpi TIFF,满足高清要求;
  • 尺寸对齐:单栏图宽约 8.5 cm(≈3.35 in),双栏图 17–18 cm。建议在 figsize 初始化时就按版心设定,避免后期缩放导致字号变化。
fig.savefig('figure.pdf')         # 矢量:投稿首选
fig.savefig('figure.svg')         # 矢量:可再编辑
fig.savefig('figure.tiff', dpi=600) # 位图:600 dpi 备份
fig.savefig('figure.png', dpi=300)  # 位图:网页/汇报

五、科研绘图速查表

元素 推荐设置 作用
字体字号 Arial / Helvetica,10–12 pt 与论文正文协调,缩小后仍可读
坐标轴线宽 1.2 pt,仅保留左、下 清晰利落,不笨重
网格 虚线、透明度 0.2 左右 辅助读数但不抢眼
误差棒 capsize 4–6,注明 SEM/SD 端帽明确、口径清晰
配色 色盲友好方案(如 YlGnBu) 黑白打印与色觉障碍者友好
导出 PDF/SVG 矢量 + 600 dpi TIFF 满足各类期刊投稿要求

结语

科研绘图不应是每次手动美化的“玄学”,而应成为规范化的流水线作业。通过建立全局模板、编写可重复运行的脚本、并按版心尺寸和矢量格式导出,研究者可以将精力更多集中在数据本身,高效产出符合国际期刊标准的高质量插图。

版权声明

仅作分享,不代表本号观点,若涉及侵权等行为,请联系我们删除,万分感谢!

【声明】内容源于网络
0
0
Ai尚研修
1234
内容 3220
粉丝 0
Ai尚研修 1234
总阅读86.5k
粉丝0
内容3.2k