Bokeh models to plot interactive addition of columns using CustomJS and CheckboxGroup

I want a CheckboxGroup to represent different columns of a dataframe. The idea is for the user to be able to add multiple column values if they select multiple columns and interactively display the sum as a plot.

I have the following:

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import CheckboxGroup, CheckboxButtonGroup, TextInput
import pandas as pd

output_file('additive_checkbox.html')
names = ['Number', 'A', 'B', 'C']
rows = [(340, 77, 70, 15),
        (341, 80, 73, 15),
        (342, 83, 76, 16),
        (343, 86, 78, 17)]
data = pd.DataFrame(rows, columns=names)
data['combined'] = None
source = ColumnDataSource(data)
callback = CustomJS(args=dict(source=source), code="""
    const labels = cb_obj.labels;
    const active = cb_obj.active;
    const data = source.data;
    const sourceLen = data.combined.length;
    const combined=Array(sourceLen).fill(undefined);
    var combined_label = ''

if (active.length > 0) {
    const selectedColumns = labels.filter((val, ind) => active.includes(ind));
    for(let i = 0; i < sourceLen; i++) {
        let sum = 0;
        for(col of selectedColumns){
            sum += data[col][i];
        }
        combined[i] = sum;
    }
}
data.combined=combined;
source.change.emit();
""")
checkbox_group = CheckboxButtonGroup(labels=names[1:], active=[], js_event_callbacks=callback, width=400)

final_col = column(p, checkbox_group)
show(final_col)

And it is giving me the following error: ValueError: failed to validate CheckboxButtonGroup(id='1223', ...).js_event_callbacks: expected an element of Dict(String, List(Instance(CustomJS))), got CustomJS(id='1222', ...)

I am not good with JS and have no idea what it means!

Well, first things first. The error has nothing to do with JavaScript, per se. You are tying to use js_event_callbacks, which is not intended for end-users to ever set directly. [1] Instead, you should use js_on_event or js_on_change which are demonstrated in many examples and have an entire chapter in the user’s guide:

Once you have changed to use standard APIs we can look into any further issues.


  1. It had to be made “public” for uninteresting technical reasons related to serialization, but it was explicitly and purposefully never demonstrated in any examples or docs, and otherwise hidden from view to discourage anyone from trying to use it. Hopefully in the future it can be completely hidden. ↩︎

Thanks a lot for the help. The error message wasn’t really helpful and neither was the direct reference asking me to change callback to js_event_callbacks. I have spent so much time trying to figure out why my code that worked perfectly before suddenly isn’t working any longer. I changed to the following:

checkbox_group = CheckboxButtonGroup(labels=col_names[1:], active=[])
checkbox_group.js_on_change("active",callback) #not sure if the argument is labels since that is what changes, but both didn't work
# also tried 
# checkbox_group.js_on_click(callback)

p.line(x='Wavelength', y='combined', source=source, line_width =1)
show(column(p,checkbox_group))

Now, it doesn’t plot any combined data at all :frowning: only shows me the gridplot with the CheckboxGroup Buttons

I would not expect it to, given this line in your code:

data['combined'] = None

That has never been valid Bokeh usage. I’m not sure what you are trying to accomplish, but it always been the case that:

  • every value in a CDS .data dict should be a list/array/series (i.e. a “column”), and
  • all columns in a CDS must always be the same length

In the JS code, it fills that column with sum of two or more selected columns using the CheckBoxGroup. I have actually used this standalone html tool for over a year and then we got new data and I came to update it and it broke.

That actually creates a column with None of length equal to other columns in the dataframe just like data[‘combined’] = 0 would, and I have tried that too. The JS event calls are broken, everything else should be okay.

My gridplot also consists of the non-interactive baseline plots and that is from a CDS with a series of different column sizes, and that part is working fine.

@brainonlunchbreak It seems like you have made some changes and tried some different things. At this point I’d ask you provide a new updated complete MRE that I can actually run to investigate directly.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.