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

如何在Bokeh的MultiLine图元悬浮时显示单个对应数值?

解决Bokeh MultiLine HoverTool显示单个点精确值的问题

你遇到的这个问题确实是Bokeh中MultiLine glyph的默认行为导致的——因为每个数据条目都是列表,HoverTool会直接显示整个列表,而非当前悬停点的单个值。不用$x/$y(鼠标坐标)也不用额外不可见线条的话,有两种可靠方案,都能完美兼容筛选、联动等复杂功能:


方案一:自定义JS回调(适配MultiLine高性能场景)

如果你的图表包含大量线条,MultiLine的性能优势很重要,那么可以通过HoverTool的JavaScript回调动态捕获当前悬停点的精确值:

完整代码

from bokeh.plotting import show, figure
from bokeh.models import ColumnDataSource, HoverTool, CustomJS

df = {
    'X_value': [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]],
    'model': ['m1', 'm1', 'm2', 'm2'],
    'color': ['red', 'red', 'blue', 'blue'],
    'Y_value': [[0.50, 0.66, 0.70, 0.67], [0.65, 0.68, 0.71, 0.66], [0.80, 0.79, 0.84, 0.80], [0.80, 0.83, 0.76, 0.64]]
}
source = ColumnDataSource(df)

p = figure(plot_height=400)
multi_line_renderer = p.multi_line(
    xs='X_value', 
    ys='Y_value', 
    legend="model", 
    color='color', 
    line_width=5, 
    line_alpha=0.6, 
    hover_line_alpha=1.0, 
    source=source
)

# 配置带JS回调的HoverTool
hover = HoverTool(
    show_arrow=False,
    line_policy='next',
    renderers=[multi_line_renderer],  # 仅作用于当前MultiLine
    tooltips=[],  # 初始为空,由JS动态填充
    callback=CustomJS(args=dict(source=source), code="""
        // 获取当前悬停的线条索引和点索引
        const line_idx = cb_data.index.indices[0];
        const point_idx = cb_data.index.index;
        
        // 从数据源中提取对应点的精确值
        const x_val = source.data.X_value[line_idx][point_idx];
        const y_val = source.data.Y_value[line_idx][point_idx];
        const model_name = source.data.model[line_idx];
        
        // 更新Hover提示内容
        cb_obj.tooltips = [
            ('Model', model_name),
            ('X_value', x_val),
            ('Y_value', y_val.toFixed(2))  // 可选:格式化小数位数
        ];
    """)
)

p.add_tools(hover)
show(p)

核心逻辑

  1. 通过cb_data.index获取当前悬停的线条在数据源中的索引和点在该线条内的索引
  2. 从数据源的嵌套列表中提取对应点的精确值
  3. 动态更新HoverTool的提示内容,完全基于原始数据源操作,不影响筛选、联动功能

方案二:转换为长格式使用Line glyph(更直观)

如果你的线条数量不算特别多,可以将嵌套列表的数据源转换为扁平的长格式,用普通的Line glyph绘制,HoverTool就能直接识别单个点的值:

完整代码

import pandas as pd
from bokeh.plotting import show, figure
from bokeh.models import ColumnDataSource, HoverTool

# 将原始嵌套数据转换为长格式DataFrame
df_long = pd.DataFrame({
    'X_value': [1,2,3,4]*4,
    'Y_value': [0.50,0.66,0.70,0.67,0.65,0.68,0.71,0.66,0.80,0.79,0.84,0.80,0.80,0.83,0.76,0.64],
    'model': ['m1']*4 + ['m1']*4 + ['m2']*4 + ['m2']*4,
    'color': ['red']*8 + ['blue']*8,
    'line_id': [0]*4 + [1]*4 + [2]*4 + [3]*4  # 标记每条线的唯一ID
})

source = ColumnDataSource(df_long)

p = figure(plot_height=400)
p.line(
    x='X_value', 
    y='Y_value', 
    legend="model", 
    color='color', 
    line_width=5, 
    line_alpha=0.6, 
    hover_line_alpha=1.0, 
    source=source,
    group='line_id'  # 按line_id分组绘制多条线
)

# 直接配置HoverTool即可显示单个点值
hover = HoverTool(
    show_arrow=False,
    line_policy='next',
    tooltips=[
        ('Model', '@model'),
        ('X_value', '@X_value'),
        ('Y_value', '@Y_value')
    ]
)

p.add_tools(hover)
show(p)

优势

  • 无需编写JS代码,逻辑更直观
  • 长格式数据源天然支持Bokeh的各种筛选、联动组件,兼容性拉满

内容的提问来源于stack exchange,提问作者Dmitriy Apollonin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:46:42