I’m trying to figure out how to filter data by both a checkbox group and a multiselect, and I can’t get the multiselect to work and don’t understand why. I think it’s because of how the multiselect handles the data, perhaps it somehow doesn’t give a list of active fields like the checkbox group does. I’ve poured over the documentation and it all looks fine and am seriously starting to question my sanity.
Here’s the simplified code with the JS code which I expected to work but didn’t commented out:
from bokeh.plotting import figure, show
from bokeh.models import Slider, CustomJSFilter, CDSView, ColumnDataSource, CustomJS
from bokeh.models.widgets import CheckboxGroup, MultiSelect
from bokeh.layouts import layout
from bokeh.transform import factor_cmap
data = dict(Apples=[97, 34, 23, 6, 26, 97, 21, 92, 73, 10, 92, 14, 77, 4, 25, 48, 26, 39, 93],
Bananas=[87, 63, 56, 38, 57, 63, 73, 56, 30, 23, 66, 47, 76, 15, 80, 78, 69, 87, 28],
Oranges=[21, 65, 86, 39, 32, 62, 46, 51, 17, 79, 64, 43, 54, 50, 47, 63, 54, 84, 79],
Category = ['A', 'B', 'B', 'C', 'A', 'C', 'B', 'C', 'C', 'B', 'A', 'A', 'B', 'B', 'A', 'C', 'C', 'C', 'C'],
Multi_Category = ['X', 'X', 'Y', 'Z', 'Z', 'X', 'Z', 'Y', 'X', 'Y', 'Y', 'Y', 'Y', 'X', 'Z', 'X', 'Y', 'Y', 'Y'])
colordict = dict(Colors = ['red', 'green', 'blue'],
Categories = ['A', 'B', 'C'],
Multi_Categories = ['X', 'Y', 'Z'])
source = ColumnDataSource(data=data)
checkbox_group = CheckboxGroup(labels= colordict['Categories'], active = [1])
checkbox_group.js_on_change("active", CustomJS(code="source.change.emit();", args=dict(source=source)))
multiselect = MultiSelect(value = colordict['Multi_Categories'], options = colordict['Multi_Categories'])
custom_filter = CustomJSFilter(args=dict(source=source, checkbox_group = checkbox_group, multiselect = multiselect), code=
'''var indices = [];
selected = checkbox_group.active.map(i=>checkbox_group.labels[i]);
column = source.data['Category'];
// multselected = multiselect.active.map(i=>multiselect.labels[i]);
// mult_column = source.data['Multi_Category'];
for (var i = 0; i < source.get_length(); i++){
if ( selected.includes(column[i])
// &&
// multiselected.includes(mult_column[i))
){ indices.push(true);
} else {indices.push(false);}}return indices;''')
view = CDSView(source=source, filters=[custom_filter])
p = figure()
p.circle('Oranges', 'Bananas', source=source, view=view, size=20, fill_color = factor_cmap('Category', palette = colordict['Colors'], factors = colordict['Categories']))
controls = [checkbox_group, multiselect]
l = layout([[controls, p]], sizing_mode="stretch_both")
show(l)
Could someone please help me understand how I can get this multiselect to work?
Again, sorry for all these stupid questions…
edit: fixed formatting for code