Bokeh - Обновление графика с помощью виджета Select и CustomJS - PullRequest
0 голосов
/ 14 апреля 2020

Я пытаюсь отобразить гистограмму и отфильтровываю содержимое объекта Select. Столь же простой, как кажется, я не смог найти рабочее решение после двух дней поиска. Мне нужно сделать это с Custom JS, а не с сервером bokeh.

Вот код, который я пробую, но когда я его запускаю, ничего не отображается, даже пустой график.

import pandas as pd
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, CustomJS, CustomJSFilter, CDSView, Select, IndexFilter
from bokeh.io import show, output_notebook
from bokeh.layouts import column
output_notebook()

df = pd.DataFrame({'Subject': ['Math', 'Math', 'Math', 'Science', 'Science', 'Science'],
                  'Class': ['Algebra', 'Calculus', 'Trigonometry', 'Biology', 'Chemistry', 'Physics'],
                  'FailRate': [0.05, 0.16, 0.31, 0.12, 0.20, 0.08]})

src = ColumnDataSource(df)

subj_list = sorted(list(set(src.data['Subject'])))

callback = CustomJS(args=dict(src=src), code='''
    src.change.emit();
''')

js_filter = CustomJSFilter(code='''
var indices = [];
for (var i = 0; i < src.get_length(); i++){
    if (src.data['Subject'][i] == select.value){
        indices.push(true);
    } else {
        indices.push(false);
    }
}
return indices;
''')

options = ['Please select...'] + subj_list
select = Select(title='Subject Selection', value=options[0], options=options)

select.js_on_change('value', callback)

view = CDSView(source=src, filters=[js_filter])

class_list = sorted(list(src.data['Class']))

p = figure(x_range=class_list, plot_height=400, plot_width=400) 
p.vbar('Class', top='FailRate', width=0.9, source=src, view=view)

show(column(select, p))

Насколько я могу судить, часть проблемы связана с этой строкой (или переменной 'view'):

p.vbar('Class', top='FailRate', width=0.9, source=src, view=view)

До того, как я добавил 'view = view' в В приведенной выше строке я по крайней мере получал окно выбора и график, хотя взаимодействие не работало.

1 Ответ

0 голосов
/ 14 апреля 2020

Bokeh может волшебным образом транспортировать ваши Python объекты во время выполнения, чтобы отображаться в ваших браузерах как JavaScript объекты, но есть ограничения для маги c. Вы должны точно указать Bokeh , какие объекты следует транспортировать, указав параметр args для объекта CustomJS. Кроме того, это проще, если вы используете обратный вызов для обновления индексов в IndexFilter. Тогда вам нужен только один обратный вызов:

filter = IndexFilter(indices=[])

callback = CustomJS(args=dict(src=src, filter=filter), code='''
  const indices = []
  for (var i = 0; i < src.get_length(); i++) {
    console.log(i, src.data['Subject'][i], cb_obj.value)
    if (src.data['Subject'][i] == cb_obj.value) {
      indices.push(i)
    }
  }
  filter.indices = indices
  src.change.emit()
''')

select.js_on_change('value', callback)

view = CDSView(source=src, filters=[filter])

Последнее замечание: вместо передачи и использования select я использовал неявную переменную cb_obj, которая всегда является объектом, который вызвал изменение. (Может быть ошибка с использованием переданного выбора)

РЕДАКТИРОВАТЬ: Нет, ошибки нет. Проблема заключалась в том, что Select был определен после обратного вызова, и, поскольку вещи были в записной книжке, он использовал значение из предыдущего выполнения ячейки. К сожалению, характер ноутбука * intrinsi c делает проблемы с поврежденным состоянием очень легко достижимыми, в целом. Если вы сначала определите Select, то код будет работать, как и ожидалось, с select вместо cb_obj:

options = ['Please select...'] + subj_list
select = Select(title='Subject Selection', value=options[0], options=options)

cb = CustomJS(args=dict(select=select, src=src, filter=filter), ...)

даже при повторных вызовах ячейки. Обратите внимание, что в cb_obj нет ничего плохого, но многие люди предпочитают явно передавать (и называть) виджеты.

В качестве заключительного замечания я упомяну, что для проверки отладки необходимо научиться проверять консоль JS браузера. CustomJS тип обратных вызовов. Ошибки из вашего кода тут же обнаружились.

...