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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:32:43