Несоответствие фильтрации данных в Боке

#python #bokeh

#python #bokeh

Вопрос:

Прошу прощения, но я не могу создать какой-либо воспроизводимый код для этого вопроса, поскольку он довольно противоречив.

Итак, у меня есть таблица данных bokeh, и я выполняю с ней некоторую фильтрацию, используя 4 выпадающих списка. Таблица данных обновляется на основе значения выпадающего списка, и обновления были написаны на JS. Фильтрация работает, как ожидалось, но, как ни странно, для некоторых очень специфических комбинаций выпадающих значений она ничего не отображает в таблице данных. Мне было интересно, была ли это проблема с моими данными, но я принудительно преобразовал все в строки, и это все равно вызвало у меня ту же проблему.

Обновления написаны здесь:

 combined_callback_code = """
var data = source.data;

var original_data = original_source.data;

var origin = origin_select_obj.value;

var classification = classification_select_obj.value;

var currency = currency_select_obj.value;

var grade = grade_select_obj.value;

for (var key in original_data) {
    data[key] = [];
    for (var i = 0; i < original_data['Origin'].length;   i) {
        if ((origin === "ALL" || original_data['Origin'][i] === origin) amp;amp;
            (classification === "ALL" || original_data['Classification'][i] === classification) amp;amp;
            (currency === "ALL" || original_data['Currency'][i] === currency) amp;amp;
            (grade === "ALL" || original_data['BrokenPct'][i] === grade)){
            data[key].push(original_data[key][i]);
            }
    }
    }

target_obj.change.emit();
source.change.emit();
"""



# define the filter widgets, without callbacks for now
origin_list = ['ALL']   df['Origin'].unique().tolist()
origin_select = Select(title="Origin:", value=origin_list[0], options=origin_list)

classification_list = ['ALL']   df['Classification'].unique().tolist()
classification_select = Select(title="Classification:", value=classification_list[0], options=classification_list)

currency_list = ['ALL']   df['Currency'].unique().tolist()
currency_select = Select(title = "Currency:", value=currency_list[0], options = currency_list)

grade_list = ["ALL"]   df['BrokenPct'].unique().tolist()
grade_select = Select(title = "Grade:", value = grade_list[0], options = grade_list)

# now define the callback objects now that the filter widgets exist
generic_callback = CustomJS(
    args=dict(source=source, 
              original_source=original_source, 
              origin_select_obj=origin_select, 
              classification_select_obj=classification_select,
              currency_select_obj = currency_select,
              grade_select_obj = grade_select,
              target_obj=data_table),
    code=combined_callback_code
)


# finally, connect the callbacks to the filter widgets
origin_select.js_on_change('value', generic_callback)
classification_select.js_on_change('value', generic_callback)
currency_select.js_on_change('value', generic_callback)
grade_select.js_on_change('value', generic_callback)
  

Ответ №1:

Правильный способ обновления табличных данных в вашем обратном вызове JS заключается в следующем:

 var data = {};
//build your data here
source.data = data;
  

Где source — источник данных столбца Bokeh для вашей таблицы данных.
Вам не нужно использовать:

 source.change.emit();
  

Вы делаете это только тогда, когда заменяете только часть своих данных, например, один столбец таблицы.
И если data_table это ваш объект Bokeh DataTable, то также пропустите выполнение:

 target_obj.change.emit();
  

Дата таблицы обновляется автоматически при обновлении ее ColumnDataSource.
Посмотрите на этот простой пример:

 from bokeh.io import show
from bokeh.layouts import widgetbox
from bokeh.models import ColumnDataSource, Slider, DataTable, TableColumn, CustomJS

source = ColumnDataSource(dict(x = list(range(6)), y = [x ** 2 for x in range(6)]))
columns = [TableColumn(field = "x", title = "x"), TableColumn(field = "y", title = "x**2")]
table = DataTable(source = source, columns = columns, width = 320)
slider = Slider(start = 1, end = 20, value = 6, step = 1, title = "i", width = 300)
callback_code = """ i = slider.value;
                    new_data = {"x": [1, 2, 3, 4, 5], "y": [1, 4, 9, 16, 25]}
                    table.source.data = new_data
                    table.width = 320   i * 25;  """
callback = CustomJS(args = dict(slider = slider, table = table), code = callback_code)
slider.js_on_change('value', callback)
show(widgetbox(slider, table))
  

Комментарии:

1. Замечательно. Большое спасибо.