如何实现光谱数据填充图中数值最小曲线始终前置?
光谱曲线填充可视化解决方案
需求说明
- 拥有多组光谱数据,需对比曲线并填充曲线下方区域
- 要求数值最小的曲线始终显示在最前方
- 曲线强度顺序随光谱位置动态变化:第一个峰值处强度顺序为A<B<C<D<E,第二个峰值处为E<D<C<B<A,其他区域顺序可能随机变化
问题点
使用fill_between方法时,在强度峰值切换区域会出现显示异常,无法保证最小曲线处于顶层
测试数据(DataFrame片段)
A B C D E spectra 1.60 628 807 829 973 966 1.62 1173 1420 1620 1793 1968 1.64 3567 4512 4887 5783 6232 1.66 10365 13056 14254 17340 18286 1.68 23984 30503 33717 40242 43373 1.70 42923 54741 60679 72537 78680 1.72 59167 75363 83009 99574 107083 1.74 62070 78808 87334 104371 112352 1.76 49772 63391 69182 84503 90189 1.78 31434 39861 43771 52512 56310 1.80 16219 20637 22614 26787 28825 1.82 7632 9828 10545 12298 13602 1.84 4094 4920 5197 6192 6647 1.86 2398 2738 2851 3411 3593 1.88 1433 1508 1598 1781 1804 1.90 918 895 870 858 903 1.92 693 600 595 564 546 1.94 702 622 529 468 430 1.96 637 600 507 430 396 1.98 580 535 511 461 437 2.00 530 534 482 416 449 2.02 568 453 464 387 404 2.04 421 365 353 317 318 2.06 357 327 290 263 235 2.08 344 292 245 226 188 2.10 320 269 200 182 153 2.12 321 263 235 185 162 2.14 407 304 279 197 145 2.16 681 527 429 274 191 2.18 1537 1140 920 580 382 2.20 3962 2789 2288 1321 768 2.22 9686 6951 5331 3050 1765 2.24 21056 15007 11416 6436 3752 2.26 38267 26874 20562 11561 6637 2.28 55706 39067 29799 16900 9596 2.30 64310 45348 34907 19514 11307 2.32 59707 42021 31802 18299 10180 2.34 44050 31169 23458 13561 7769 2.36 25907 18337 13965 7889 4576 2.38 13059 9341 6997 3978 2401 2.40 6294 4539 3472 1966 1296 2.42 4272 3028 2389 1391 892 2.44 3995 2956 2312 1344 862 2.46 3970 2898 2267 1351 862 2.48 3496 2522 2055 1153 731 2.50 2512 1815 1512 938 613
解决方案
核心思路
放弃单条曲线整体填充的方式,改为按每个光谱点的强度排序,从最大到最小依次填充当前曲线与下一条更小曲线之间的区域(最小曲线直接填充到基线)。每次绘制的都是当前最上层的区域,自然保证最小曲线始终显示在最前方。
代码实现
import matplotlib.pyplot as plt import pandas as pd # 读取数据(替换为你的数据路径) df = pd.read_csv("your_spectra_data.csv", index_col="spectra") x = df.index.values # 为每条曲线分配固定颜色,保持视觉一致性 colors = {'A': '#ff9999', 'B': '#66b3ff', 'C': '#99ff99', 'D': '#ffcc99', 'E': '#c2c2f0'} plt.figure(figsize=(10,6)) # 逐点处理光谱数据 for i in range(len(x)): # 获取当前光谱点的所有曲线强度,按强度从大到小排序 current_vals = df.loc[x[i]].to_dict() sorted_items = sorted(current_vals.items(), key=lambda item: item[1], reverse=True) # 从最大到最小依次填充区域 prev_val = 0 # 基线初始值 for label, val in sorted_items: # 处理最后一个点的边界情况 if i < len(x)-1: next_val = df.loc[x[i+1]][label] plt.fill_between([x[i], x[i+1]], [prev_val, next_val], [val, next_val], color=colors[label], alpha=0.7) else: plt.fill_between([x[i]], [prev_val], [val], color=colors[label], alpha=0.7) prev_val = val # 绘制所有曲线的轮廓线,增强辨识度 for label in df.columns: plt.plot(x, df[label], color=colors[label], linewidth=1) # 添加图表元素 plt.xlabel("光谱值") plt.ylabel("强度") plt.title("层级有序的光谱曲线填充图") plt.legend(df.columns) plt.show()
代码说明
- 逐点排序:对每个光谱位置的曲线强度重新排序,实时确定当前区域的层级关系
- 分段填充:按强度从高到低的顺序,填充每条曲线与下一条更小曲线之间的区域,最小曲线直接填充到基线
- 边缘线绘制:最后绘制所有曲线的轮廓线,避免填充区域重叠导致曲线不可见
- 颜色映射:为每条曲线分配固定颜色,保证不同光谱位置的同一条曲线视觉统一
该方法完美解决了曲线交叉时的层级问题,确保任意位置下数值最小的曲线都显示在最上层,完全匹配期望效果。
内容的提问来源于stack exchange,提问作者NightofBrokenGlass
相关产品推荐
相关产品推荐

