Search code examples
javascriptpythonbokeh

How to add a hierarchical checkbox


I try to modify the code below, to have a "curves" checkbox that would deactivate / activate all the children (actually, the code I need will handle a lot of those, this is just an example):

The current code gives:

enter image description here

And I need to achieve this:

enter image description here

import numpy as np
from bokeh.layouts import column, row
from bokeh.models import CustomJS, Slider, CheckboxGroup
from bokeh.plotting import ColumnDataSource, figure, show

# output_notebook()

# initial input data
x = np.linspace(0, 10, 500)
y = np.sin(x)
z = np.cos(x)
name_lst = ['sin', 'cos']

# dataframe
source = ColumnDataSource(data=dict(x=x, y=y, z=z))

# initialize figure
fig = figure(width=200, height=200)
line_renderer = [
    fig.line('x', 'y', source=source, name=name_lst[0]),
    fig.line('x', 'z', source=source, name=name_lst[1])
]
line_renderer[0].visible = False
#  a couple of check boxes

checkbox = CheckboxGroup(
    labels=name_lst, 
    active=[1, 1], 
    width=100
)

callback = CustomJS(args=dict(lines=line_renderer, checkbox=checkbox),
                    code="""
    lines[0].visible = checkbox.active.includes(0);
    lines[1].visible = checkbox.active.includes(1);
""")

# changes upon clicking and sliding
checkbox.js_on_change('active', callback)

layout = row(fig, column( checkbox))
show(layout)

Solution

  • First, add 'curves' to the name_lst.

    name_lst = ['curves', 'sin', 'cos']
    

    Second, we modify the line_renderer, checkbox.

    # now, it's 1: sin, 2: cos
    line_renderer = [
        fig.line('x', 'y', source=source, name=name_lst[1]),
        fig.line('x', 'z', source=source, name=name_lst[2])
    ]
    line_renderer[0].visible = False
    #  a couple of check boxes
    
    checkbox = CheckboxGroup(
        labels=name_lst, 
        active=[2, 2, 2], # the cos checkbox is now in the index 2
        width=100
    )
    

    Now, we're going to show the curve when curves or the specific checkbox is checked.
    To do this, we modify the JS code. || means or in JS.

    # 0: curves, 1: sin, 2: cos
    callback = CustomJS(args=dict(lines=line_renderer, checkbox=checkbox),
                        code="""
        lines[0].visible = checkbox.active.includes(0) || checkbox.active.includes(1);
        lines[1].visible = checkbox.active.includes(0) || checkbox.active.includes(2);
    """)