如何从与Bokeh CustomJS函数本地变量同步的ColumnDataSource对象中获取数据?

5
基于以下代码示例,我想从CustomJS函数中提取数据(例如x值)以将其保存在python列表rect_data中。虽然变量x与ColumnDataSource对象source同步,但是当我在执行以下代码的图形中绘制矩形选择时,python列表rect_data仍然为空列表。我做错了什么,如何解决这个问题?谢谢!
# You must first run "bokeh serve" to view this example

from bokeh.models import CustomJS, ColumnDataSource, BoxSelectTool, Range1d, Rect
from bokeh.plotting import figure, show
from bokeh.client import push_session
from bokeh.io import curdoc

source = ColumnDataSource(data=dict(x=[], y=[], width=[], height=[]))

callback = CustomJS(args=dict(source=source), code="""

        var data = source.get('data');
        var geometry = cb_data['geometry'];


        var width = geometry['x1'] - geometry['x0'];
        var height = geometry['y1'] - geometry['y0'];
        var x = geometry['x0'] + width/2;
        var y = geometry['y0'] + height/2;


        data['x'].push(x);
        data['y'].push(y);
        data['width'].push(width);
        data['height'].push(height);


        source.trigger('change');
    """)

box_select = BoxSelectTool(callback=callback)

p = figure(plot_width=400,
           plot_height=400,
           tools=[box_select],
           title="Select Below",
           x_range=Range1d(start=0.0, end=1.0),
           y_range=Range1d(start=0.0, end=1.0))


rect = Rect(x='x',
            y='y',
            width='width',
            height='height',
            fill_alpha=0.3,
            fill_color='#009933')



p.add_glyph(source, rect, selection_glyph=rect, nonselection_glyph=rect)

session = push_session(curdoc())

def update():
    global rect_data
    global source    
    rect_data = source.data['x']
    print(rect_data)


curdoc().add_periodic_callback(update,10)
session.show() 
session.loop_until_closed() 

你在 JavaScript 控制台中看到任何错误吗?此外,你可以在 CustomJS 代码中添加一些 console.log(某些变量); 并检查浏览器的 JavaScript 控制台中的值。在 CustomJS 中,变量是否按照预期发生变化? - Pablo Reyes
CustomJS函数的JavaScript代码没有错误,因为保存在变量“source”中的矩形选择在图形中完美绘制。当我通过JavaScript控制台检查变量“x”(或数组data ['x']的值)的值时,我可以在控制台中获得正确的x值,但是Python列表'rect_data'仍然为空。 - mike
1个回答

3
您可以使用ToolEvents来实现此目的。请参见以下示例。
from bokeh.plotting import figure
from bokeh.client import push_session
from bokeh.io import curdoc
from bokeh.models import ColumnDataSource, CustomJS, BoxSelectTool, Range1d, Rect

source = ColumnDataSource(data=dict(x=[], y=[], width=[], height=[]))

callback = CustomJS(args=dict(source=source), code="""

        var data = source.get('data');
        var geometry = cb_data['geometry'];


        var width = geometry['x1'] - geometry['x0'];
        var height = geometry['y1'] - geometry['y0'];
        var x = geometry['x0'] + width/2;
        var y = geometry['y0'] + height/2;


        data['x'].push(x);
        data['y'].push(y);
        data['width'].push(width);
        data['height'].push(height);


        source.trigger('change');
    """)

box_select = BoxSelectTool(callback=callback)

p = figure(plot_width=400,
           plot_height=400,
           tools=[box_select],
           title="Select Below",
           x_range=Range1d(start=0.0, end=1.0),
           y_range=Range1d(start=0.0, end=1.0))


rect = Rect(x='x',
            y='y',
            width='width',
            height='height',
            fill_alpha=0.3,
            fill_color='#009933')


p.add_glyph(source, rect, selection_glyph=rect, nonselection_glyph=rect, name="selectionbox")

session = push_session(curdoc())

def toolEventsCallback(attr, old, new):
    print("callback", new)
    x0 = new[0]['x0']
    x1 = new[0]['x1']
    print("x0=%f  x1=%f" % (x0, x1))

p.tool_events.on_change("geometries", toolEventsCallback)

session.show() 
session.loop_until_closed() 

至少在Bokeh 0.11.1中,没有向Python发送ColumnDataSource的事件。


太棒了!谢谢Martin! - mike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接