Как реализовать обратный вызов Javascript для виджета с множественным выбором в Bokeh - PullRequest
0 голосов
/ 17 мая 2019

Я новичок в Bokeh и Javascript, и я пытаюсь реализовать простой виджет с множественным выбором в Bokeh.Идея состоит в том, чтобы просто отобразить данные x и y на диаграмме рассеяния в зависимости от буквы или букв, выбранных пользователем (A, B, C).График должен быть пустым, прежде чем пользователь выберет выбор.Проблема заключается в обратном вызове Javascript: ничего не происходит, когда я выбираю запись с виджетом MultiSelect.Код ниже.

from bokeh.models import CustomJS, ColumnDataSource, MultiSelect, Column
from bokeh.plotting import figure, show
import pandas as pd

data = dict(letter = ['A','A','B','C','B','B','A','C','C','B'], 
x = [1, 2, 1, 2, 3, 2, 2, 3, 2, 3], 
y = ['10','20','10','30','10','40','10','30','10','40'])
data = pd.DataFrame(data)

data_source = ColumnDataSource(data)
source = ColumnDataSource(dict(letter = [], x = [], y = []))

plot = figure()
plot.circle('x', 'y', line_width = 2, source = source)

callback = CustomJS(args = {'source': source, 'data_source': data_source},
code = """
var data = data_source
source.data = data[cb_obj.value];
""")

multiselect = MultiSelect(title = 'Choose', value = [], options = ['A', 'B', 'C'])
multiselect.js_on_change('value', callback)

layout = Column(multiselect, plot)
show(layout)

Есть идеи?

1 Ответ

0 голосов
/ 17 мая 2019

Вы на правильном пути.Если вы хотите отфильтровать данные, как правило, рекомендуется иметь «основной» источник данных, из которого можно извлекать только необходимые элементы при изменении отфильтрованного значения.Я считаю, что проще всего сделать это с помощью циклов (см. Код ниже).Кроме того, не забывайте всегда вносить изменения в источник в конце обратного вызова.

from bokeh.models import CustomJS, ColumnDataSource, MultiSelect, Column

from bokeh.plotting import figure, show
import pandas as pd

data = dict(letter = ['A','A','B','C','B','B','A','C','C','B'], 
x = [1, 2, 1, 2, 3, 2, 2, 3, 2, 3], 
y = ['10','20','10','30','10','40','10','30','10','40'])
data = pd.DataFrame(data)

data_source = ColumnDataSource(data)
source = ColumnDataSource(dict(x = [], y = []))

plot = figure()
plot.circle('x', 'y', line_width = 2, source = source)

callback = CustomJS(args = {'source': source, 'data_source': data_source},
code = """
var data = data_source.data;
var s_data = source.data;
var letter = data['letter'];
var select_vals = cb_obj.value;
var x_data = data['x'];
var y_data = data['y'];
var x = s_data['x'];
x.length = 0;
var y = s_data['y'];
y.length = 0;
for (var i = 0; i < x_data.length; i++) {
    if (select_vals.indexOf(letter[i]) >= 0) {
        x.push(x_data[i]);
        y.push(y_data[i]);
        }
}
source.change.emit();
""")

multiselect = MultiSelect(title = 'Choose', value = [], options = ['A', 'B', 'C'])
multiselect.js_on_change('value', callback)
layout = Column(multiselect, plot)
show(layout)

Общий комментарий: я, как и вы, только недавно начал использовать Bokeh, и я новичок в JS, тоже.Я нашел примеры в руководстве пользователя Bokeh , очень полезные.

...