☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Update content in second multiselect widget

Community Supportcustomjsbokehjs
Zana
Zana

Hi,

Added the code below with test source.
Is it possible to update the second multiselect widget to only show values that have data points for what the user selects on the first multiselect widget.
So in the below code if the user selects ‘a’ the second multiselect tool updates and only showes ‘a-2’, ‘a-5’.


from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CDSView, BooleanFilter, CustomJSTransform, MultiSelect, CustomJS
from bokeh.plotting import figure
from bokeh.transform import transform
import numpy as np

p = figure()
ds = ColumnDataSource(dict(x=list(range(10)), 
                           y=list(range(10)), 
                           names = ['a', 'b', 'c', 'c', 'd', 'd', 'a', 'a', 'c', 'c'], 
                           name_id = ['a-5', 'b-1', 'c-1', 'c-1', 'd-1', 'd-1', 'a-2', 'a-5', 'c-2', 'c-2']))

b = BooleanFilter([True if x == 'a' else False for x in ds.data['names']])
selectoroptions = [str(x) for x in sorted(np.unique(ds.data['names']))]
ms = MultiSelect(title= 'MC Experiment:', value = ['a'],
                                    options=selectoroptions)

b_id = BooleanFilter([True if x == 'a-5' else False for x in ds.data['name_id']])
selectoroptions = [str(x) for x in sorted(np.unique(ds.data['name_id']))]
ms_id = MultiSelect(title= 'ID:', value = ['a-5'],
                                    options=selectoroptions)

ms.js_on_change('value', CustomJS(args = dict(f=b, source=ds, columnName = 'names'),
                                      code="""\
                                      const val = cb_obj.value;
                                      f.booleans = Array.from(source.data[columnName]).map(d =>  val.includes(d != null && d.toString()));
                                      source.change.emit();                                      
                                      """))

ms_id.js_on_change('value', CustomJS(args = dict(f=b_id, source=ds, columnName = 'name_id'),
                                      code="""\
                                      const val = cb_obj.value;
                                      f.booleans = Array.from(source.data[columnName]).map(d =>  val.includes(d != null && d.toString()));
                                      source.change.emit();                                      
                                      """))


view = CDSView(source=ds, filters=[b, b_id])
tr = CustomJSTransform(v_func="return xs.map(x => 10 * x);")
p.scatter('x', transform('y', tr), view=view, source=ds, color='red')

show(column(p, ms, ms_id))
⌁   Link to post
p-himik
p-himik

Here’s how I would do it. The main change is in the first CustomJS.

from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CDSView, BooleanFilter, CustomJSTransform, MultiSelect, CustomJS
from bokeh.plotting import figure
from bokeh.transform import transform

p = figure()
ds = ColumnDataSource(dict(x=list(range(10)),
                           y=list(range(10)),
                           names=['a', 'b', 'c', 'c', 'd', 'd', 'a', 'a', 'c', 'c'],
                           name_id=['a-5', 'b-1', 'c-1', 'c-1', 'd-1', 'd-1', 'a-2', 'a-5', 'c-2', 'c-2']))

options = sorted(set(ds.data['names']))
initial_value = [options[0]]
b = BooleanFilter([x in initial_value for x in ds.data['names']])
ms = MultiSelect(title='MC Experiment:', value=initial_value, options=options)

id_options = sorted(set(i for n, i in zip(ds.data['names'], ds.data['name_id'])
                        if n in initial_value))
initial_id_value = [id_options[0]]
b_id = BooleanFilter([x in initial_id_value for x in ds.data['name_id']])
ms_id = MultiSelect(title='ID:', value=initial_id_value, options=id_options)

ms.js_on_change('value', CustomJS(args=dict(f=b, source=ds, columnName='names', ms_id=ms_id),
                                  code="""\
                                      const val = cb_obj.value;
                                      f.booleans = Array.from(source.data[columnName]).map(d =>  val.includes(d != null && d.toString()));
                                      const id_options = [...new Set(source.data.name_id.filter((_, idx) => f.booleans[idx]))];
                                      id_options.sort();
                                      
                                      // New lines.
                                      ms_id.options = id_options;
                                      ms_id.value = [id_options[0]];
                                      
                                      source.change.emit();                                      
                                      """))

ms_id.js_on_change('value', CustomJS(args=dict(f=b_id, source=ds, columnName='name_id'),
                                     code="""\
                                      const val = cb_obj.value;
                                      f.booleans = Array.from(source.data[columnName]).map(d =>  val.includes(d != null && d.toString()));
                                      source.change.emit();                                      
                                      """))

view = CDSView(source=ds, filters=[b, b_id])
tr = CustomJSTransform(v_func="return xs.map(x => 10 * x);")
p.scatter('x', transform('y', tr), view=view, source=ds, color='red')

show(column(p, ms, ms_id))
⌁   Link to post
Zana
Zana

Thanks! That worked perfectly!
Do you know if its possible to have the tool select all available ids?
In the plot above it finds a-2 and a-5 and plots a-2. Is it possible for it to plot all the ids for the specified letter. If not I can just do CTRL-A in the multiselect, just wondering if its possible:D

⌁   Link to post
Zana
Zana

Awesome. Thanks!

Last question btw! :stuck_out_tongue:
I tried adding a third multiselect. But now its not plotting anything. Even if I select everything. You have an idea why?

from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, CDSView, BooleanFilter, CustomJSTransform, MultiSelect, CustomJS
from bokeh.plotting import figure
from bokeh.transform import transform

p = figure()
ds = ColumnDataSource(dict(x=list(range(10)),
                           y=list(range(10)),
                           tc=list(range(10)),
                           temp_int=['(20, 30]', '(40, 50]', '(20, 30]', '(20, 30]', '(40, 50]', '(20, 30]', '(20, 30]', '(20, 30]', '(20, 30]', '(40, 50]'],
                           matrix_names=['ras', 'das', 'ras', 'das', 'das', 'bas', 'ras', 'ras', 'ras', 'bas'],
                           names=['a', 'b', 'c', 'c', 'd', 'd', 'a', 'a', 'c', 'c'],
                           name_id=['a-5', 'b-1', 'c-1', 'c-1', 'd-1', 'd-1', 'a-2', 'a-5', 'c-2', 'c-2']))

options = sorted(set(ds.data['names']))
initial_value = [options[0]]
b = BooleanFilter([x in initial_value for x in ds.data['names']])
ms = MultiSelect(title='MC Experiment:', value=initial_value, options=options)

id_options = sorted(set(i for n, i in zip(ds.data['names'], ds.data['name_id'])
                        if n in initial_value))
initial_id_value = id_options#[id_options[0]]
b_id = BooleanFilter([x in initial_id_value for x in ds.data['name_id']])
ms_id = MultiSelect(title='ID:', value=initial_id_value, options=id_options)

mn_options = sorted(set(ds.data['matrix_names']))
mn_initial_value = [mn_options[0]]
b_mn = BooleanFilter([x in initial_value for x in ds.data['matrix_names']])
ms_mn = MultiSelect(title='Matrix Names:', value=mn_initial_value, options = mn_options)

ms.js_on_change('value', CustomJS(args=dict(f=b, source=ds, columnName='names', ms_id=ms_id, ms_mn = ms_mn),
                                  code="""\
                                      const val = cb_obj.value;
                                      f.booleans = Array.from(source.data[columnName]).map(d =>  val.includes(d != null && d.toString()));
                                      
                                      // New lines.

                                      const id_options = [...new Set(source.data.name_id.filter((_, idx) => f.booleans[idx]))];
                                      id_options.sort();
                                      
                                      ms_id.options = id_options;
                                      ms_id.value = id_options;

                                      const mn_options = [...new Set(source.data.matrix_names.filter((_, idx) => f.booleans[idx]))];
                                      mn_options.sort();
                                      
                                      ms_mn.options = mn_options;
                                      ms_mn.value = mn_options;

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

ms_id.js_on_change('value', CustomJS(args=dict(f=b_id, source=ds, columnName='name_id'),
                                     code="""\
                                      const val = cb_obj.value;
                                      f.booleans = Array.from(source.data[columnName]).map(d =>  val.includes(d != null && d.toString()));
                                      source.change.emit();                                      
                                      """))

view = CDSView(source=ds, filters=[b, b_id, b_mn])
tr = CustomJSTransform(v_func="return xs.map(x => 10 * x);")
p.scatter('x', transform('y', tr), view=view, source=ds, color='red')

show(column(p, ms, ms_id, ms_mn))
⌁   Link to post

End of archived discussion · Replies are disabled