pythonbokeh

Bokeh: Widget to Show/Hide Figures


Looking to do something along the lines of a UI as here: Bokeh: Using Checkbox widget to hide and show plots wherein I can selectively show/hide the whole figure in a column of figures. A drop down menu (OptionMenu with multiple selections) where I could select which plots showed up (assuming I could name the figures) would be preferable.

I am not familiar with JS, any guidance? (Thanks in advance)

I'd hope that the image wouldn't be visible anymore and the next figure would jump up like so:

eg: enter image description here

I have multiple figures in a column generated as:

from bokeh.io import output_file, show
from bokeh.layouts import column
from bokeh.plotting import figure

output_file("layout.html")

x = list(range(11))
y0 = x
y1 = [10 - i for i in x]
y2 = [abs(i - 5) for i in x]

# create a new plot
s1 = figure(plot_width=250, plot_height=250, title=None)
s1.circle(x, y0, size=10, color="navy", alpha=0.5)

# create another one
s2 = figure(plot_width=250, plot_height=250, title=None)
s2.triangle(x, y1, size=10, color="firebrick", alpha=0.5)

# create and another
s3 = figure(plot_width=250, plot_height=250, title=None)
s3.square(x, y2, size=10, color="olive", alpha=0.5)

# put the results in a column and show
show(column(s1, s2, s3))

Solution

  • The original answer is outdated. Bokeh plot objects (e.g. from figure) have a visible property (and have had for some time) that can be toggled on or of either by CustomJS core or by Python code.


    OUTDATED

    Plots don't have a visible toggle, at least as of version 0.13. So you will have to reset the children value of the layout widget. I'm not quite sure what interaction you intend with a dropdown. Here is a complete example with a checkbox:

    from bokeh.io import output_file, show
    from bokeh.layouts import column, row
    from bokeh.plotting import figure
    from bokeh.models import CheckboxGroup, CustomJS
    
    output_file("layout.html")
    
    x = list(range(11))
    y0 = x
    y1 = [10 - i for i in x]
    y2 = [abs(i - 5) for i in x]
    
    s1 = figure(plot_width=250, plot_height=250, title=None)
    s1.circle(x, y0, size=10, color="navy", alpha=0.5)
    
    s2 = figure(plot_width=250, plot_height=250, title=None)
    s2.triangle(x, y1, size=10, color="firebrick", alpha=0.5)
    
    s3 = figure(plot_width=250, plot_height=250, title=None)
    s3.square(x, y2, size=10, color="olive", alpha=0.5)
    
    col = column(s1, s2, s3)
    
    checkbox = CheckboxGroup(labels=["Plot 1", "Plot 2", "Plot 3"],
                             active=[0, 1, 2], width=100)
    
    callback = CustomJS(args=dict(plots=[s1,s2, s3], col=col, checkbox=checkbox), code="""
    const children = []
    for (const i of checkbox.active) {
         children.push(plots[i])
    } 
    col.children = children
    """)
    checkbox.js_on_change('active', callback)
    
    show(row(checkbox, col))
    

    You could do something similar with a MultiSelect:

    select = MultiSelect(options=[("0", "Plot 1"), ("1", "Plot 2"), ("2", "Plot 3")],
                           value=["0", "1", "2"], width=100)
    
    callback = CustomJS(args=dict(plots=[s1,s2, s3], col=col, select=select), code="""
    const children = []
    for (const i of select.value) {
        children.push(plots[i])
    }
    col.children = children
    """)
    select.js_on_change('value', callback)
    

    Small FYI that that code is a little sloppy—it's relying on JS implicitly casting strings like "0" to numbers.