Bokeh双数据源双图场景下TapTool跨图回调实现问题咨询
Bokeh TapTool跨图回调实现方案
你提供的原始代码核心问题有两个:
- 传入CustomJS的
lines_y是ColumnDataSource对象,它的data属性是键值对结构,你直接按数组索引取值会拿到空值 - 没有把所有待切换的y值序列整理成JS可以直接按索引匹配的结构,回调时无法快速拿到选中元素对应的数据
修正后可直接运行的代码
from bokeh.layouts import row from bokeh.models import ColumnDataSource, CustomJS, TapTool from bokeh.plotting import figure, show import numpy as np # 第一个图的数据源:如果是7个圆形改对应字段即可 source_bars = ColumnDataSource({'x': [1, 2, 3], 'y': [2, 4, 1] , 'colnames': ['A', 'B', 'C']}) # 提前准备所有待切换的第二图数据,索引和第一图元素一一对应:第n个元素对应点第一图第n个元素展示的数据 lines_y = [np.random.random(3).tolist() for i in range(3)] # 第二图初始数据源 src1 = ColumnDataSource(data=dict(x= [1, 2, 3], y=lines_y[0])) plot1 = figure(tools = 'tap') # 如果是圆形换成circle方法即可,逻辑完全一致 bars = plot1.vbar(x = 'x', top = 'y', source = source_bars, bottom = 0, width = 0.5) plot2 = figure() lines = plot2.vbar(x = 'x', top = 'y', source = src1, bottom = 0, width = 0.5) # JS回调逻辑 code = ''' if (cb_data.source.selected.indices.length > 0){ // 取第一个选中元素的索引 const selected_idx = cb_data.source.selected.indices[0]; // 匹配对应的数据更新第二图数据源 src1.data['y'] = lines_y[selected_idx]; src1.change.emit(); } ''' # 把回调要用到的对象都传入args plot1.select(TapTool).callback = CustomJS(args={'src1': src1, 'lines_y': lines_y}, code=code) show(row(plot1, plot2))
通用实现思路
- 提前整理好第一图元素和第二图待展示数据的映射关系,推荐用数组按索引对应,JS取值最方便
- CustomJS的
args参数要主动传入所有回调会用到的对象,JS无法直接读取Python侧定义的变量 - 回调更新数据源后必须调用
change.emit()触发Bokeh重绘,修改才会生效
内容的提问来源于stack exchange,提问作者ReinholdN
相关产品推荐
相关产品推荐

