编程语言
首页 > 编程语言> > 如何获取Bokeh小部件事件和属性列表(可用于触发Python回调)

如何获取Bokeh小部件事件和属性列表(可用于触发Python回调)

作者:互联网

真正的(一般)问题

我是Bokeh的新手,我正在尝试构建一个可以根据小部件提供的输入动态更新的情节.但是,大多数小部件都没有完全记录Python回调的使用,因此我被卡住了.

>我如何知道应该使用哪种窗口小部件方法来附加回调?我可以通过在交互式控制台中探测窗口小部件属性来猜测可用的选择,但这并不优雅,我确信它是在文档中的某处写的.
>如果我知道要使用的方法(例如on_event或on_change),我仍然需要弄清楚它的签名和参数.例如,如果我使用on_change,我可以监控哪些小部件属性?
>一旦我知道我可以监控哪个属性,我怎么知道事件将产生的数据结构?

一些更多的背景和(不是有用的)具体问题

这是一个恰当的例子.我正在使用像this example这样的笔记本嵌入式服务器.作为练习,我想用具有任意值的DataTable替换滑块.这是我目前的代码:

from bokeh.layouts import column
from bokeh.models import ColumnDataSource, DataTable
from bokeh.plotting import figure
from bokeh.io import show, output_notebook

from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature

output_notebook()

def modify_doc(doc):
    df = sea_surface_temperature.copy()
    source = ColumnDataSource(data=df)
    source_table = ColumnDataSource(data={"alpha": [s for s in "abcdefgh"], 
                                          "num": list(range(8))})

    plot = figure(x_axis_type='datetime', y_range=(0, 25),
                  y_axis_label='Temperature (Celsius)',
                  title="Sea Surface Temperature at 43.18, -70.43")
    plot.line('time', 'temperature', source=source)

    def callback(attr, old, new):
        # This is the old callback from the example. What is "new" when I use 
        # a table widget?
        if new == 0:
            data = df
        else:
            data = df.rolling('{0}D'.format(new)).mean()
        source.data = ColumnDataSource(data=data).data

    table = DataTable(source=source_table, 
                      columns=[TableColumn(field="alpha", title="Alpha"),
                               TableColumn(field="num", title="Num")])
    # How can I attach a callback to table so that the plot gets updated 
    # with the "num" value when I select a row?
    # table.on_change("some_attribute", callback)

    doc.add_root(column(table, plot))

show(modify_doc)

解决方法:

JavaScript callbacksPython callbacks是Bokeh中非常强大的工具,可以附加到任何Bokeh模型元素.此外,您可以通过编写自己的extensions with TypeScript(最终编译为JS)来扩展Bokeh功能

可以使用以下两种方法之一添加JS回调:

Model.js_on_event('event', callback)
Model.js_on_change('attr', callback)

Python回调主要用于小部件:

Widget.on_event('event, onevent_handler)
Widget.on_change('attr', onchange_handler)
Widget.on_click(onclick_handler)

每个小部件的事件处理程序的确切函数签名,可以是:

onevent_handler(event)
onchange_handler(attr, old, new) 
onclick_handler(new)
onclick_handler()

attr可以是任何窗口小部件类(或它的基类)属性.因此,您需要始终参考Bokeh reference pages.同时扩展JSON Prototype有助于找出支持的属性,例如看看Div,我们无法直接看到来自其基类的id,name,style或text属性.但是,所有这些属性都存在于Div的JSON原型中,因此得到Div的支持:

{
  "css_classes": [],
  "disabled": false,
  "height": null,
  "id": "32025",
  "js_event_callbacks": {},
  "js_property_callbacks": {},
  "name": null,
  "render_as_text": false,
  "sizing_mode": "fixed",
  "style": {},
  "subscribed_events": [],
  "tags": [],
  "text": "",
  "width": null
}

回到你的问题:很多时候你可以使用不同的方法获得相同的结果.

据我所知,没有很好的方法列出每个小部件的所有支持事件,但阅读文档和深入挖掘基类有很大帮助.

使用上述方法可以检查可以在回调中使用哪些窗口小部件属性.当涉及到事件时,我建议您查看并探索IDE中的bokeh.events类.您可以找到每个事件的扩展描述.在使用程序员的直觉来选择窗口小部件支持的正确事件时,它会自然而然地发生(因此没有用于Plot的button_click而没有用于Button的pan事件,反之亦然).

决定哪个小部件(模型元素)附加回调以及选择哪个方法或哪个事件绑定回调是你的,主要取决于:哪个用户操作应该触发你的回调?

因此,您可以将JS回调附加到任何窗口小部件(值更改,滑块移动等等),任何工具(TapTool,HoverTool等等),data_source(单击字形),绘制画布(例如,用于点击在字形之外的区域)或绘图范围(缩放或平移事件)等…

基本上你需要知道所有Python对象都有它们在BokehJS中的等价物,所以你可以在两个域中以相同的方式使用它们(当然,有一些语法差异).

This documentation显示例如ColumnDataSource具有“selected”属性,因此对于点,您可以检查source.selected.indices并查看图中哪个点被选中或类似于:选择了哪些表行.您可以在Python中以及在浏览器中的代码中设置断点,并检查Python或BokehJS数据结构.

这是你的代码(稍微修改为“纯Bokeh”v1.0.4,因为我没有安装Jupiter Notebook)

from bokeh.layouts import column
from bokeh.models import ColumnDataSource, DataTable, TableColumn
from bokeh.plotting import figure, curdoc
from bokeh.io import show, output_notebook
from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature

# output_notebook()
def modify_doc(doc):
    df = sea_surface_temperature.copy()
    source = ColumnDataSource(data = df)
    source_table = ColumnDataSource(data = {"alpha": [s for s in "abcdefgh"],
                                            "num": list(range(8))})

    plot = figure(x_axis_type = 'datetime', y_range = (0, 25),
                  y_axis_label = 'Temperature (Celsius)',
                  title = "Sea Surface Temperature at 43.18, -70.43")
    plot.line('time', 'temperature', source = source)

    def callback(attr, old, new):  # here new is an array containing selected rows
        if new == 0:
            data = df
        else:
            data = df.rolling('{0}D'.format(new[0])).mean()  # asuming one row is selected

        source.data = ColumnDataSource(data = data).data

    table = DataTable(source = source_table,
                      columns = [TableColumn(field = "alpha", title = "Alpha"),
                                 TableColumn(field = "num", title = "Num")])
    source_table.selected.on_change('indices', callback)

    doc().add_root(column(table, plot))

modify_doc(curdoc)
# show(modify_doc)

结果:

enter image description here

标签:python,bokeh
来源: https://codeday.me/bug/20191006/1858915.html