如何获取Bokeh小部件事件和属性的列表(可用于触发Python回调) [英] How to get a list of Bokeh widget events and attributes (which can be used to trigger a Python callback)
问题描述
真正的(一般)问题
我是Bokeh的新手,我正在尝试构建一个可以根据小部件提供的输入动态更新的图.但是,对于大多数小部件,Python回调的用法尚未完全记录下来,因此我陷入了困境.
- 我如何知道应该使用哪种窗口小部件方法来附加我的回调?我可以通过在交互式控制台中探查widgets属性来猜测可用的选择,但这并不优雅,并且我敢肯定它写在文档中的某个地方.
- 假设我知道要使用的方法(例如
on_event
或on_change
),我仍然必须弄清楚其签名和参数.例如,如果我使用on_change
,我可以监视哪些窗口小部件属性? - 一旦我知道可以监视的属性,我如何知道事件将产生的数据结构?
更多上下文和(未使用)特定问题
这是一个适当的示例.我正在使用 this中的笔记本嵌入式服务器例子.作为练习,我想用带有任意值的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)
可以使用以下两种方法之一添加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
}
回到您的问题:很多时候,您可以使用不同的方法获得相同的结果.
据我所知,没有一种很好的方法可以列出每个小部件的所有受支持的事件,但是阅读文档并深入研究基类会大有帮助.
使用上述方法,可以检查您可以在回调中使用哪些小部件属性.当涉及到事件时,建议您在IDE中查看和探索bokeh.events
类.您可以在其中找到每个事件的扩展说明.随着时间的推移,使用程序员的直觉来选择窗口小部件支持的正确事件将自然而然地发生(因此对于Plot
来说没有button_click
,对于Button
来说没有pan
事件,反之亦然).
决定是将哪个小部件(模型元素)附加到回调以及选择哪种方法或将回调绑定到哪个事件的决定主要取决于:哪个用户操作应触发您的回调? >
因此,您可以将JS回调附加到任何小部件(值更改,滑块移动等),任何工具(TapTool,HoverTool等...),data_source(单击字形),绘制画布(例如点击字形以外的区域)或绘图范围(缩放或平移事件),等等... 基本上,您需要了解所有Python对象在BokehJS中都有它们的等效项,因此您可以在两个域中以相同的方式使用它们(当然,在语法上有所不同). 本文档例如显示ColumnDataSource具有"selected"属性,因此对于点,您可以检查 这是您的代码(由于我没有安装Jupiter Notebook,因此对"pure Bokeh" v1.0.4做了一些修改) 结果: I am new to Bokeh and I am trying to build a plot which can be dynamically updated based on input provided by a widget. However, usage of Python callbacks is not thoroughly documented for most widgets and therefore I'm stuck.
Here is an appropriate example. I am using a notebook-embedded server like in this example. As an exercise, I would like to replace the slider with a
This answer was given for Bokeh v1.0.4 and may not be compliant with the latest documentation JavaScript callbacks and Python callbacks, are very powerful tools in Bokeh and can be attached to any Bokeh model element. Additionally you can extend Bokeh functionality by writing your own extensions with TypeScript (eventually compiled to JS) JS callbacks can be added using either of both methods: Python callbacks are mainly used for widgets: The exact function signature for event handlers very per widget and can be: The Coming back to your question: Many times you can achieve the same result using different approaches. To my knowledge, there is no nice method that lists all supported events per widget but reading documentation and digging into the base classes helps a lot. Using methods described above it is possible to check which widget attributes you can use in your callbacks. When it comes to events I advice you to look at and explore the Decision to which widget (model element) attach the callback and which method to choose or to which event bound the callback is yours and depends mainly on: which user action should trigger your callback? So you can have a JS callback attached to any widget (value change, slider move, etc...), any tool (TapTool, HoverTool, etc...), data_source (clicking on glyph), plot canvas (e.g. for clicks on area outside a glyph) or plot range (zoom or pan events), etc... Basically you need to know that all Python objects have their equivalents in BokehJS so you can use them the same way in both domains (with some syntax differences, of course). This documentation shows for example that ColumnDataSource has a "selected" property so for points you can inspect And here is your code (slightly modified for "pure Bokeh" v1.0.4 as I don't have Jupiter Notebook installed) Result: 这篇关于如何获取Bokeh小部件事件和属性的列表(可用于触发Python回调)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!source.selected.indices
并查看选择了绘图上的哪个点,或者与您的情况类似:选择了哪些表行.您可以在Python和浏览器中的代码中设置断点,并检查Python或BokehJS数据结构.在运行代码时,可以在IDE(运行配置)或终端(例如BOKEH_MINIFIED=no python3 main.py
)中将环境变量BOKEH_MINIFIED
设置为no
.这将使在浏览器中调试BokehJS更加容易.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)
The real (general) question
on_event
or on_change
), I still have to figure out its signature and arguments. For instance, if I'm using on_change
, which widget attributes can I monitor?Some more context and the (not-as-useful) specific question
DataTable
with arbitrary values. Here is the code I currently have: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)
Model.js_on_event('event', callback)
Model.js_on_change('attr', callback)
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
can be any widget class (or it's base class) attribute. Therefore you need always to consult the Bokeh reference pages. Also expanding the JSON Prototype helps to find out which attributes are supported e.g. looking at Div we cannot see directly the id
, name
, style
or text
attributes which come from its base classes. However, all of these attributes are present in the Div's JSON Prototype and hence are supported by 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
}
bokeh.events
class in your IDE. You can find there extended description for every event. In time it will come naturally when using your programmer's intuition to select the right event that your widget supports (so no button_click
for Plot
and no pan
event for Button
but the other way around). source.selected.indices
and see which point on the plot are selected or like in your case: which table rows are selected. You can set a breakpoint in code in Python and also in the browser and inspect the Python or BokehJS data structures. It helps to set the environment variable BOKEH_MINIFIED
to no
either in you IDE (Run Configuration) or in Terminal (e.g. BOKEH_MINIFIED=no python3 main.py
) when running your code. This will make debugging the BokehJS in the browser much easier.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)