Gerardo Luis Alcala
Gerardo Luis Alcala

Reputation: 1

Bokeh: Update a scatterplot from a checkboxgroup using CustomJS to filter source

I'm not very familiar with Java Script and need help from this great community!.

I'm trying to create a scatterplot with a Checkboxgroup attached to select different groups to plot. Dummy data is the following:

from bokeh.models import CustomJS, ColumnDataSource, CheckboxGroup, Column
from bokeh.plotting import figure, show
import pandas as pd

data = dict(letter = ['A','A','B','C','B','B','A','C','C','B'], 
x = [1, 2, 1, 2, 3, 2, 2, 3, 2, 3], 
y = ['10','20','10','30','10','40','10','30','10','40'])
data = pd.DataFrame(data)

source = ColumnDataSource(data)

plot = figure()
plot.circle('x', 'y', line_width = 2, source = source)
show(plot)

I would like to add a Checkboxgroup with letter as possible selections, and to plot the values of the selected letters only. It would be great if this could be done with Java Script to embbed in an HTML document.

Thanks in advance.

Upvotes: 0

Views: 634

Answers (1)

Eugene Pakhomov
Eugene Pakhomov

Reputation: 10652

import pandas as pd
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CDSView, CheckboxGroup, CustomJS, BooleanFilter
from bokeh.plotting import figure, show

data = dict(letter=['A', 'A', 'B', 'C', 'B', 'B', 'A', 'C', 'C', 'B'],
            x=[1, 2, 1, 2, 3, 2, 2, 3, 2, 3],
            y=['10', '20', '10', '30', '10', '40', '10', '30', '10', '40'])
data = pd.DataFrame(data)

source = ColumnDataSource(data)

plot = figure()
active_letter = 'A'
f = BooleanFilter(booleans=[l == active_letter for l in data['letter']])
uniq_letters = sorted(set(data['letter']))
cg = CheckboxGroup(labels=uniq_letters, active=[uniq_letters.index(active_letter)])
cg.js_on_change('active',
                CustomJS(args=dict(source=source, f=f),
                         code="""\
                             const letters = cb_obj.active.map(idx => cb_obj.labels[idx]);
                             f.booleans = source.data.letter.map(l => letters.includes(l));
                             source.change.emit();
                         """))

plot.circle('x', 'y', line_width=2, source=source,
            view=CDSView(source=source, filters=[f]))

show(row(cg, plot))

Upvotes: 2

Related Questions