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

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)

关键修改说明:

  1. 规范获取选中索引:用source.selected.indices替代字典式访问,这是Bokeh官方推荐的API用法,更简洁且不易出错。
  2. 触发视图更新:直接赋值source.selected.indices = indices,indices是Selected对象的可观察属性,赋值会自动触发Bokeh的变更事件,让前端同步更新选中高亮效果。
  3. 修复制造商提取逻辑:原代码中source.data['cyl_mfr'][output][1]会因output是列表而报错,改为取output[0]获取单个选中项的索引后再提取制造商。

现在运行bokeh serve --show your_script.py启动Bokeh Server,点击任意一个制造商的柱子,同制造商的所有柱子都会被自动选中并高亮,完美实现你需要的一键选中同组功能。

内容的提问来源于stack exchange,提问作者Frank W

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:44:18