CheckboxGroup in Bokeh to plot additive plots

2019-08-04 23:35发布

问题:

I want to use a checkbox group to represent linearly additive sources. The idea is for the user to be able to turn on or turn off multiple sources of different kinds to display a plot with added values.

I implemented a dropdown version where the data had the different combinations as columns of the dataframe so the CustomJS part of the code was as follows:

 callback = CustomJS(args={'source':source},code="""
        // print the selectd value of the select widget - 
        // this is printed in the browser console.
        // cb_obj is the callback object, in this case the select 
        // widget. cb_obj.value is the selected value.
        console.log(' changed selected option', cb_obj.value);

        // create a new variable for the data of the column data source
        // this is linked to the plot
        var data = source.data;

        // allocate the selected column to the field for the y values
        data['A1'] = data[cb_obj.value];

        // register the change - this is required to process the change in 
        // the y values
        source.change.emit();
""")

I don't know Javascript well enough. Is there a way to just give a dataframe as follows:

Wave    A    B   C
340    77   70  15
341    80   73  15
342    83   76  16
343    86   78  17

And have checkbox group buttons where if the user selects 'A' and 'C' the plot changes to a plot of Wave vs. A+C and vice versa for removing the selection.

I found a similar question, but it just shows/hides the plots and doesn't change the data: https://stackoverflow.com/a/38706613/8565759

I have way too many selections in the real data to manually assign combinations.

回答1:

Yes, you can achieve this with the CheckboxGroup - you can use the active attribute of CheckboxGroup to select the correct columns to add to the combined plot. Here is a complete example with the data you provided:

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
import pandas as pd

output_file('additive_checkbox.html')
names = ['Wave', '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);
    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 = CheckboxGroup(labels=names[1:], active=[], callback=callback)
p = figure(width=400, height=400)
p.line(x='Wave', y='combined', source=source)
show(layout([[widgetbox(checkbox_group)], [p]]))