Bokeh中CustomJS能否使用HoverTool数据?联动绘图坐标获取问题
在Bokeh中用CustomJS实现交互联动图表
当然可以在Bokeh的CustomJS里获取HoverTool或TapTool的交互数据,而且完全能实现你要的「点击/悬停主图点,副图绘制对应(i,j)坐标」的功能!你之前Tap事件拿不到坐标,应该是没正确利用cb_data对象获取选中点的数据源信息,我来给你详细拆解实现步骤:
核心思路
不管是Tap还是Hover交互,CustomJS回调里的cb_data参数都会包含当前交互点的关键信息:
- 对于TapTool:通过
cb_data.source.selected.indices拿到被点击点在数据源中的索引 - 对于HoverTool:通过
cb_data.index.indices拿到当前悬停点的索引
拿到索引后,就能从主图数据源取出对应的(x,y)值,再根据你的逻辑计算出(i,j),最后更新副图的数据源就能实现联动。
完整代码示例
下面是可直接运行的例子,实现点击主图点后,副图自动绘制对应的(i,j)点(这里假设i、j是点的索引,你可以换成自己的函数逻辑):
from bokeh.plotting import figure, show, ColumnDataSource from bokeh.layouts import row from bokeh.models import TapTool, CustomJS, HoverTool # 1. 准备主图数据:模拟5个(x,y)点 main_data = { 'x': [1, 2, 3, 4, 5], 'y': [6, 7, 8, 9, 10], } main_source = ColumnDataSource(data=main_data) # 2. 准备副图空数据源(用来存放计算后的(i,j)) sub_data = { 'i': [], 'j': [], } sub_source = ColumnDataSource(data=sub_data) # 3. 创建主图和副图 p1 = figure(title="主图:点击/悬停触发联动", tools="tap,hover") p1.circle(x='x', y='y', source=main_source, size=15, color='steelblue') p2 = figure(title="副图:显示对应(i,j)坐标", x_range=(-1, 5), y_range=(-1, 5)) p2.circle(x='i', y='j', source=sub_source, size=20, color='crimson') # 4. 编写Tap事件的CustomJS回调 tap_callback = CustomJS(args=dict(main_source=main_source, sub_source=sub_source), code=""" // 获取点击点的索引 const indices = main_source.selected.indices; if (indices.length > 0) { const idx = indices[0]; // 从主数据源取出对应的x、y值 const x = main_source.data['x'][idx]; const y = main_source.data['y'][idx]; // 替换成你的(i,j)计算逻辑,比如根据x,y查询映射表或自定义函数 const i = idx; // 这里用点的索引作为i const j = idx; // 这里用点的索引作为j // 更新副图数据源并触发刷新 sub_source.data = {'i': [i], 'j': [j]}; sub_source.change.emit(); } """) # 5. 给主图的TapTool绑定回调 tap_tool = p1.select_one(TapTool) tap_tool.callback = tap_callback # 6. (可选)实现Hover悬停联动的回调 hover_callback = CustomJS(args=dict(main_source=main_source, sub_source=sub_source), code=""" const idx = cb_data.index.indices[0]; if (idx != null) { const x = main_source.data['x'][idx]; const y = main_source.data['y'][idx]; const i = idx; const j = idx; sub_source.data = {'i': [i], 'j': [j]}; sub_source.change.emit(); } """) hover_tool = HoverTool() hover_tool.callback = hover_callback p1.add_tools(hover_tool) # 7. 布局并显示图表 layout = row(p1, p2) show(layout)
关键细节说明
cb_data的正确使用:Tap事件依赖cb_data.source.selected.indices,Hover事件依赖cb_data.index.indices,这是获取交互点位置的核心- 数据源刷新:修改副图数据源后必须调用
sub_source.change.emit(),否则Bokeh不会自动更新图表 - 自定义逻辑替换:你可以把代码中
const i = idx; const j = idx;换成自己的计算规则,比如i = x * 2; j = y - 5,或者根据(x,y)查询预设的(i,j)映射表
这样就能完美实现你想要的交互联动效果啦!
内容的提问来源于stack exchange,提问作者Slade
相关产品推荐
相关产品推荐

