【发布时间】:2016-08-15 11:10:24
【问题描述】:
使用 Bokeh,我试图通过 Slider 的回调以编程方式更新 .selected 的 .selected 字典,但无法设法使选择反映在情节中。
在下面的 sn-p 中,我希望能够通过ybox_select 工具和/或通过调整控制一对最小/最大线的位置(注意:为简洁起见,在此示例中,我只包括了“最大”滑块和线)。如果可能的话,我想在不使用 CustomJS 回调的情况下实现这一点。
我在操作ybox_select 工具(触发selection_change 函数)时调整了水平线和滑块值(当然还有选择,这是隐式发生的)。相反,当我操作滑块(触发slider_selection 函数)时,我设法控制了水平线,但显然不是源选择。换言之,slider_selection 中发生的source.data 的修改会反映在绘图中(即水平线的修改位置),但source.selected 的修改不会反映在绘图中(也不反映在 DataTable 中,正如我单独验证的那样)。
按照this thread 中的建议(我已经问过这个问题的简短版本,但到目前为止没有得到任何答案),我已经制作了source.selected 的副本,然后复制回@ 987654332@(.data 相同),但这没有任何影响。
我一定错过了一些相当基本的东西,但不知道是什么。任何想法?请避免基于 CustomJS 的建议,除非您确定没有纯 Python 替代方案。
非常感谢您的任何反馈!
(注意:使用bokeh serve --show script.py将此代码作为脚本运行)
from bokeh.io import curdoc
from bokeh.models import BoxSelectTool, Slider
from bokeh.plotting import figure, ColumnDataSource
from bokeh.sampledata.glucose import data
from bokeh.layouts import column
import numpy as np
#===============================================================================
# Data and source
y = data.ix['2010-10-06']['glucose']
x = np.arange(len(y))
maxval=[max(y)]*len(x)
source = ColumnDataSource(dict(x=x, y=y, maxval=maxval))
#===============================================================================
# Basic plot setup
tools = 'wheel_zoom,ybox_select,reset'
p = figure(plot_width=800, plot_height=400, tools=tools, title='Min/max selection')
# Plot data
cr = p.circle('x', 'y', color="blue", source = source,
selection_color="blue", nonselection_color="gray",
size=6, alpha=0.8)
# Plot max horizontal line
p.line('x', 'maxval', line_color='blue', line_width=0.5, source=source,
nonselection_alpha=1.0, nonselection_color='blue')
#===============================================================================
# Callbacks
def selection_change(attrname, old, new):
ixs = new['1d']['indices']
if ixs:
arr = np.asarray(source.data['y'])[ixs]
max_slider.value = np.max(arr)
source.data['maxval'] = [np.max(arr)]*len(source.data['x'])
def slider_selection(attrname, old, new):
selected = source.selected.copy()
data = source.data.copy()
data['maxval'] = [max_slider.value]*len(data['x'])
yy = np.asarray(data['y'])
maxi = np.asarray(data['maxval'])
# Below is the new selection I would to visualize
selected['1d']['indices'] = np.where(yy <= maxi)[0].tolist()
# Updated data is reflected in the plot (horizontal line at 'maxval' moves)
source.data = data.copy()
# Updated selection is NOT reflected in the plot
# (nor in a DataTable, as tested separately)
source.selected = selected.copy()
#===============================================================================
# Slider
max_slider = Slider(start=min(y), end=max(y),
value=max(y), step=0.1, title="Maximum")
#===============================================================================
# Trigger callbacks
source.on_change('selected', selection_change)
max_slider.on_change('value', slider_selection)
#===============================================================================
# Layout
plot_layout = column(p, max_slider)
curdoc().add_root(plot_layout)
curdoc().title = "Demo"
【问题讨论】: