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

如何在Bokeh悬停工具中显示图像glyph的像素对应直方图计数

解决方案:Bokeh 2.4.3 实现2D直方图Hover显示计数

纯Bokeh实现思路

Bokeh 2.4.3 没有image_index工具,需要通过自定义JS回调手动计算鼠标位置对应的bin索引,再从计数数组H中取值并显示在hover提示里。核心步骤是:

  • 将计数数组H、bin的起始值和步长传入数据源
  • 用HoverTool的customJS回调,把鼠标坐标转换为bin的行列索引
  • 根据索引从H中提取计数,更新hover提示内容

代码示例

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

# 生成测试数据
np.random.seed(42)
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)

# 计算2D直方图
H, xedges, yedges = np.histogram2d(x, y, bins=20)
# 转置H匹配Bokeh的image渲染顺序(行优先对应y轴方向bin)
H = H.T

# 准备数据源:包含图像数据、bin参数和计数数组
source = ColumnDataSource(data={
    'image': [H],
    'x': [xedges[0]],
    'y': [yedges[0]],
    'dw': [xedges[-1] - xedges[0]],
    'dh': [yedges[-1] - yedges[0]],
    'counts': [H.tolist()]  # 转成列表方便JS读取
})

p = figure(width=600, height=600, tools='pan,box_zoom,reset')
# 绘制2D直方图
p.image(image='image', x='x', y='y', dw='dw', dh='dh', source=source, palette='Viridis256')

# 配置HoverTool:通过JS动态更新提示内容
hover = HoverTool(
    tooltips=[
        ('x range', '@x_start - @x_end'),
        ('y range', '@y_start - @y_end'),
        ('count', '@count')
    ],
    callback=CustomJS(args=dict(source=source, xedges=xedges.tolist(), yedges=yedges.tolist()), code="""
        const hover = cb_obj;
        const x_coord = hover.geometries[0].rx;
        const y_coord = hover.geometries[0].ry;
        
        // 计算bin的步长和索引
        const x_step = xedges[1] - xedges[0];
        const y_step = yedges[1] - yedges[0];
        let x_idx = Math.floor((x_coord - xedges[0]) / x_step);
        let y_idx = Math.floor((y_coord - yedges[0]) / y_step);
        
        // 边界处理:避免索引越界
        x_idx = Math.max(0, Math.min(x_idx, xedges.length - 2));
        y_idx = Math.max(0, Math.min(y_idx, yedges.length - 2));
        
        // 提取对应bin的计数
        const count = source.data.counts[0][y_idx][x_idx];
        
        // 更新hover提示文本
        hover.tooltips[0] = ['x range', `${xedges[x_idx].toFixed(2)} - ${xedges[x_idx+1].toFixed(2)}`];
        hover.tooltips[1] = ['y range', `${yedges[y_idx].toFixed(2)} - ${yedges[y_idx+1].toFixed(2)}`];
        hover.tooltips[2] = ['count', count.toString()];
    """)
)

p.add_tools(hover)
show(p)

Holoviews 实现思路

Holoviews 对2D直方图的交互支持更简洁,无需手动编写JS,直接通过Histogram2D结合内置HoverTool即可自动映射计数:

代码示例

import numpy as np
import holoviews as hv
from holoviews import opts

hv.extension('bokeh')

# 生成测试数据
np.random.seed(42)
x = np.random.normal(size=1000)
y = np.random.normal(size=1000)

# 计算2D直方图的bin和计数
H, xedges, yedges = np.histogram2d(x, y, bins=20)
# 创建Holoviews的2D直方图对象
hist2d = hv.Histogram2D((xedges, yedges, H), kdims=['x', 'y'], vdims='count')

# 配置图表和hover提示
hist2d.opts(
    opts.Histogram2D(
        width=600, height=600, palette='Viridis256',
        tools=['hover', 'pan', 'box_zoom', 'reset'],
        tooltip=[('x', '@x_start{0.2f} - @x_end{0.2f}'),
                 ('y', '@y_start{0.2f} - @y_end{0.2f}'),
                 ('count', '@count')]
    )
)

# 渲染图表
hv.render(hist2d)

说明

  • Holoviews 会自动处理bin索引与计数的映射逻辑,无需手动计算
  • 生成的图表基于Bokeh后端,完全兼容现有Bokeh生态,代码量远少于纯Bokeh实现

内容的提问来源于stack exchange,提问作者Anirban Chakraborty

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 10:10:54