为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
相关产品推荐
相关产品推荐

