Defining a JavaScript callback from a button to select all checkboxes?

I’m following up on the answer given here, to create checkboxes and use them to turn scatter plots off and on. Works like a charm! What I want to do now is to have two buttons, for selecting all and for clearing all, checkbox selections. I want to do this with JavaScript, for eventual embedding in a webpage. However, try as I might, I can’t get such a thing to work. I imagine this is relatively simple, but as a bokeh beginner there’s a lot I don’t know. Anyway, if anybody can point me in the direction of such a beast, I’d be thrilled. Thanks!

Can you share what you have already tried, that did not work?

Thank you for your reply. Well, the callback function for changing the display is

filter =  CustomJSFilter(code="""
let selected = checkboxes.active.map(i=>checkboxes.labels[i]);
let indices = [];
let column = source.data['FOR'];
for(let i=0; i<column.length; i++){
    if(selected.includes(column[i])){
        indices.push(i);
    }
}
return indices;
""", args=dict(checkboxes=checkboxes, source=source))

and it is called with

checkboxes.js_on_change("active", CustomJS(code="source.change.emit();", args=dict(source=source)))

I was hoping to define another filter function and have that called by the button callback:

all = Button(label='All')
def every():
    checkboxes.js_on_change("active", CustomJS(code="source.change.emit();", args=dict(source=source),filter_all))
all.js_on_click(every())

where filter_all is another filter function which simply returns all indices:

filter_all =  CustomJSFilter(code="""
let indices = [];
for(let i=0; i<column.length; i++){
        indices.push(i);
    }
return indices;
""", args=dict(checkboxes=checkboxes, source=source))

This doesn’t work. I have lots of confusion about the relative behaviour of JavaScript and Python, as well as some more particular questions:

  1. How can I set the particular callback function to be used in a callback? The function filter is not given in the checkboxes callback: I imagine if there is only one function it is automatically taken to be the function needed.
  2. What I’ve attempted to do is clumsy: use the button to call another function which sets the state of all the checkboxes. As well as not working (how do the checkboxes get information from this set of indices?), it’s a mixture of Python and JavaScript. And I want callbacks to be JavaScript only.
  3. Probably a better way would be for the button to simply plot all the scatter plots generated from the pandas DataFrame that holds the data. But the problem with that is that I’m not fully sure how to include plotting commands within a JavaScript function.

Anyway, any pointers - or even better, examples - would be terrific! Thanks again.

Summary

This text will be hidden

Base on your initial description of the problem:

I want to do now is to have two buttons, for selecting all and for clearing all, checkbox selections.

The code above has things I would not expect to see. In particular I wouldn’t expect to see a CustomJSFilter since that really is only useful to apply to data columns in a ColumnDataSource. So I’ll start by giving a complete example that fits the description above, as I understand it, and we can see if that is what you are after or not:

from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import Button, CheckboxGroup, CustomJS

s = CheckboxGroup(labels=["foo", "bar", "baz"])

b1 = Button(label="clear all")
b1.js_on_click(CustomJS(args=dict(s=s), code="""
    s.active = []
"""))

b2 = Button(label="select all")
b2.js_on_click(CustomJS(args=dict(s=s), code="""
    s.active = [0,1,2]
"""))

show(column(s, b1, b2))

ScreenFlow

Thank you very much indeed! To make things easier, here’s what I’m trying to do: I have a list of about 67 educational disciplines, each one with a current market size and growth rate. These are being scaled to between 0 and 1 for mapping on a square. Each discipline comes with a broad field in which it sits. So for example, we might have:

FIELD:  NATURAL AND PHYSICAL SCIENCES
Discipline:  Physics
Abbreviation: Phs
Position: (0.5,0.7)
Colour:  #45AE0B

Within this same field we might also see chemistry, biology, etc. Then there are fields for health, business, education, and so on. All of this information is held in one pandas dataframe. The checkboxes are for these broad fields of education.

In order to emulate a current chart, each discipline is plotted as its abbreviation inside a colored rectangle: I’ve used plot.rect and plot.text for that (I found that plot.label didn’t give me the flexibility I needed), with a hover that shows the full name.

So far all this works fine, but as I say I haven’t found an easy way (with JavaScript) to mange the checkboxes.

This should be, I imagine, very simple, except that it’s causing me no end of confusion. Does all this make sense?

This means that with your examples above, all we need to do is to map those to the plot itself, I suppose.

You can hook up a callback handler on the checkbox group:

s.js_on_change('active', CustomJS(...))

This will trigger whenever the active property changes, and that includes when the buttons changes it.

You have not stated explicity, but I think you are trying to show/hide entire subsets of the plot based on the checkbox values? i.e. there is a checkbox "NATURAL AND PHYSICAL SCIENCES" and you want to show/hide all the things that fall under that category? If so I would do it this way:

  • Use a new glyph call for each category (i.e. partition your data into subsets and pass each subset to a new call to rect and text) You could do this in a loop.

  • Now you can show/hide everything for a given category by toggling the visible value on the corresponding rect and text glyph for that category

There is probably some way to accomplish this with a single call to rect for all the data and CustomJSFilter too, but I don’t have anything immediate to point to.

Thank you again! And indeed you are quite correct about my requirements: hiding and showing all items under a particular field.

I wasn’t quite sure to what glyphs the “visible” property applies (an example in the docs uses lines), but this will almost certainly be the way to go. When I have it all fixed up, and on a web page (which means working out the scaling to fit in an iframe), I’ll let you know!

It applies to all of them.

When I have it all fixed up, and on a web page (which means working out the scaling to fit in an iframe), I’ll let you know!

It would be great it if you could make a post about it in the Showcase Category!