How to link individual buttons in a CheckboxButtonGroup to different callback functions

I am trying to work through several Bokeh examples that are not covered in the tutorials as a method of learning the package. Right now I am trying to encode a simple scatter plot with circle glyphs with three buttons within a CheckboxButtonGroup. I would like to link a callback function to each button, but so far I am only able to link one Callback function to the entire group, such that depressing any of the three buttons will execute the same function, instead of a different function for each button. How can I link a Callback function to each button? My sample code is attached.
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

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)

counter = [0]
counter = dict(counter=counter)
counter1 = ColumnDataSource(counter)
counter2 = ColumnDataSource(counter)
counter3 = ColumnDataSource(counter)

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, counter=counter1), 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();
""")

callback2 = CustomJS(args=dict(source=source, counter=counter2), code="""
    var f = 3.0

    var count = counter2.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();
""")

callback3 = CustomJS(args=dict(source=source, counter=counter3), code="""
    var f = 3.0

    var count = counter3.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] = Math.pow(x[i], f)
    }
    source.change.emit();
""")

LABELS = ["Add Subtract", "Multiply", "Power"]

checkbox_button_group = CheckboxButtonGroup(labels=LABELS, active=[0, 1, 2])

checkbox_button_group.js_on_click(callback1)
checkbox_button_group.js_on_click(callback2)

layout = column(checkbox_button_group, plot)
show(layout)

This is not possible. You will have to write one callback that looks at the new value for the CheckboxButtonGroup as a whole, and reacts differently depending on the value.

Bryan, that’s good information to have, thank you. However, how do I get each button to provide a specific response and how do I reference that response in the single callback function. Please forgive me, my JavaScript background is minimal.

You can look at the active property of the widget in the callback, which will tell you which of the checkboxes is checked:

callback = CustomJS(args=dict(group=checkbox_button_group), code="""
   console.log(group.active)
""")

Does your response imply that with the callback function provided I should see the specific response printed to my terminal or someplace on the html display when I click a button in the group? Like I mentioned, I am working on picking up javascript, but am barely a novice. It appears that the console.log command should print the active property to the terminal, but that is not the behavior I am seeing.

@webbja123 console.log prints the the browser’s JavaScript console which is normally part of a browsers “dev tools”. Every browser has a different way to access the JS console and related dev tools[1], so you will have to Google for the specifics regarding whatever browser you happen to be using.


  1. E.g. on OSX/Safari it’s command-option-C to open the JS console but that obviously won’t apply to windows or even necessarily other browsers on OS X ↩︎

I see, thank you!