[英]Bokeh (0.12.1) Update DataColumnSource Selection programmatically with bokeh serve (Python only)
using Bokeh, I am trying to update the .selected
dictionary of a ColumnDataSource
programmatically, via the callback of a Slider, but cannot manage to get the selection reflected in the plot. 使用Bokeh,我试图通过Slider的回调以编程方式更新ColumnDataSource
的.selected
字典,但无法设法使选择反映在图中。
In the following snippet, the idea is that I want to be able to make a y-axis selection both via the ybox_select
tool and/or by adjusting the sliders that control the position of a pair of min/max lines (NOTE: for brevity, in this example I only included the 'max' slider and line). 在下面的代码段中,这个想法是,我希望能够使经由所述y轴的选择既 ybox_select
工具和/或通过调整控制一对的最小/最大线(注的位置的滑块:为了简洁,在此示例中,我仅包含了“最大”滑块和一行)。 If possible, I want to achieve this without using CustomJS callbacks. 如果可能,我想在不使用CustomJS回调的情况下实现这一目标。
I got as far as adjusting the horizontal line and the slider value (and of course the selection, which happens implicitly) when I operate the ybox_select
tool (which triggers the selection_change
function). 当我操作ybox_select
工具(触发selection_change
函数)时,我可以调节水平线和滑块值(当然还有选择,它是隐式发生的)。 Instead, when I operate the slider (triggering the slider_selection
function), I manage to control the horizontal line but, apparently, not the source selection. 相反,当我操作滑块(触发slider_selection
函数)时,我设法控制水平线,但显然不是源选择。 In other words, the modification of source.data
that occurs in slider_selection
is reflected in the plot (ie the modified position of the horizontal line) but the modification of source.selected
is NOT reflected in the plot (nor in a DataTable, as I verified separately). 换句话说,在source.data
中发生的对slider_selection
的修改反映在图中(即,水平线的修改位置),但是对source.selected
的修改source.selected
反映在图中(也不在DataTable中,因为我单独验证)。
Following the suggestion in this thread (where I've asked a shorter version of this question but didn't get any answers so far), I've worked on a copy of source.selected
and then copied back to .selected
(same for .data
), but this didn't have any effects. 按照该主题的建议(我曾问过这个问题的简短版本,但到目前为止还没有得到任何答案),我研究了source.selected
的副本,然后又复制回.selected
(与.data
),但这没有任何效果。
I must be missing something rather fundamental, but cannot figure out what. 我必须错过一些基本的东西,但不能弄清楚是什么。 Any idea? 任何想法? Please avoid suggestions based on CustomJS, unless you're sure that there is no pure-Python alternative. 请避免基于CustomJS的建议,除非您确定没有纯Python的替代方法。
Thanks a lot for any feedback! 非常感谢您的任何反馈!
(Note: run this code as a script with bokeh serve --show script.py
) (注意:将此代码作为脚本与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"
Adding the following line to slider_selection seems to do what you want: 将以下行添加到slider_selection似乎可以满足您的要求:
source.trigger("selected", old, selected)
the new function definition: 新函数定义:
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()
source.trigger("selected", old, selected)
(Though it's a bit late, I found your question trying to find a similar answer, I figured this might be useful to others). (尽管为时已晚,但我发现您的问题试图找到类似的答案,但我认为这可能对其他人有用)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.