☰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

CustomJS modifying BooleanFilter

Community Support
nlosacco
nlosacco

Hi all,

I have a multiline plot (say columns ‘x’ and ‘y’) and I’d like to filter values based on other columns of the ColumnDataSource (say ‘units’ and ‘depth’). I can achieve this statically with:

zmin = 20.
zmax = 40.
bools2a = [True if u == '2a' else False for u in source.data['units']]
boolsZ = [True if z > zmin and z < zmax else False for z in source.data['depths']]
bfZ = BooleanFilter(boolsZ)
view2a = CDSView(source = source, filters=[BooleanFilter(bools2a),bfZ])

now, I’d like to use a RangeSlider to act on zmin and zmax to interactively filter the plotted data:

range_slider = RangeSlider(
    title="depth range",
    start=0,
    end=70,
    step=1,
    value=(zmin, zmax),
)

but even after studying the docs for one entire day I’m not able to achieve this with CustomJS, can anyone provide an example?

⌁   Link to post
gmerritt123
gmerritt123

What version of bokeh are you using? CDSView (as of 3.x I believe) no longer takes “filters” but rather a single filter (and you use IntersectionFilter/UnionFilter etc. to blend them)…

Anyway, here’s a snippet. Not using BooleanFilter because I don’t think that’s actually what you need → You want to collect the indices from src meeting a certain condition (i.e. is depth_range within the bounds of the range slider?) and then use those indices to update an IndexFilter.

from bokeh.plotting import figure, show
from bokeh.models import CustomJS, RangeSlider, CustomJS, IndexFilter, CDSView, ColumnDataSource
from bokeh.layouts import column

src = ColumnDataSource(data={'x':[[1,2,3],[1,2,3],[1,2,3]]
                             ,'y':[[3,1,2],[2,2,1],[2,3,4]]
                             ,'depth_range':[5,4,3]
                             ,'c':['blue','red','green']
                             })

sl = RangeSlider(start=0,end=6, step=1,value=(0,6),title='depth_range')

f = figure()

#initalize filter containing ALL indices --> because starting the slider at either end of its start/end
filt = IndexFilter(indices=list(range(len(src.data['depth_range']))))
view = CDSView(filter=filt)
r = f.multi_line(xs='x',ys='y',line_color='c',source=src,view=view)

#the callback
cb = CustomJS(args=dict(src=src, sl=sl, filt=filt)
              ,code='''
              var inds = []
              //for every item in the src, if its depth range value lies within the slider bounds, append it to the inds list
              for (var i = 0; i<src.data['depth_range'].length; i++){
                      if (src.data['depth_range'][i] >= sl.value[0] && src.data['depth_range'][i] <= sl.value[1]){
                              inds.push(i)}
                      }
              //update the filter with the new indices and emit the change to the src
              filt.indices = inds
              src.change.emit()
              ''')
#want this code to trigger when value of slider changes             
sl.js_on_change('value',cb)

show(column([f,sl]))
⌁   Link to post
nlosacco
nlosacco

Thanks for your thorough reply. I didn’t manage to try it yet, I’ll do it now. Just one thing:
shouldn’t it be:
filt.change.emit()
rather than
src.change.emit()
?

PS: yep I was using Bokeh 2.something by mistake, in fact the inconsistency with the documentation was sort of puzzling me. Now I’m using 3.1.0

⌁   Link to post
Bryan
Bryan

Lots of things trigger off of data source change updates. it is often the best way to ask for a full redraw. TBH none of this internal eventing should be user-visible at all, it would be much better to define a small stable API surface that could be used in JS callbacks, but no-one has has the chance to work on such yet.

⌁   Link to post

End of archived discussion · Replies are disabled