如何实现半线性半对数次坐标轴?Walter-Leigh气候图绘制求助
Walter-Leigh气候图:降水轴线性+对数刻度问题解决
问题背景
需要绘制Walter-Leigh气候图,核心需求:
- 降水轴:0-100范围为线性刻度,100以上(截断至300)为对数刻度
- 温度轴位于左侧,降水轴位于右侧
尝试过Python的ggplot(效果不如R版本)、cloupy内置函数(数据格式限制多、效果差),自定义实现时参考方案修改代码后,出现对数刻度与线性刻度叠加的问题。
原代码及问题效果
原代码(缺失月份变量m):
import pandas as pd import numpy as np import matplotlib.pyplot as pl from mpl_toolkits.axes_grid1 import make_axes_locatable # 数据 t=[8.2,8.9,11.2,15.0,19.8,24.5,27.1,26.7,21.6,17.5,13.3,9.7] p=[77.2,66.2,58.5,63.8,60.4,44.6,24.3,36.7,83.0,73.3,123.0,109.5] # 自定义绘图代码 fig, axt=pl.subplots() axt.set_xlabel("Months") axt.set_ylabel("Temperature") pl.ylim([0,50]) axt.plot(m,t, "r") axp=axt.twinx() axp.plot(m,p) axp.set_yscale("linear") axp.set_ylim([0,100]) axp.spines['top'].set_visible(False) axp.set_ylabel("Precipitation") divider = make_axes_locatable(axp) axp2=divider.append_axes("top", size=1, pad=0) axp2.plot(m,p) axp2.set_yscale("log") axp2.set_ylim([100,300]) axp2.spines['bottom'].set_visible(False) axp2.xaxis.set_ticks_position('top') axp2.yaxis.set_ticks_position('right') pl.setp(axp2.get_xticklabels(), visible=False) pl.show()
当前效果:
解决方案
问题根源是重复绘制全量降水数据导致线条叠加,且两个轴未在100刻度处对齐。修正后的代码如下:
import pandas as pd import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import make_axes_locatable # 数据定义 t = [8.2,8.9,11.2,15.0,19.8,24.5,27.1,26.7,21.6,17.5,13.3,9.7] p = [77.2,66.2,58.5,63.8,60.4,44.6,24.3,36.7,83.0,73.3,123.0,109.5] m = np.arange(1,13) # 补全月份序列 fig, axt = plt.subplots(figsize=(8,6)) # 左侧温度轴 axt.set_xlabel("月份") axt.set_ylabel("温度 (°C)", color='#d62728') axt.set_ylim(0, 50) axt.plot(m, t, color='#d62728', linewidth=2) axt.tick_params(axis='y', labelcolor='#d62728') # 右侧降水线性轴(0-100) axp = axt.twinx() axp.set_ylabel("降水量 (mm)", color='#1f77b4') axp.set_yscale("linear") axp.set_ylim(0, 100) # 仅绘制0-100范围内的降水数据 p_linear = np.where(np.array(p) <= 100, np.array(p), np.nan) axp.plot(m, p_linear, color='#1f77b4', linewidth=2) axp.tick_params(axis='y', labelcolor='#1f77b4') axp.spines['top'].set_visible(False) # 隐藏顶部脊柱,衔接对数轴 # 右侧降水对数轴(100-300) divider = make_axes_locatable(axp) axp2 = divider.append_axes("top", size="100%", pad=0) axp2.set_yscale("log") axp2.set_ylim(100, 300) # 仅绘制100以上的降水数据 p_log = np.where(np.array(p) > 100, np.array(p), np.nan) axp2.plot(m, p_log, color='#1f77b4', linewidth=2) # 调整轴样式:隐藏底部脊柱,隐藏x轴刻度/标签 axp2.spines['bottom'].set_visible(False) axp2.tick_params(axis='x', bottom=False, labelbottom=False) axp2.tick_params(axis='y', labelcolor='#1f77b4') # 设置对数轴刻度为100、200、300,用普通数值显示而非科学计数 axp2.set_yticks([100, 200, 300]) axp2.get_yaxis().set_major_formatter(plt.ScalarFormatter()) axp2.get_yaxis().set_minor_formatter(plt.ScalarFormatter()) plt.tight_layout() plt.show()
关键修正点
- 补全月份变量:添加
m = np.arange(1,13)解决原代码中m未定义的问题 - 拆分数据绘制:将降水数据按0-100、100-300拆分,分别在对应轴绘制,避免线条叠加
- 轴对齐与样式调整:让线性轴和对数轴在100刻度处无缝衔接,隐藏重叠脊柱,统一降水轴颜色
- 对数轴优化:自定义刻度并禁用科学计数,让刻度更直观
内容的提问来源于stack exchange,提问作者Tomislav
相关产品推荐
相关产品推荐

