Bokeh分组柱状图:用TapTool一键选中同组所有柱子
解决Bokeh分组柱状图点击选中同组所有柱子的问题
你的思路完全正确——通过TapTool捕捉点击事件、匹配同组数据、更新选中状态,问题核心在于直接修改source.selected['1d']['indices']不会触发Bokeh的属性变更通知,因为Selected是一个不可变的结构,必须通过规范的API方法来更新。
下面是修正后的完整代码,我标注了关键修改点:
from bokeh.io import show, output_file from bokeh.models import ColumnDataSource, HoverTool, TapTool, Selection from bokeh.plotting import figure from bokeh.palettes import Spectral5 from bokeh.sampledata.autompg import autompg_clean as df from bokeh.transform import factor_cmap # 准备数据 df.cyl = df.cyl.astype(str) df.yr = df.yr.astype(str) group = df.groupby(('cyl', 'mfr')) source = ColumnDataSource(group) index_cmap = factor_cmap('cyl_mfr', palette=Spectral5, factors=sorted(df.cyl.unique()), end=1) # 设置图表 p = figure(plot_width=800, plot_height=300, title="Mean MPG by # Cylinders and Manufacturer", x_range=group, toolbar_location=None, tools="") p.vbar(x='cyl_mfr', top='mpg_mean', width=1, source=source, line_color="white", fill_color=index_cmap) # 图表样式调整 p.y_range.start = 0 p.x_range.range_padding = 0.05 p.xgrid.grid_line_color = None p.xaxis.axis_label = "Manufacturer grouped by # Cylinders" p.xaxis.major_label_orientation = 1.2 p.outline_line_color = None # 添加工具 p.add_tools(HoverTool(tooltips=[("MPG", "@mpg_mean"), ("Cyl, Mfr", "@cyl_mfr")])) p.add_tools(TapTool()) # 我的额外代码(修正版) import pandas as pd import sys from bokeh.plotting import curdoc # 调试输出重定向(可选) save_stderr = sys.stderr f_err = open('error.log', 'w') sys.stderr = f_err save_stdout = sys.stdout f_info = open('info.log', 'w') sys.stdout = f_info def callback_tap(attr, old, new): output = source.selected.indices # 更规范的选中索引获取方式 print(output, type(output)) if len(output) == 1: # 获取选中项的制造商 selected_cyl_mfr = source.data['cyl_mfr'][output[0]] man = selected_cyl_mfr[1] # 筛选同制造商的所有索引 tmp = pd.DataFrame(source.data['cyl_mfr'], columns=['cyl', 'mfr']) indices = tmp.index[tmp.mfr == man].tolist() # 关键修正:通过赋值indices属性触发视图更新 source.selected.indices = indices # 绑定回调函数 source.on_change('selected', callback_tap) curdoc().add_root(p)
关键修改说明:
- 规范获取选中索引:用
source.selected.indices替代字典式访问,这是Bokeh官方推荐的API用法,更简洁且不易出错。 - 触发视图更新:直接赋值
source.selected.indices = indices,indices是Selected对象的可观察属性,赋值会自动触发Bokeh的变更事件,让前端同步更新选中高亮效果。 - 修复制造商提取逻辑:原代码中
source.data['cyl_mfr'][output][1]会因output是列表而报错,改为取output[0]获取单个选中项的索引后再提取制造商。
现在运行bokeh serve --show your_script.py启动Bokeh Server,点击任意一个制造商的柱子,同制造商的所有柱子都会被自动选中并高亮,完美实现你需要的一键选中同组功能。
内容的提问来源于stack exchange,提问作者Frank W
相关产品推荐
相关产品推荐

