Matplotlib如何实现Y轴局部非线性或截断适配极值数据?
解决Matplotlib中极值拉伸Y轴的可视化问题
针对你的数据(90%低值、10%极高值)导致Y轴被拉伸的问题,这里提供三个实用的解决方案:
一、断裂Y轴(截断处理)
直接把Y轴分成上下两段,让低值区域拥有足够的展示空间,高值区域单独占一小段,中间用断裂标记区分,既能看清低值细节,又能保留高值的存在。
import matplotlib.pyplot as plt import numpy as np # 模拟你的数据分布 low_values = np.random.uniform(0.32, 16.27, 90) high_values = np.random.uniform(200, 367.1, 10) data = np.concatenate([low_values, high_values]) x = np.arange(len(data)) # 创建上下两个子图,共享X轴 fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), sharex=True) fig.subplots_adjust(hspace=0.05) # 缩小子图间距,让断裂更自然 # 下方子图:展示低值区域 ax2.plot(x, data, 'o') ax2.set_ylim(0, 17) # 覆盖最大低值16.27 ax2.set_ylabel('数值') # 隐藏上方边框,避免重复 ax2.spines['top'].set_visible(False) ax2.tick_params(labeltop=False) # 上方子图:展示高值区域 ax1.plot(x, data, 'o') ax1.set_ylim(350, 370) # 覆盖最高值367.1 # 隐藏下方边框 ax1.spines['bottom'].set_visible(False) ax1.tick_params(labelbottom=False) # 添加断裂标记 d = .015 # 控制断裂线的倾斜角度 kwargs = dict(transform=ax1.transAxes, color='k', clip_on=False) ax1.plot((-d, +d), (-d, +d), **kwargs) # 左上断裂线 ax1.plot((1 - d, 1 + d), (-d, +d), **kwargs) # 右上断裂线 kwargs.update(transform=ax2.transAxes) ax2.plot((-d, +d), (1 - d, 1 + d), **kwargs) # 左下断裂线 ax2.plot((1 - d, 1 + d), (1 - d, 1 + d), **kwargs) # 右下断裂线 ax1.set_title('断裂Y轴展示极值数据') plt.xlabel('样本索引') plt.show()
二、局部非线性缩放
自定义分段缩放函数,对低值区域用线性缩放保证细节,对高值区域用压缩式缩放(比如平方根),通过调整缩放系数让整体刻度间距看起来均匀。
import matplotlib.pyplot as plt import numpy as np def forward(x): # 分段处理:<=16.27用线性,>16.27用平方根压缩 mask = x <= 16.27 out = np.empty_like(x) out[mask] = x[mask] # 调整缩放系数k,控制高值区域的轴间距 k = 0.2 out[~mask] = 16.27 + (np.sqrt(x[~mask]) - np.sqrt(16.27)) * k return out def inverse(x): # 逆变换,对应forward函数 mask = x <= 16.27 out = np.empty_like(x) out[mask] = x[mask] k = 0.2 out[~mask] = ((x[~mask] - 16.27)/k + np.sqrt(16.27)) ** 2 return out # 模拟数据 low_values = np.random.uniform(0.32, 16.27, 90) high_values = np.random.uniform(200, 367.1, 10) data = np.concatenate([low_values, high_values]) x = np.arange(len(data)) fig, ax = plt.subplots(figsize=(8,6)) ax.plot(x, data, 'o') # 设置自定义缩放 ax.set_yscale('function', functions=(forward, inverse)) # 手动设置刻度,保证间距均匀 yticks = [0.32, 4.3075, 8.295, 12.2825, 16.27, 100, 200, 367.1] ax.set_yticks(yticks) ax.set_yticklabels([str(t) for t in yticks]) ax.set_title('局部非线性缩放Y轴') ax.set_xlabel('样本索引') ax.set_ylabel('数值') plt.show()
提示:可以根据实际效果调整k值,让16.27到367.1的轴间距和前面的刻度间距匹配。
三、聚焦低值+突出高值
如果不需要精确展示高值的分布细节,只需提示存在高值,可以让Y轴聚焦于低值区域,同时用颜色或注释突出高值样本。
import matplotlib.pyplot as plt import numpy as np # 模拟数据 low_values = np.random.uniform(0.32, 16.27, 90) high_values = np.random.uniform(200, 367.1, 10) data = np.concatenate([low_values, high_values]) x = np.arange(len(data)) fig, ax = plt.subplots(figsize=(8,6)) # 绘制低值样本 ax.plot(x, data, 'o', color='blue', label='低值样本') # 筛选并绘制高值样本,用红色突出 high_indices = np.where(data > 16.27)[0] ax.plot(x[high_indices], data[high_indices], 'o', color='red', label='高值样本') # Y轴聚焦低值区域 ax.set_ylim(0, 17) ax.set_yticks([0.32, 4.3075, 8.295, 12.2825, 16.27]) # 添加注释说明高值范围 ax.annotate(f'高值范围: {np.min(high_values):.1f}~{np.max(high_values):.1f}', xy=(0.95, 0.95), xycoords='axes fraction', ha='right', va='top', bbox=dict(boxstyle='round', facecolor='wheat')) ax.set_title('聚焦低值区域+突出高值样本') ax.set_xlabel('样本索引') ax.set_ylabel('数值') ax.legend() plt.show()
内容的提问来源于stack exchange,提问作者erotski
相关产品推荐
相关产品推荐

