第三章 原始质谱数据可视化:谱图、基峰图、总离子流图

拿到质谱数据后,第一件事是什么?我个人的习惯——先看一眼数据长什么样。可视化不是秀图,而是帮你快速发现异常、把握整体质量、判断后续处理方向。这一章我们专门聊三个最基础也最常用的图:质谱谱图、基峰色谱图和总离子流色谱图。

原始质谱数据 → 三种可视化 原始质谱数据 质谱谱图 (MS) 基峰图 (BPC) 总离子流图 (TIC) 三种图的用途 • 质谱谱图:单个时间点的m/z vs 强度分布,用于鉴定化合物 • 基峰图:每个时间点最强离子强度,反映色谱峰形,常用于峰检测 • 总离子流图:所有离子强度之和,展示整体信号变化

3.1 质谱谱图(Mass Spectrum)

质谱谱图就是某一时刻(或一段保留时间窗口内)的质荷比(m/z)vs 离子强度的二维图。说白了,它告诉你“现在这个时间点,样品里有哪些质量的离子,各自有多少”。

我在第一次做代谢组学项目时,拿到 .mzML 文件就直接跑机器学习,结果模型一团糟。后来回过头看一眼原始谱图才发现——有一批样本的基线噪声高得离谱,质谱仪参数根本不对。你看,可视化能救命。

绘制方法(Python + pyOpenMS)

常用的库是 pyOpenMS + matplotlib,也可以直接用 pymzml。下面给出一个简单的片段,读入单个扫描并画质谱图:

import numpy as np
import matplotlib.pyplot as plt
import pyopenms as oms

# 从 mzML 文件中读取
exp = oms.MSExperiment()
oms.MzMLFile().load("sample.mzML", exp)

# 取第 10 个扫描(索引从 0 开始)
spec = exp[9]
mz_array, intensity_array = spec.get_peaks()

plt.figure(figsize=(10, 4))
plt.vlines(mz_array, 0, intensity_array, color='#3498db', linewidth=0.8)
plt.xlabel("m/z"); plt.ylabel("Intensity")
plt.title(f"MS Spectrum at RT = {spec.getRT():.2f} s")
plt.tight_layout(); plt.show()
小技巧:如果数据是 profile 模式(连续波形),画出来像山丘;如果是 centroided(已质心化),画出来是竖线。我建议在可视化前先确认数据模式,省的画出来怀疑人生。

3.2 基峰色谱图(Base Peak Chromatogram)

基峰图(BPC)的思路很简单:对于色谱上的每个时间点(每个扫描),只取强度最高的那个离子的强度值,然后把所有时间点的这个“最强值”连成一条线。

为什么不用总离子流图?我记得有一次做 LC-MS 数据,TIC 看起来信号很平稳,但 BPC 却暴露出几个关键色谱峰被高背景信号淹没了。你想想看,如果机器偶尔有高噪声 spike,TIC 会把它累积进去,而 BPC 只取最强信号,反而能更清晰地反映真实色谱峰。

从 mzML 中提取 BPC

def compute_bpc(exp):
    rts, bpc_intensities = [], []
    for spec in exp:
        if spec.getMSLevel() == 1:       # 只取一级谱
            _, ints = spec.get_peaks()
            if len(ints) > 0:
                rts.append(spec.getRT())
                bpc_intensities.append(np.max(ints))
    return np.array(rts), np.array(bpc_intensities)

rts, bpc = compute_bpc(exp)
plt.plot(rts, bpc, color='#2ecc71', linewidth=0.7)
plt.xlabel("Retention Time (s)")
plt.ylabel("Base Peak Intensity")
plt.title("Base Peak Chromatogram")
plt.show()
避坑指南:我曾经在处理高分辨率 Orbitrap 数据时,发现 BPC 上出现了大量“尖刺”。排查后发现是质谱仪在数据采集时偶尔跳零,少数扫描里 m/z 全部为 0,导致 np.max(ints) 返回 0。后来加了过滤条件 if np.max(ints) > 0,问题解决。

3.3 总离子流色谱图(Total Ion Current Chromatogram)

TIC 是把每个扫描的所有离子强度加起来,反映总离子流随时间的变化。它是最基础的全局视图,就像监控摄像头的全景模式。

TIC 有三个常见用途:

  • 快速评估运行质量——比如溶剂前沿、柱流失、信号衰减
  • 归一化基线——在定量时用 TIC 做强度校正
  • 发现跑样异常——如果 TIC 突然掉为零,可能是喷雾堵塞或电压崩溃

提取与绘制

def compute_tic(exp):
    rts, tic = [], []
    for spec in exp:
        if spec.getMSLevel() == 1:
            _, ints = spec.get_peaks()
            rts.append(spec.getRT())
            tic.append(np.sum(ints))
    return np.array(rts), np.array(tic)

rts, tic = compute_tic(exp)
plt.plot(rts, tic, color='#9b59b6', linewidth=0.7)
plt.xlabel("Retention Time (s)")
plt.ylabel("Total Ion Current")
plt.title("Total Ion Current Chromatogram")
plt.show()

三种图对比一览

图谱类型横轴纵轴核心信息典型用途
质谱谱图 (MS)m/z强度单个时间点的质荷比分布化合物鉴定、碎片分析
基峰色谱图 (BPC)保留时间最强离子强度每个扫描的最大离子色谱峰检测、峰对齐
总离子流图 (TIC)保留时间所有离子强度之和全局信号总量质量控制、基线归一化
重要区别:BPC 和 TIC 的纵轴量级可能差好几个数量级。TIC 是总强度(可能几十亿),BPC 只是最强离子强度(几百万到几千万)。画图时建议用独立 y 轴范围,不要放在同一张图里比较绝对值。

可视化之前的一个预处理动作

不管你要画哪种图,第一步几乎都是:确定你读进来的数据格式正确。我用 pyOpenMS 时经常踩的坑——忘记设置 log 级别,或者 mzML 文件里的 MS level 标记不对。所以我习惯在可视化前先打印一些元信息,像这样:

print(f"Number of scans: {len(exp)}")
print(f"First scan MS level: {exp[0].getMSLevel()}")
print(f"First scan RT: {exp[0].getRT():.2f} s")
print(f"First scan m/z range: {exp[0].getMZRange()[0]:.4f} - {exp[0].getMZRange()[1]:.4f}")

这一小段代码能省掉你后面 80% 的 debug 时间。我个人每次加载数据都会跑一遍,相当于给数据“号个脉”。

组合视图:多面板图

实际工作中,我经常把 TIC、BPC 和某个质谱谱图放在同一张图里,以便在时间维和质谱维之间快速跳转。例如:

fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 8), sharex=True)

# ax1: TIC
ax1.plot(rts, tic, color='#9b59b6')
ax1.set_ylabel("TIC")

# ax2: BPC
ax2.plot(rts, bpc, color='#2ecc71')
ax2.set_ylabel("BPC")

# ax3: 选择保留时间 120s 处的质谱谱图
target_rt = 120
closest_idx = np.argmin(np.abs(rts - target_rt))
spec = exp[closest_idx]   # 需要保证是 MS1
mz, ints = spec.get_peaks()
ax3.vlines(mz, 0, ints, color='#e74c3c', linewidth=0.6)
ax3.set_xlabel("m/z")
ax3.set_ylabel("Intensity")
ax3.set_xlim(100, 400)   # 限制显示范围,避免太密

plt.tight_layout()
plt.show()

这样的组合图,在你调整预处理参数(比如保留时间窗口、m/z 容差)时特别有用。我看到哪个峰在 BPC 上比较突出,就迅速点开对应时间的质谱谱图,看看那团峰里到底有哪些离子——这也是我筛选候选特征最常用的方法之一。

本章小结

三种可视化——质谱谱图、BPC、TIC——构成了观察原始数据的三棱镜。谱图看细节,BPC 抓主峰,TIC 管全局。记住一个原则:在动手建特征之前,先画图。我曾因为跳过这一步吃过苦头,希望你不用再踩同一个坑。