在散景中通过鼠标从绘图中提取值

Extract values from a plot by mouse in bokeh

我有一个函数 y=f(x,a,b),其中 x,y 是自变量和因变量,a,b 是参数。

我想生成一个双面板图 [A,B],其中 A 是 a-versus-b 参数 space,B 是 y-versus-x 函数线。我希望能够在面板 A 中使用鼠标(例如,通过悬停)到 select 一对 (a,b) 值,然后相应地更新面板 B 中的 y--x 行。

我需要什么widget/method才能实现这个目标?我对 bokeh hover tool 做了一些研究,但它生成的是工具提示而不是面板图,而且除了悬停工具中的工具提示语法外,我不知道如何从鼠标中提取值。

PS:我知道这可以通过使用两个滑块(一个用于 a,一个用于 b)来实现,但是使用面板和鼠标可以更灵活地探测 a-b 阶段 space .

部分解决方案

我发现了一个非常相似的问题 on how to extract the value from the mouse hover tool. Combined with another example 关于从不同 widget/subplot 中的回调更改子图,这是一个可行的解决方案,下面列出了一些主要缺点:

# my test
from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource, HoverTool
from bokeh.plotting import Figure, output_notebook, show

output_notebook()

x0 = [x*0.005 for x in range(0, 200)]
y0 = x0
sB = ColumnDataSource(data=dict(x=x0, y=y0))
sA = ColumnDataSource(data = dict(x=[0],y=[0]))

callback = CustomJS(args=dict(sA=sA,sB=sB), code="""
    var geometry = cb_data['geometry'];
    var a = geometry.x; // current mouse x position in plot coordinates
    var b = geometry.y; // current mouse y position in plot coordinates
    var as = sA.get('data')['x'];
    var bs = sA.get('data')['y'];
    as[0] = a;
    bs[0] = b;
    sA.trigger('change');

    var data = sB.data;
    x = data['x']
    y = data['y']
    for (i = 0; i < x.length; i++) {
        y[i] = Math.pow(x[i], a+b) // have to convert python function to js here!!!
    }
    sB.trigger('change');
""")

hover_tool = HoverTool(callback=callback)
A = Figure(x_range=(0,1), y_range=(0,1), tools= [hover_tool,
                        "crosshair,box_zoom,wheel_zoom,pan,reset"])
A.circle(x='x',y='y',source=sA)
B = Figure(x_range=(0,1), y_range=(0,1), tools= ["crosshair,box_zoom,wheel_zoom,pan,reset"])
B.line(x='x',y='y',source=sB)
layout = column(A,B)
show(layout)

此解决方案的一个主要缺点是它利用了我完全不熟悉的 javascript,我必须将函数 f(x,a,b) 从 python 转换为 javascript。如果有任何更好的解决方案可以保留原始 python 功能 f 或其他解决方法,我将不胜感激?

我想我找到了您问题的解决方案。

我给你完整的代码:

from bokeh.plotting import figure,show, ColumnDataSource, output_notebook
from bokeh.models import Label
from bokeh.models import CustomJS, HoverTool
import numpy as np
output_notebook()
TOOLS = "xpan,crosshair"

callback_js ="""
        var geometry = cb_data['geometry'];
        var x_data = geometry.x; // current mouse x position in plot coordinates
        var y_data = geometry.y; // current mouse y position in plot coordinates
        console.log("(x,y)=" + x_data+","+y_data); //monitors values in Javascript console
        date_label.text ='x=' + x_data.toFixed(2) + '    ' + 'y=' + y_data.toFixed(2)
        console.log(date_label.text)
    """


s = ColumnDataSource(data = dict(x=[0,1],y=[0,1])) #points of the line
p = figure(x_range=(0,1), y_range=(0,1),tools=TOOLS)
p.line(x='x',y='y',source=s)
date_label = Label(x=30, y=30, x_units='screen', y_units='screen',
                     text='', render_mode='css',
                     border_line_color='white', border_line_alpha=1.0,
                     background_fill_color='white', background_fill_alpha=1.0)

date_label.text = ""
p.add_layout(date_label)
callback=CustomJS(args={'date_label':date_label},code=callback_js)
p.add_tools(HoverTool(tooltips=None, callback=callback))
show(p)

如果你想改进它,请给我反馈。

良好的编码