Python Bokeh - filter scatterplot using CheckboxGroup and JS callback

Viewed 122

I have been struggling with trying to understand how to use widgets to filter Bokeh scatterplots. I'm new to both Bokeh and JavaScript so it has been a steep learning curve. I have tried a lot of code I've found online but have not found anything that works or does what I specifically need to do. I would greatly appreciate some help with my code - I'm sure the CustomJS is not doing what I need it to do.

I have adapted the code below from the Bokeh gallery to illustrate what I'd like to do. It is plotting up the iris dataset. I would like users to be able to select a species from the checkbox and the graph to update and only plot that subset of the data.

Thank you!

from bokeh.plotting import figure, output_notebook, show
from bokeh.sampledata.iris import flowers
from bokeh.models import BooleanFilter, CDSView, ColumnDataSource
from bokeh.models.widgets import CheckboxGroup
from bokeh.models.callbacks import CustomJS

output_notebook()

alldata = ColumnDataSource(flowers)
subdata = ColumnDataSource(flowers)

checkbox = CheckboxGroup(labels = flowers['species'].unique().tolist())
p = figure()
p.circle('petal_length', 'petal_width', source = subdata)

show(p)
show(checkbox)

callback = CustomJS(args=dict(subdata=subdata, alldata=alldata),
                         code="""
                             const spec = cb_obj.value;
                             subdata = alldata[spec];
                             subdata.data.change.emit();
                          """)

checkbox.js_on_change('value', callback)

I've tried another approach using CDS views / filtering but with no success.

from bokeh.plotting import figure, output_notebook, show
from bokeh.sampledata.iris import flowers
from bokeh.models import BooleanFilter, CDSView, ColumnDataSource, IndexFilter, GroupFilter
from bokeh.models.widgets import CheckboxGroup
from bokeh.models.callbacks import CustomJS

output_notebook()

alldata = ColumnDataSource(flowers)

checkbox = CheckboxGroup(labels = flowers['species'].unique().tolist())
show(checkbox)


filter = IndexFilter(indices=list(range(0,len(flowers['species']))))

checkbox.js_on_change('value', callback)

callback = CustomJS(args=dict(src=alldata, filter=filter), code='''
  const indices = []
  for (var i = 0; i < src.get_length(); i++) {
    console.log(i, src.data['species'][i], cb_obj.value)
    if (src.data['species'][i] == cb_obj.value) {
      indices.push(i)
    }
  }
  filter.indices = indices
  src.change.emit()
''')

view = CDSView(source=alldata, filters=[filter])

p = figure()
p.circle('petal_length', 'petal_width', source = alldata, view = view)

show(p)
0 Answers
Related