在散景中通过鼠标从绘图中提取值
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)
如果你想改进它,请给我反馈。
良好的编码
我有一个函数 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 .
部分解决方案
我发现了一个非常相似的问题
# 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)
如果你想改进它,请给我反馈。
良好的编码