I have a simple example problem where I have created a pd.DataFrame
containing numbers in the x
and y
columns and a text string in the z
column. The data is passed to a ColumnDataSource
so the x
and y
columns can be plotted as circle glyphs on a scatter plot. In addition I have included two buttons within a ChecboxButtonGroup
that will be used to filter the dataframe based on the values of the z
column. One button will filter out rows where z
is equal to Apple
and the other will do the same for Orange
. When unchecked, the buttons should unfiltered the data based on the values in z
. Attached is my attempt at this problem, but it is clearly not correct. What is the best way to to attack this example problem.
from bokeh.models import ColumnDataSource, CustomJS, Button
from bokeh.models import CheckboxButtonGroup
from bokeh.plotting import Figure, output_file, show
from bokeh.layouts import column
import pandas as pd
output_file("js_on_change.html")
x = [1.2, 2.4, 0.8, 5.6, 12.1, 8.8]
y = [3.4, 1.1, 4.2, 6.6, 1.8, 12.1]
z = ['Apple', 'Apple', 'Orange', 'Orange', 'Orange', 'Orange']
data = dict(x=x, y=y, z=z)
source = ColumnDataSource(data)
stats_df = pd.DataFrame({'bar_one_stat': [False],
'bar_two_stat': [False],
})
stats = ColumnDataSource(stats_df)
plot = Figure(plot_width=400, plot_height=400)
plot.circle('x', 'y', source=source, size=8, line_alpha=0.6)
callback1 = CustomJS(args=dict(source=source), code="""
var f = 3.0
var count = counter.data;
var c = count['counter']
if (c[0]%2==1) f = -1*f;
c[0]++
counter.change.emit();
var data = source.data;
var x = data['x']
var y = data['y']
for (var i = 0; i < x.length; i++) {
y[i] = y[i] + f
}
source.change.emit();
""")
LABELS = ["Apple", "Orange"]
checkbox_button_group = CheckboxButtonGroup(labels=LABELS, active=[])
callback3 = CustomJS(args=dict(group=checkbox_button_group,
source=source, stats=stats),
code="""
// Create variables for start status of buttons
var status = stats.data
var bar_one = status['bar_one_stat'];
var bar_two = status['bar_two_stat'];
// Create variables for data
var data = source.data;
var x = data['x'];
var y = data['y'];
// Filter dataframe to re-plot data
if (group.active.includes(0) & bar_one[0] == false) {
var iter = 0
for (var i = 0; i < x.length; i++) {
if (z[i] == 'Apple') {
x[iter] = x[i]
y[iter] = y[i]
z[iter] = z[i]
}
}
bar_one[0] = true;
}
source.change.emit();
stats.change.emit();
""")
checkbox_button_group.js_on_click(callback3)
layout = column(checkbox_button_group, plot)
show(layout)