2016-08-15 1 views
0

с помощью 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" 

ответ

0

Добавление следующей строки в slider_selection, кажется, что вы хотите:

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

новое определение функции:

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) 

(Хотя немного поздно, я нашел ваш вопрос, пытаясь f ind подобный ответ, я подумал, что это может быть полезно другим).