如何为Matplotlib堆叠柱状图添加年份Y轴并修正分数轴范围
解决方案:堆叠柱状图双Y轴配置与数据归一化
核心步骤
- 数据归一化:将每个时间区间内的各状态数值除以该区间的总和,让堆叠后柱子总高度为1,对应Y轴0-1范围,消除原0-8范围的误解。
- 双Y轴实现:用
matplotlib的twinx()方法创建共享X轴的第二个Y轴,用于绑定年份标签。
完整代码示例
import numpy as np import matplotlib.pyplot as plt # 模拟数据:2个系统参数b,每个b对应8个时间区间×5种状态的数值 np.random.seed(42) data_b1 = np.random.randint(1, 3, size=(8, 5)) data_b2 = np.random.randint(1, 3, size=(8, 5)) # 归一化处理:每个时间区间内的状态值除以该区间总和,确保堆叠后总高度为1 norm_b1 = data_b1 / data_b1.sum(axis=1, keepdims=True) norm_b2 = data_b2 / data_b2.sum(axis=1, keepdims=True) # 时间区间与对应年份 time_intervals = np.arange(8) years = [2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022] # 柱子宽度与X轴位置设置 bar_width = 0.35 x_b1 = time_intervals x_b2 = time_intervals + bar_width # 创建主坐标轴 fig, ax1 = plt.subplots(figsize=(10, 6)) # 绘制参数b1的堆叠柱状图 bottom = np.zeros(8) colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd'] for state_idx in range(5): ax1.bar(x_b1, norm_b1[:, state_idx], bar_width, bottom=bottom, label=f'状态{state_idx+1}', color=colors[state_idx]) bottom += norm_b1[:, state_idx] # 绘制参数b2的堆叠柱状图(半透明区分) bottom = np.zeros(8) for state_idx in range(5): ax1.bar(x_b2, norm_b2[:, state_idx], bar_width, bottom=bottom, color=colors[state_idx], alpha=0.7) bottom += norm_b2[:, state_idx] # 配置主Y轴(比例轴) ax1.set_ylabel('状态分布比例') ax1.set_ylim(0, 1) ax1.set_xlabel('时间区间') ax1.set_xticks(time_intervals + bar_width/2) ax1.set_xticklabels([f'区间{t+1}' for t in time_intervals]) ax1.legend(title='系统状态', bbox_to_anchor=(1.05, 1), loc='upper left') # 创建副Y轴(年份标注) ax2 = ax1.twinx() ax2.set_ylabel('对应年份') # 让副Y轴刻度与时间区间对齐 ax2.set_yticks(time_intervals + bar_width/2) ax2.set_yticklabels(years) # 同步副Y轴范围与主Y轴,保证刻度位置匹配 ax2.set_ylim(ax1.get_ylim()) plt.title('不同参数b下各时间区间系统状态分布') plt.tight_layout() plt.show()
关键说明
- 归一化逻辑:
sum(axis=1, keepdims=True)保证按行(时间区间)计算总和,广播除法让每个状态值转化为占比。 - 双Y轴绑定:
twinx()生成的副轴与主轴共享X轴,通过设置yticks和yticklabels将年份与时间区间一一对应。 - 视觉区分:用半透明效果区分不同参数b的柱子,避免重叠混淆。
内容的提问来源于stack exchange,提问作者madhafakha
相关产品推荐
相关产品推荐

