Bokeh(0.12.1)使用Bokeh serve以编程方式更新DataColumnSource选择(仅限于Python)

2024-04-28 12:55:22 发布

您现在位置:Python中文网/ 问答频道 /正文

使用Bokeh,我试图通过一个滑块的回调,以编程方式更新.selected字典,但无法在绘图中反映选择。在

在下面的代码片段中,我希望能够通过ybox_select工具和/或通过调整控制一对最小/最大线位置的滑块来进行y轴选择both(注意:为了简洁起见,在本例中我只包含了“max”滑块和线)。如果可能,我希望不使用CustomJS回调来实现这一点。在

当我操作ybox_select工具(它触发selection_change函数)时,我已经调整了水平线和滑块值(当然还有选择,这是隐式的)。相反,当我操作滑块(触发slider_selection函数)时,我设法控制水平线,但显然不是源代码选择。换句话说,在slider_selection中发生的source.data的修改反映在绘图中(即水平线的修改位置),但是{}的修改没有反映在绘图中(也没有反映在数据表中,正如我单独验证的那样)。在

按照this thread中的建议(我问了这个问题的一个简短版本,但到目前为止没有得到任何答案),我制作了一个source.selected的副本,然后复制回.selected(与{}相同),但这没有任何效果。在

我一定是错过了一些很基本的东西,但我不知道是什么。有什么想法吗?请避免基于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"

Tags: fromimportsourcedataplotnpbokehchange
1条回答
网友
1楼 · 发布于 2024-04-28 12:55:22

将以下行添加到slider_selection中似乎可以执行您想要的操作:

source.trigger("selected", old, selected)

新函数定义:

^{pr2}$

(虽然有点晚了,但我发现你的问题试图找到一个类似的答案,我想这可能对其他人有用)。在

相关问题 更多 >