You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为Bokeh水平条形图添加标签及调整X轴数值的技术问询

Bokeh水平条形图常见问题解答

1. 为hbar条形添加数值标签

要给水平堆叠条形图的每个条形添加数值标签,你可以使用Bokeh的LabelSet组件,核心是计算每个条形的中心坐标,再将标签绑定到对应位置。

修改后的完整代码

from bokeh.palettes import GnBu3, OrRd3
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, LabelSet

fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
years = ["2015", "2016", "2017"]

exports = {'fruits' : fruits,
           '2015'   : [2, 1, 4, 3, 2, 4],
           '2016'   : [5, 3, 4, 2, 4, 6],
           '2017'   : [3, 2, 4, 4, 5, 3]}

imports = {'fruits' : fruits,
           '2015'   : [-1, 0, -1, -3, -2, -1],
           '2016'   : [-2, -1, -3, -1, -2, -2],
           '2017'   : [-1, -2, -1, 0, -2, -2]}

p = figure(y_range=fruits, height=350, x_range=(-16, 16), title="Fruit import/export, by year",
           toolbar_location=None)

# 绘制出口堆叠条形
p.hbar_stack(years, y='fruits', height=0.9, color=GnBu3, source=ColumnDataSource(exports),
             legend_label=["%s exports" % x for x in years])

# 绘制进口堆叠条形
p.hbar_stack(years, y='fruits', height=0.9, color=OrRd3, source=ColumnDataSource(imports),
             legend_label=["%s imports" % x for x in years])

# 计算出口标签的位置和文本
label_data = []
# 处理出口数据
current_export = [0] * len(fruits)
for year in years:
    vals = exports[year]
    for idx, fruit in enumerate(fruits):
        # 条形中心x坐标:起始位置 + 数值的一半
        center_x = current_export[idx] + vals[idx]/2
        label_data.append({
            'x': center_x,
            'y': fruit,
            'text': str(vals[idx])
        })
        current_export[idx] += vals[idx]

# 处理进口数据(显示绝对值)
current_import = [0] * len(fruits)
for year in years:
    vals = imports[year]
    for idx, fruit in enumerate(fruits):
        center_x = current_import[idx] + vals[idx]/2
        label_data.append({
            'x': center_x,
            'y': fruit,
            'text': str(abs(vals[idx]))
        })
        current_import[idx] += vals[idx]

# 创建标签数据源并添加到图中
label_source = ColumnDataSource(label_data)
labels = LabelSet(x='x', y='y', text='text', source=label_source,
                  text_align='center', text_baseline='middle')
p.add_layout(labels)

# 原有样式设置
p.y_range.range_padding = 0.1
p.ygrid.grid_line_color = None
p.legend.location = "top_left"
p.axis.minor_tick_line_color = None
p.outline_line_color = None

show(p)

关键步骤说明

  • 计算每个条形的中心坐标:堆叠条形的起始位置是之前年份数值的累加,中心位置为起始位置加上当前数值的一半。
  • 使用LabelSet批量添加标签,通过text_align和text_baseline确保标签居中显示在条形内部。

2. 调整X轴去除负数值

根据需求,有两种常见实现方式:

方式一:将X轴刻度显示为绝对值(保留原数据布局)

如果希望保留左侧的进口条形,但X轴不显示负刻度,可以自定义刻度格式化器,将负数转为绝对值显示:

from bokeh.models import FuncTickFormatter

# 在原有代码基础上添加以下配置
p.xaxis.formatter = FuncTickFormatter(code="""
    return Math.abs(tick).toString();
""")

方式二:将所有数据转为正数,重构布局(完全去掉负数值)

如果希望彻底移除X轴的负数区间,可以将进口数据转为正数,调整条形位置,让出口和进口分别位于X轴的两侧:

# 重构进口数据为正数
positive_imports = {'fruits': fruits}
for year in years:
    positive_imports[year] = [abs(v) for v in imports[year]]

# 重新设置X轴范围为正数区间
p = figure(y_range=fruits, height=350, x_range=(0, 16), title="Fruit import/export, by year",
           toolbar_location=None)

# 出口条形从0开始堆叠
p.hbar_stack(years, y='fruits', height=0.9, color=GnBu3, source=ColumnDataSource(exports),
             legend_label=["%s exports" % x for x in years])

# 进口条形从指定位置开始堆叠(这里用8作为分隔,也可动态计算出口最大值)
p.hbar_stack(years, y='fruits', height=0.9, color=OrRd3, source=ColumnDataSource(positive_imports),
             legend_label=["%s imports" % x for x in years], x=8)

# 其余样式和标签代码同前...

选择建议

  • 若需要保留原有的正负对比布局,仅隐藏负刻度,选方式一;
  • 若希望完全移除负数,让进口和出口都以正数形式展示,选方式二。

内容的提问来源于stack exchange,提问作者Paul Borowy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 03:25:20