Pyplot/Matplotlib实现Y轴压缩效果的方法求助
实现Walter/Lieth气候图的Y轴压缩效果(Matplotlib)
我当初做Walter/Lieth气候图的时候也碰到过这个问题!要实现右侧Y轴100以上的压缩效果,核心是给轴做非线性自定义变换——单纯设置刻度值只会让数值间隔变大,但视觉上还是等距的,而我们需要的是数值间隔变大但视觉距离缩小,这就得靠自定义轴尺度来实现。
核心思路
我们需要定义一对正向/逆向变换函数:
- 正向变换:把实际的降水量数值转换成绘图时的视觉坐标,当数值≤100时保持线性,数值>100时按比例压缩(比如每50的数值增量对应10的视觉增量)
- 逆向变换:把视觉坐标转回实际数值,用于Matplotlib的交互和坐标计算
具体代码实现
1. 导入依赖库
import matplotlib.pyplot as plt import matplotlib.scale as mscale import matplotlib.transforms as mtransforms import pandas as pd # 用pandas的where函数处理数组更方便,也可以用numpy替代
2. 定义变换函数
这里我用压缩系数5,你可以根据数据范围调整(系数越大,压缩程度越高):
def forward(y): # 正向变换:≤100保持线性,>100时按比例压缩 return y.where(y <= 100, 100 + (y - 100)/5) def inverse(y): # 逆向变换:把视觉坐标转回实际数值 return y.where(y <= 100, 100 + (y - 100)*5)
3. 注册自定义轴尺度(或直接调用)
有两种方式使用这个变换:
方式一:注册自定义尺度类(规范且复用性强)
class CompressedPrecipScale(mscale.ScaleBase): name = 'compressed_precip' def __init__(self, axis, **kwargs): super().__init__(axis) def get_transform(self): return mtransforms.FuncTransform(forward, inverse) def set_default_locators_and_formatters(self, axis): # 设置符合Walter/Lieth标准的刻度:0-100按20间隔,100以上按50间隔 axis.set_major_locator(plt.FixedLocator([0,20,40,60,80,100,150,200,250,300])) axis.set_major_formatter(plt.FormatStrFormatter('%d')) # 注册这个自定义尺度 mscale.register_scale(CompressedPrecipScale)
绘图时直接调用:
fig, ax = plt.subplots(figsize=(8,6)) # 模拟气候数据(月份-降水量) months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] precip_data = [55,42,68,90,130,190,220,175,145,95,70,58] ax.bar(months, precip_data, color='darkblue') # 应用自定义压缩尺度 ax.set_yscale('compressed_precip') ax.set_ylabel('Precipitation (mm)') ax.set_title('Walter/Lieth Climograph (Custom Y-axis)') plt.tight_layout() plt.show()
方式二:直接使用function尺度(快速实现)
如果不想注册类,可以直接用Matplotlib 3.1+支持的function尺度:
fig, ax = plt.subplots(figsize=(8,6)) ax.bar(months, precip_data, color='darkblue') # 直接传入变换函数 ax.set_yscale('function', functions=(forward, inverse)) # 手动设置符合标准的刻度 ax.set_yticks([0,20,40,60,80,100,150,200,250,300]) ax.set_ylabel('Precipitation (mm)') ax.set_title('Walter/Lieth Climograph (Quick Y-axis Compression)') plt.tight_layout() plt.show()
关键注意点
- 必须定义逆向变换函数:Matplotlib需要它来处理鼠标悬停、坐标拾取等交互功能,否则会出现交互异常
- 压缩系数可灵活调整:如果你的降水量最大值超过300,可以把系数调大(比如10),避免视觉空间过于拥挤
- 手动设置刻度定位器:确保显示的刻度完全符合Walter/Lieth标准,100以下小间隔,100以上大间隔
内容的提问来源于stack exchange,提问作者Jannik Günther
相关产品推荐
相关产品推荐

