如何在Bokeh图表的轴端显示鼠标移动时的坐标信息?
在Bokeh中实现鼠标移动时轴端实时显示时间与价格
可以通过CustomJS回调+自定义文本元素实现需求,无需依赖HoverTool或Crosshair工具的限制。以下是两种实现方案:
方案1:在图表旁实时显示信息
这种方式将信息放在图表右侧,布局清晰直观:
from bokeh.plotting import figure, show from bokeh.models import ColumnDataSource, CustomJS, Div, Row from bokeh.sampledata.stocks import AAPL import pandas as pd # 处理示例数据 df = pd.DataFrame(AAPL) df['date'] = pd.to_datetime(df['date']) source = ColumnDataSource(data=df) # 创建基础图表 p = figure(x_axis_type='datetime', y_axis_label='Price', width=800, height=400, tools='pan,wheel_zoom,reset') p.line('date', 'close', source=source) # 创建用于展示实时信息的Div容器 info_panel = Div( text='<div style="font-size:14px; padding:10px;">日期:<span id="date"></span><br>价格:<span id="price"></span></div>', width=200 ) # 自定义鼠标移动事件回调 mouse_move_callback = CustomJS(args=dict(p=p, info_panel=info_panel), code=""" // 获取鼠标屏幕坐标 const screen_x = cb_obj.x; const screen_y = cb_obj.y; // 将屏幕坐标转换为数据空间的实际值 const data_x = p.x_scale.invert(screen_x); const data_y = p.y_scale.invert(screen_y); // 格式化日期和价格 const date_str = new Date(data_x).toLocaleDateString(); const price_str = '$' + data_y.toFixed(2); // 更新面板显示内容 info_panel.text = `<div style="font-size:14px; padding:10px;">日期:<span id="date">${date_str}</span><br>价格:<span id="price">${price_str}</span></div>`; """) # 绑定鼠标移动事件 p.js_on_event('mousemove', mouse_move_callback) # 组合图表和信息面板 layout = Row(p, info_panel) show(layout)
方案2:直接在轴端显示信息
如果希望信息紧贴轴的末端(如x轴右侧、y轴顶部),可以使用Text元素并动态更新位置:
from bokeh.plotting import figure, show from bokeh.models import ColumnDataSource, CustomJS, Text from bokeh.sampledata.stocks import AAPL import pandas as pd # 处理数据 df = pd.DataFrame(AAPL) df['date'] = pd.to_datetime(df['date']) source = ColumnDataSource(data=df) # 创建图表 p = figure(x_axis_type='datetime', y_axis_label='Price', width=800, height=400, tools='pan,wheel_zoom,reset') p.line('date', 'close', source=source) # 创建轴端文本元素 date_label = Text(x=[0], y=[p.plot_height + 20], text=[''], text_align='right', text_font_size='12pt') price_label = Text(x=[-20], y=[0], text=[''], text_align='right', text_font_size='12pt', angle=90) # 将文本元素添加到图表布局 p.add_layout(date_label, 'above') p.add_layout(price_label, 'left') # 自定义回调逻辑 axis_label_callback = CustomJS(args=dict(p=p, date_label=date_label, price_label=price_label), code=""" const screen_x = cb_obj.x; const screen_y = cb_obj.y; const data_x = p.x_scale.invert(screen_x); const data_y = p.y_scale.invert(screen_y); // 格式化显示内容 const date_str = new Date(data_x).toLocaleDateString(); const price_str = '$' + data_y.toFixed(2); // 更新文本内容和位置(始终固定在轴端) date_label.text = [date_str]; date_label.x = [p.plot_width]; price_label.text = [price_str]; price_label.y = [p.plot_height]; """) p.js_on_event('mousemove', axis_label_callback) show(p)
关键说明
- 使用
js_on_event('mousemove')监听鼠标移动事件,实时获取屏幕坐标 - 通过
x_scale.invert()和y_scale.invert()将屏幕坐标转换为数据空间的实际值(日期、价格) - 可以根据需求调整格式化规则(如日期显示精度、价格小数位数)
内容的提问来源于stack exchange,提问作者forraxa
相关产品推荐
相关产品推荐

