You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python修复Y轴范围过大图表:解决峰值掩盖有效数据问题

解决Matplotlib图表峰值掩盖有效数据的问题

我完全懂你这种困扰——那些突然飙升的峰值一下子就把你真正要分析的有效数据给淹没了,而且每个子图的Y轴尺度还不一样,硬设Y轴范围确实不是个通用的好办法。这里有两个实用的方案,你可以根据自己的需求来选:

方案一:过滤极端异常值(简单直接)

如果这些峰值属于噪声或者你不需要展示它们,你可以基于百分位数来过滤掉超出合理范围的数值,把它们替换成阈值或者NaN(Matplotlib绘图时会自动跳过NaN)。

示例代码:

import numpy as np

# 定义过滤函数,默认保留99%以内的数据,可根据需求调整percentile参数
def filter_extreme_values(data, percentile=99):
    # 计算指定百分位数作为阈值
    upper_threshold = np.percentile(data, percentile)
    # 把超过阈值的数值替换为阈值(也可以换成np.nan,这样绘图时会跳过这些点)
    filtered_data = np.where(data > upper_threshold, upper_threshold, data)
    return filtered_data

# 批量处理你的plotdata列表
filtered_plotdata = [filter_extreme_values(dataset) for dataset in plotdata]

# 后续绘图代码不变,只需要把plotdata换成filtered_plotdata
fig, (ax1,ax2,ax3,ax4) = plt.subplots(4, sharex = False, figsize =(15,15))
ax1.plot(Epoch[0], filtered_plotdata[0])
ax1.set_ylabel(label, fontsize = 20)
ax1.tick_params(axis = 'both',which = 'major', labelsize = 18)
ax1.get_yaxis().set_tick_params(direction='out',width=2)
ax1.set_xlim([start1, stop1])
nbins = 5
ax1.yaxis.set_major_locator(MaxNLocator(nbins=nbins,prune='upper'))

# ax2、ax3、ax4的代码同理替换plotdata为filtered_plotdata即可

方案二:使用断裂Y轴(保留所有数据)

如果你不想丢弃峰值数据,只是希望同时看清正常范围的细节,那可以给Y轴做断裂处理——把峰值区域单独放在一个小的子图里,下方子图展示正常尺度的数据,这样既能保留完整数据,又不会让峰值掩盖有效信息。

示例代码:

import numpy as np
from matplotlib.ticker import MaxNLocator

# 创建4组上下子图,每组对应一个原图表
fig, ((ax1_top, ax2_top), 
      (ax1_bottom, ax2_bottom), 
      (ax3_top, ax4_top), 
      (ax3_bottom, ax4_bottom)) = plt.subplots(4, 2, figsize=(15,15))

# 处理第一个子图ax1
threshold_1 = np.percentile(plotdata[0], 99)  # 自定义阈值,比如99%分位数
# 底部子图:显示正常范围数据
ax1_bottom.plot(Epoch[0], plotdata[0])
ax1_bottom.set_ylabel(label, fontsize=20)
ax1_bottom.set_ylim(bottom=None, top=threshold_1)
ax1_bottom.set_xlim([start1, stop1])
ax1_bottom.tick_params(axis='both', which='major', labelsize=18)
ax1_bottom.get_yaxis().set_tick_params(direction='out', width=2)
ax1_bottom.yaxis.set_major_locator(MaxNLocator(nbins=5, prune='upper'))

# 顶部子图:显示峰值区域
ax1_top.plot(Epoch[0], plotdata[0])
ax1_top.set_ylim(bottom=threshold_1, top=None)
ax1_top.set_xlim([start1, stop1])
ax1_top.tick_params(axis='both', which='major', labelsize=18)
ax1_top.get_yaxis().set_tick_params(direction='out', width=2)
ax1_top.yaxis.set_major_locator(MaxNLocator(nbins=2, prune='lower'))
ax1_top.spines.bottom.set_visible(False)  # 隐藏底部边框
ax1_bottom.spines.top.set_visible(False)   # 隐藏顶部边框
ax1_top.tick_params(labelbottom=False)     # 隐藏底部刻度标签

# 添加Y轴断裂的斜线标记
d = 0.015  # 斜线的大小,可调整
kwargs = dict(transform=ax1_top.transAxes, color='black', clip_on=False)
ax1_top.plot((-d, +d), (-d, +d), **kwargs)
ax1_top.plot((1 - d, 1 + d), (-d, +d), **kwargs)

kwargs.update(transform=ax1_bottom.transAxes)
ax1_bottom.plot((-d, +d), (1 - d, 1 + d), **kwargs)
ax1_bottom.plot((1 - d, 1 + d), (1 - d, 1 + d), **kwargs)

# 重复上述逻辑处理ax2、ax3、ax4,注意每个子图的阈值要单独计算(因为数据不同)
# 比如处理ax2:
threshold_2 = np.percentile(plotdata[1], 99)
ax2_bottom.plot(Epoch[1], plotdata[1])
ax2_bottom.set_ylabel(label, fontsize=20)
ax2_bottom.set_ylim(bottom=None, top=threshold_2)
ax2_bottom.set_xlim([start2, stop2])
# ... 后续设置和ax1类似,不再重复

两种方案对比:

  • 方案一适合峰值是噪声或无需展示的场景,代码简单,图表整洁;
  • 方案二适合需要保留峰值数据完整性的场景,能让读者同时看到整体数据和细节,但代码稍复杂。

内容的提问来源于stack exchange,提问作者alex anderson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:51:56