使用numpy与pyqtgraph BarGraphItem创建堆叠直方图:不同长度数组可行吗?
用pyqtgraph的BarGraphItem实现基于不同长度数组的堆叠直方图
当然可以!numpy + pyqtgraph完全能轻松搞定这个需求——不同长度的数组只需要先做一点点预处理对齐,就能顺利生成堆叠直方图了。我给你一步步拆解实现思路,再附上完整代码示例:
核心思路
堆叠直方图的关键是让每一组柱状图的底部“踩”在前面所有组的顶部。对于长度不一的数组,我们首先要把它们对齐到相同长度(短数组补0或者你需要的填充值),然后计算每一组的起始y坐标(也就是前面所有组的累加和),最后用BarGraphItem依次绘制每一层。
步骤拆解
1. 数据预处理:对齐不同长度的数组
假设你有几个长度不同的numpy数组,我们先找到其中最长的数组长度,然后用numpy.pad()把短数组补到这个长度(补0是最常见的选择,如果你有其他需求也可以换填充值)。
比如:
import numpy as np # 模拟不同长度的输入数组 arr1 = np.array([3, 5, 2, 7]) arr2 = np.array([1, 4]) arr3 = np.array([6, 2, 5]) # 找到最长数组的长度 max_len = max(len(arr1), len(arr2), len(arr3)) # 把所有数组补到相同长度 padded_arr1 = np.pad(arr1, (0, max_len - len(arr1)), mode='constant') padded_arr2 = np.pad(arr2, (0, max_len - len(arr2)), mode='constant') padded_arr3 = np.pad(arr3, (0, max_len - len(arr3)), mode='constant')
2. 计算堆叠层的起始位置
每一层柱状图的起始y值是前面所有层的数值之和,我们可以用numpy.cumsum()来快速计算:
# 先把数组整理成一个二维数组(每行是一组数据) stacked_data = np.vstack([padded_arr1, padded_arr2, padded_arr3]) # 计算每一层的起始y坐标:第一个层从0开始,后面的层是前面所有层的累加和 base_ys = np.cumsum(stacked_data, axis=0) - stacked_data
这里base_ys的每一行就是对应组柱状图的底部y值,stacked_data的每一行是对应组的高度。
3. 用BarGraphItem绘制堆叠直方图
接下来创建pyqtgraph的图形界面,然后依次添加每一层的BarGraphItem,记得给不同层设置不同颜色区分:
import pyqtgraph as pg from PyQt5.QtWidgets import QApplication import sys app = QApplication(sys.argv) # 创建绘图窗口 win = pg.GraphicsLayoutWidget(show=True, title="堆叠直方图(不同长度数组)") plot = win.addPlot(title="Stacked Bar Graph") # 设置x轴的位置(每个bar的中心位置) x = np.arange(max_len) bar_width = 0.6 # 柱状图宽度 # 定义不同层的颜色 colors = ['#1f77b4', '#ff7f0e', '#2ca02c'] # 依次绘制每一层 for i in range(stacked_data.shape[0]): bar = pg.BarGraphItem( x=x, height=stacked_data[i], y=base_ys[i], width=bar_width, brush=pg.mkBrush(colors[i]) ) plot.addItem(bar) # 设置x轴标签(可选,根据你的实际需求设置) plot.setAxisItems({'bottom': pg.AxisItem(orientation='bottom', ticks=[(i, f'Cat {i+1}') for i in x])}) # 显示图例 legend = plot.addLegend() for i, color in enumerate(colors): legend.addItem(pg.BarGraphItem(brush=pg.mkBrush(color)), f'Group {i+1}') sys.exit(app.exec_())
额外注意事项
- 如果你的短数组末尾没有数据代表“无值”,补0是合理的;如果是缺失值,你也可以考虑用
np.nan,不过pyqtgraph会忽略nan值(对应的位置不会绘制柱状图)。 - 如果你不想让x轴的数量对应最长数组的长度,而是想只保留有数据的类别,可以先整理出所有存在数据的x位置,再做对齐处理——不过这种情况稍微复杂一点,核心还是先把数据对齐到统一的x轴维度。
内容的提问来源于stack exchange,提问作者Yuliya Goroshkova
相关产品推荐
相关产品推荐

