如何用Matplotlib/Seaborn绘制并排的两组堆叠直方图
在同一图表中绘制并排堆叠直方图(Matplotlib & Seaborn)
Matplotlib 实现方法
你说得对,Matplotlib 没有直接的"一键式"函数生成并排堆叠直方图,但我们可以通过positions参数调整每组堆叠柱的位置,避免手动计算所有条形的高度,这应该是最接近原生支持的方式了。
核心思路是:
- 先计算每个bin的中心位置,然后给两组堆叠柱分别设置左右偏移,让它们在同一个bin区间内并排显示
- 通过
rwidth控制每组堆叠柱的宽度,确保两组之间留有空隙
下面是完整代码示例:
import matplotlib.pyplot as plt import numpy as np # 模拟你的数据(替换成你自己的correct_a、incorrect_a等) np.random.seed(42) correct_a = np.random.normal(5, 1, 100) incorrect_a = np.random.normal(7, 1, 50) correct_b = np.random.normal(5.5, 1, 120) incorrect_b = np.random.normal(6.5, 1, 60) # 共用的bin edges(和你原代码一致) edges = np.linspace(2, 10, 9) bin_width = edges[1] - edges[0] bin_centers = (edges[:-1] + edges[1:]) / 2 # 每个bin的中心位置 offset = bin_width * 0.25 # 左右偏移量,确保两组柱不重叠 # 绘制第一组堆叠柱(A组),向左偏移 plt.hist([correct_a, incorrect_a], bins=edges, stacked=True, color=['green', 'red'], rwidth=0.4, alpha=0.7, label=['Correct A', 'Incorrect A'], positions=bin_centers - offset) # 绘制第二组堆叠柱(B组),向右偏移 plt.hist([correct_b, incorrect_b], bins=edges, stacked=True, color=['blue', 'orange'], rwidth=0.4, alpha=0.7, label=['Correct B', 'Incorrect B'], positions=bin_centers + offset) # 美化图表 plt.xlabel('数值') plt.ylabel('计数') plt.legend() plt.title('并排堆叠直方图(Matplotlib)') plt.show()
Seaborn 实现方法
Seaborn 目前确实没有原生支持这种并排堆叠直方图的函数,但我们可以通过预处理数据、计算bin内的计数,再用条形图来实现。步骤如下:
- 将所有数据整理成长格式的DataFrame
- 用
pd.cut给每个数据点分配对应的bin - 分组统计每个bin、每组、每个类型的计数
- 用
bar函数绘制堆叠的并排条形
代码示例:
import seaborn as sns import pandas as pd import matplotlib.pyplot as plt import numpy as np # 模拟数据(替换成你的真实数据) np.random.seed(42) correct_a = np.random.normal(5, 1, 100) incorrect_a = np.random.normal(7, 1, 50) correct_b = np.random.normal(5.5, 1, 120) incorrect_b = np.random.normal(6.5, 1, 60) # 整理成长格式DataFrame df_a = pd.DataFrame({ 'value': np.concatenate([correct_a, incorrect_a]), 'type': ['Correct']*len(correct_a) + ['Incorrect']*len(incorrect_a), 'group': 'A' }) df_b = pd.DataFrame({ 'value': np.concatenate([correct_b, incorrect_b]), 'type': ['Correct']*len(correct_b) + ['Incorrect']*len(incorrect_b), 'group': 'B' }) df = pd.concat([df_a, df_b]) # 定义bin edges并分配每个数据点的bin edges = np.linspace(2, 10, 9) bin_width = edges[1] - edges[0] bin_centers = (edges[:-1] + edges[1:]) / 2 df['bin'] = pd.cut(df['value'], bins=edges, labels=bin_centers) # 统计每个bin、group、type的计数 counts = df.groupby(['bin', 'group', 'type']).size().unstack('type').fillna(0).astype(int) # 绘制并排堆叠条形图 bar_width = bin_width * 0.4 x = np.arange(len(bin_centers)) fig, ax = plt.subplots() # 绘制A组堆叠柱 ax.bar(x - bar_width/2, counts.loc[:, ('A', 'Correct')], width=bar_width, color='green', alpha=0.7, label='Correct A') ax.bar(x - bar_width/2, counts.loc[:, ('A', 'Incorrect')], width=bar_width, bottom=counts.loc[:, ('A', 'Correct')], color='red', alpha=0.7, label='Incorrect A') # 绘制B组堆叠柱 ax.bar(x + bar_width/2, counts.loc[:, ('B', 'Correct')], width=bar_width, color='blue', alpha=0.7, label='Correct B') ax.bar(x + bar_width/2, counts.loc[:, ('B', 'Incorrect')], width=bar_width, bottom=counts.loc[:, ('B', 'Correct')], color='orange', alpha=0.7, label='Incorrect B') # 设置x轴刻度 ax.set_xticks(x) ax.set_xticklabels(bin_centers.round(1)) ax.set_xlabel('数值') ax.set_ylabel('计数') ax.legend() plt.title('并排堆叠直方图(Seaborn)') plt.show()
这样就能实现你想要的效果:每个bin旁分别展示一组绿/红堆叠柱和一组蓝/橙堆叠柱啦。
内容的提问来源于stack exchange,提问作者mibm
相关产品推荐
相关产品推荐

