0

Apologies but I can't make any reproducible code for this question since it's pretty inconsistent.

So I have a bokeh data table, and I'm doing some filtering with it using 4 dropdown boxes. The data table updates based on dropdown box value, and the updates were written in JS. The filtering works as expected, but strangely enough for some very specific combinations of dropdown values it does not display anything in the data table. I was wondering if it was a problem with my data, but I coerced everything to strings and it still gave me the same problem.

The updates are written here:

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) &&
            (classification === "ALL" || original_data['Classification'][i] === classification) &&
            (currency === "ALL" || original_data['Currency'][i] === currency) &&
            (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)
Qonl
  • 79
  • 1
  • 10

1 Answers1

1

The right way do update table data in your JS callback is this way:

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

Where source is the Bokeh ColumnDataSource of you DataTable. You don't need to use:

source.change.emit();

You do it only when you replace only a part of you data e.g. one table column. And if data_table is your Bokeh DataTable object then also skip doing:

target_obj.change.emit();

The table date updates automatically when you update its ColumnDataSource. See this simple example:

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))
Tony
  • 7,767
  • 2
  • 22
  • 51