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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:08:42