如何让Bokeh vbar_stack正数值仅在Y轴正侧堆叠、负数值仅在负侧显示?
解决Bokeh vbar_stack正负值独立堆叠的问题
默认使用Bokeh的vbar_stack绘制堆叠柱状图时,正负数值会相互抵消堆叠,无法实现正方向仅堆正值、负方向仅堆负值的效果。解决思路是拆分正负数据集,分别绘制两组堆叠柱状图,具体实现如下:
步骤说明
- 拆分数据:将每个数据系列拆分为「正值子集」(负值替换为0)和「负值子集」(正值替换为0,保留负数形式)
- 分别绘图:对正值子集调用
vbar_stack绘制向上堆叠的柱状图,对负值子集调用vbar_stack绘制向下堆叠的柱状图 - 优化显示:调整Y轴范围确保所有数据完整展示,添加图例区分正负系列
完整代码示例
from bokeh.plotting import figure, show from bokeh.models import ColumnDataSource # 示例数据 categories = ['A', 'B', 'C'] series1 = [2, -3, 5] series2 = [4, 1, -2] series3 = [-1, 2, 3] # 拆分正值系列:负值转为0 pos_series1 = [max(x, 0) for x in series1] pos_series2 = [max(x, 0) for x in series2] pos_series3 = [max(x, 0) for x in series3] # 拆分负值系列:正值转为0,保留负数 neg_series1 = [min(x, 0) for x in series1] neg_series2 = [min(x, 0) for x in series2] neg_series3 = [min(x, 0) for x in series3] # 创建数据源 source = ColumnDataSource(data=dict( x=categories, pos1=pos_series1, pos2=pos_series2, pos3=pos_series3, neg1=neg_series1, neg2=neg_series2, neg3=neg_series3 )) # 创建绘图对象 p = figure(x_range=categories, title="正负值独立堆叠柱状图", y_axis_label="数值") # 绘制正值堆叠(向上) p.vbar_stack( ['pos1', 'pos2', 'pos3'], x='x', width=0.7, color=['#2ecc71', '#3498db', '#9b59b6'], source=source, legend_label=['系列1(正)', '系列2(正)', '系列3(正)'] ) # 绘制负值堆叠(向下) p.vbar_stack( ['neg1', 'neg2', 'neg3'], x='x', width=0.7, color=['#e74c3c', '#f39c12', '#e67e22'], source=source, legend_label=['系列1(负)', '系列2(负)', '系列3(负)'] ) # 调整图例和轴范围 p.legend.location = "top_left" p.legend.click_policy = "hide" # 手动设置Y轴范围,避免数据被截断 min_neg = min(sum(neg_series1), sum(neg_series2), sum(neg_series3)) max_pos = max(sum(pos_series1), sum(pos_series2), sum(pos_series3)) p.y_range.start = min_neg - 1 p.y_range.end = max_pos + 1 # 展示图表 show(p)
关键细节
- 拆分数据时,必须保证正值系列只有非负数,负值系列只有非正数,这样堆叠时才不会出现正负抵消
- 负值堆叠不需要额外设置
bottom参数,因为负数本身会让柱状图向下延伸,Bokeh会自动处理堆叠的层级关系 - 手动调整Y轴范围是为了覆盖所有正负堆叠的总高度,避免边缘数据被截断
内容的提问来源于stack exchange,提问作者dharmatech
相关产品推荐
相关产品推荐

