с помощью Bokeh, я пытаюсь программно обновить словарь .selected
по номеру ColumnDataSource
с помощью обратного вызова слайдера, но не удается получить выбор отражается в сюжете.Bokeh (0.12.1) Обновление DataColumnSource Выбор программно с помощью bokeh serve (только для Python)
В следующем фрагменте, идея заключается в том, что я хочу, чтобы иметь возможность сделать выбор по оси Y. как через ybox_select
инструмента и/или путем регулирования ползунков, которые контролируют положение пары мин/макс линий (ПРИМЕЧАНИЕ: для краткости в этом примере я включил только слайдер и линию «max»). Если возможно, я хочу достичь этого, не используя обратные вызовы CustomJS.
Я применил инструмент ybox_select
(который запускает функцию selection_change
), насколько я могу регулировать горизонтальную линию и значение ползунка (и, конечно, выбор, который происходит неявно). Вместо этого, когда я управляю ползунком (вызывая функцию slider_selection
), мне удается управлять горизонтальной линией, но, по-видимому, не выбор источника. Другими словами, модификация source.data
, которая встречается в slider_selection
, отражается на графике (то есть измененное положение горизонтальной линии), но модификация source.selected
НЕ отражается на графике (или в DataTable, как я проверял отдельно).
После предложения в this thread (где я просил укороченную версию этого вопроса, но не получили никаких ответов до сих пор), я работал над копией source.selected
, а затем копируется обратно в .selected
(то же самое для .data
), но это не имело никакого эффекта.
Должно быть, я пропустил что-то довольно фундаментальное, но не могу понять, что. Есть идеи? Пожалуйста, избегайте предложений, основанных на CustomJS, если вы не уверены, что нет альтернативы pure-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"