4. 光谱可视化基础:Matplotlib基础绘图、折线图绘制光谱、设置坐标轴与标签

做光谱分析,说白了就是跟数据打交道。你拿到手的是一堆波长和强度值,光看数字能看出什么名堂?我当年刚入行时,盯着Excel表格看了半天,眼睛都快瞎了,愣是没发现异常峰。后来老工程师丢给我一句话:「画出来,一眼就能看出来。」

嗯,这就是可视化的力量。今天我们就聊聊怎么用Matplotlib把光谱数据变成漂亮的折线图。

4.1 Matplotlib是什么?

Matplotlib是Python生态里最经典的绘图库。我个人的习惯是,不管做什么分析,第一件事就是import matplotlib.pyplot as plt。它就像你手里的画笔,能把枯燥的数字变成直观的图形。

安装很简单,如果你用的是Anaconda,它已经内置了。没有的话:

pip install matplotlib

导入方式我建议这样写:

import matplotlib.pyplot as plt
import numpy as np

为什么还要导入NumPy?因为光谱数据通常需要做一些数学处理,比如平滑、归一化。NumPy是少不了的搭档。

4.2 折线图:光谱的标准画法

光谱数据本质上就是二维数据:波长(x轴)强度(y轴)。折线图是最自然的选择。

来看一个最简单的例子。假设我们有一组拉曼光谱数据:

# 模拟光谱数据
wavelength = np.linspace(400, 800, 500)  # 400-800nm
intensity = np.exp(-((wavelength - 550) / 30)**2) * 0.8 + \
            np.exp(-((wavelength - 650) / 20)**2) * 0.5 + \
            np.random.normal(0, 0.02, 500)

plt.plot(wavelength, intensity)
plt.show()

运行这段代码,你会看到一条带有两个峰的光谱曲线。我在项目中遇到过一个问题:直接这样画出来的图,坐标轴标签是默认的,别人根本看不懂。你想想看,一个没有标注波长单位的图,谁敢用?

核心要点:光谱图必须包含三个要素——波长范围、强度标度、峰位标注。缺一个,图就不完整。

4.3 设置坐标轴与标签

这才是今天的重头戏。Matplotlib的坐标轴设置,说白了就是「告诉读者你在画什么」。

4.3.1 基础标签设置

plt.plot(wavelength, intensity, color='blue', linewidth=1.5)
plt.xlabel('Wavelength (nm)')
plt.ylabel('Intensity (a.u.)')
plt.title('Raman Spectrum of Sample A')
plt.grid(True, alpha=0.3)
plt.show()

这里有几个细节要注意:

  • 单位一定要写:波长用nm,拉曼位移用cm⁻¹,强度用a.u.(任意单位)
  • 网格线透明度:alpha=0.3,太深了会遮挡数据
  • 线宽:1.5左右比较合适,太细了打印出来看不清

我的小技巧:我习惯在xlabel里加上单位,比如'Wavelength (nm)'。曾经有一次合作方问我「你这个波长是纳米还是微米?」——从那以后,单位再也不敢省了。

4.3.2 坐标轴范围控制

有时候数据两端有噪声,你想聚焦在有效区域:

plt.xlim(450, 750)   # 只显示450-750nm
plt.ylim(0, 1.2)     # 强度范围

为什么要手动设置?因为自动缩放有时会切掉峰顶。我记得有一次做荧光光谱分析,自动缩放把主峰的顶部切掉了一小截,差点导致误判峰位。嗯,这里要注意:永远不要完全信任自动缩放

4.3.3 刻度定制

Matplotlib默认的刻度有时候不太符合光谱分析的习惯。比如你想在特定波长位置显示刻度:

from matplotlib.ticker import MultipleLocator

plt.gca().xaxis.set_major_locator(MultipleLocator(50))   # 主刻度间隔50nm
plt.gca().xaxis.set_minor_locator(MultipleLocator(10))   # 次刻度间隔10nm

这样做的好处是:图面更干净,读者能快速定位波长位置。

4.4 一张完整的光谱图应该长什么样?

我把上面的知识点整合一下,画一张标准的光谱图:

plt.figure(figsize=(10, 6))

plt.plot(wavelength, intensity, color='#2E86AB', linewidth=1.5, label='Sample A')

# 标注峰位
plt.annotate('Peak 1', xy=(550, 0.8), xytext=(520, 0.9),
             arrowprops=dict(arrowstyle='->', color='gray'))

plt.xlabel('Wavelength (nm)', fontsize=12)
plt.ylabel('Intensity (a.u.)', fontsize=12)
plt.title('Raman Spectrum - Sample A', fontsize=14, fontweight='bold')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()

这里我用了annotate来标注峰位。为什么要标注?因为光谱分析的核心就是找峰、认峰。你不标出来,别人怎么知道哪个峰对应什么物质?

4.5 知识体系:光谱可视化的核心逻辑

为了让你更直观地理解今天的内容,我画了一张SVG图,展示光谱可视化的知识结构:

光谱可视化 数据准备 波长 + 强度数组 绘图核心 plt.plot() 折线图 坐标轴设置 标签 / 范围 / 刻度 NumPy数组 CSV/Excel导入 线型/颜色 峰位标注 xlim/ylim 刻度定制 输出:清晰、可读、带标注的光谱折线图 用于报告、论文、数据分享

4.6 避坑指南

做光谱可视化这几年,我踩过不少坑。挑几个典型的说说:

我曾经犯过的错:

  • 忘记设置dpi:保存图片时用默认dpi,结果放到论文里模糊不清。现在我的保存代码必写 plt.savefig('spectrum.png', dpi=300)
  • 中文字体乱码:Matplotlib默认不支持中文。解决方案是:plt.rcParams['font.sans-serif'] = ['SimHei']
  • 图例重叠:数据线多了,图例盖住了峰。用 plt.legend(loc='best') 自动选择位置

4.7 小结

今天的内容其实就三件事:画折线图、设坐标轴、标清楚标签。听起来简单,但我在实际项目中见过太多「画了等于没画」的图——坐标轴没单位、刻度太密、峰位不标。你想想看,这样的图放到报告里,评审老师会怎么想?

下一节我们会聊更高级的话题:多光谱叠加、子图布局、以及如何把图做得更专业。但今天的基础一定要打牢。记住一句话:好的光谱图,自己会说话


公众号:蓝海资料掘金营,微信deep3321