我是 Bokeh 新手,我正在尝试构建一个可以根据小部件提供的输入动态更新的图。然而,对于大多数小部件来说,Python 回调的使用并没有完整记录,因此我陷入了困境。
on_event
或on_change
),我仍然需要弄清楚它的签名和参数。例如,如果我使用 on_change
,我可以监控哪些小部件属性?这是一个合适的例子。我正在使用笔记本嵌入式服务器,如此示例中所示。作为练习,我想用具有任意值的
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)
此答案是针对 Bokeh v1.0.4 给出的,可能不符合最新文档
JavaScript 回调 和 Python 回调,是 Bokeh 中非常强大的工具,可以附加到任何 Bokeh 模型元素。此外,您可以通过使用 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 参考页。扩展 JSON 原型还有助于找出支持哪些属性,例如查看 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
}
回到你的问题:很多时候你可以使用不同的方法获得相同的结果。
据我所知,没有很好的方法来列出每个小部件所有支持的事件,但阅读文档并深入研究基类有很大帮助。
使用上述方法可以检查您可以在回调中使用哪些小部件属性。当谈到 events 时,我建议您查看并探索 IDE 中的
bokeh.events
类。您可以找到每个事件的详细描述。随着时间的推移,当使用程序员的直觉选择小部件支持的正确事件时,它会自然而然地出现(因此 button_click
没有 Plot
,pan
没有 Button
事件,但反之亦然)。
决定将回调附加到哪个小部件(模型元素)以及选择哪种方法或将回调绑定到哪个事件是您的决定,主要取决于:哪个用户操作应触发您的回调?
因此,您可以将 JS 回调附加到任何小部件(值更改、滑块移动等)、任何工具(TapTool、HoverTool 等)、数据源(单击字形)、绘图画布(例如,单击字形之外的区域)或绘图范围(缩放或平移事件)等...
基本上,您需要知道所有 Python 对象在 BokehJS 中都有其等效项,这样您就可以在两个领域中以相同的方式使用它们(当然,有一些语法差异)。
本文档显示,ColumnDataSource具有“选定”属性,因此对于点,您可以检查
source.selected.indices
并查看选择了绘图上的哪个点,或者在您的情况下:选择了哪些表行。您可以在 Python 代码和浏览器中设置断点,并检查 Python 或 BokehJS 数据结构。当运行代码时,它有助于在 IDE(运行配置)或终端(例如 BOKEH_MINIFIED
)中将环境变量 no
设置为 BOKEH_MINIFIED=no python3 main.py
。这将使在浏览器中调试 BokehJS 变得更加容易。
这是你的代码(对“pure 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)
结果: