Интерактивный слайдер с использованием Bokeh

Я пытаюсь использовать интерактивный слайдер bokeh, чтобы изменить содержимое графика, аналогично приведенному здесь примеру. У меня есть два вложенных списка x а также y,

Я просто хочу, чтобы ползунок изменил индекс списков для построения графика. т.е. если индекс ползунка = 0, то график x[0] против y[0], если индекс слайдера равен 1, график x[1] против y[1], так далее...

Пример документации вычисляет новые данные на лету, что невозможно для данных, с которыми мне нужно работать.

Когда я запускаю приведенный ниже код, на графике ничего не появляется... Я не знаю javascript, поэтому я предполагаю, что именно здесь я ошибаюсь.

Я использую Python 3.5 и Bokeh 0.12. Все это работает в блокноте Jupyter.

import numpy as np
from bokeh.layouts import row
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import Figure, show
from bokeh.io import output_notebook
from bokeh.resources import INLINE
output_notebook(INLINE)

x = [[x*0.05 for x in range(0, 500)],
     [x*0.05 for x in range(0, 500)]]

y = [np.sin(x[0]), 
     np.cos(x[1])]

source = ColumnDataSource(data=dict(x=x, y=y))

plot = Figure(plot_width=400, plot_height=400)
plot.line('x'[0], 'y'[0], source=source, line_width=3, line_alpha=0.6)

callback = CustomJS(args=dict(source=source), code="""
        var data = source.get('data');
        var f = cb_obj.get('value');
        x = data['x'][f];
        y = data['y'][f];
        source.trigger('change');
    """)

slider = Slider(start=0, end=1, value=0, step=1, title="index", callback=callback)
layout = row(plot, slider)
show(layout)

1 ответ

Решение

Вместо ползунка, изменяющего индекс данных, которые будут нанесены на график, вы можете определить два ColumnDataSource s: source_visible а также source_available где первый содержит данные, которые в данный момент отображаются на графике, а второй действует как хранилище данных, из которого мы можем получить данные в CustomJS обратный вызов, основанный на выборе пользователя на веб-странице:

import numpy as np
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, Slider, CustomJS
from bokeh.plotting import Figure, show

# Define data
x = [x*0.05 for x in range(0, 500)]
trigonometric_functions = {
    '0': np.sin(x),
    '1': np.cos(x),
    '2': np.tan(x),
    '3': np.arctan(x)}
initial_function = '0'

# Wrap the data in two ColumnDataSources
source_visible = ColumnDataSource(data=dict(
    x=x, y=trigonometric_functions[initial_function]))
source_available = ColumnDataSource(data=trigonometric_functions)

# Define plot elements
plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source_visible, line_width=3, line_alpha=0.6)
slider = Slider(title='Trigonometric function',
                value=int(initial_function),
                start=np.min([int(i) for i in trigonometric_functions.keys()]),
                end=np.max([int(i) for i in trigonometric_functions.keys()]),
                step=1)

# Define CustomJS callback, which updates the plot based on selected function
# by updating the source_visible ColumnDataSource.
slider.callback = CustomJS(
    args=dict(source_visible=source_visible,
              source_available=source_available), code="""
        var selected_function = cb_obj.value;
        // Get the data from the data sources
        var data_visible = source_visible.data;
        var data_available = source_available.data;
        // Change y-axis data according to the selected value
        data_visible.y = data_available[selected_function];
        // Update the plot
        source_visible.change.emit();
    """)

layout = row(plot, slider)
show(layout)

Имейте в виду, что если ваши данные большие, может потребоваться некоторое время, чтобы отправить их все сразу в браузер клиента.

Другие вопросы по тегам