2

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))
azazelspeaks
  • 5,727
  • 2
  • 22
  • 39

2 Answers2

2

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.

bigreddot
  • 33,642
  • 5
  • 69
  • 122
  • This works great with the checkboxes. For the dropdown I was thinking like an Option Menu where you select the plots in the list that you want. – azazelspeaks Sep 20 '18 at 04:18
  • 1
    Ah, you could do a similar thing with [`MultiSelect`](https://bokeh.pydata.org/en/latest/docs/user_guide/interaction/widgets.html#multiselect) – bigreddot Sep 20 '18 at 17:04
  • You wouldn't happen to know of a tutorial with CustomJS and multiselect would you? – azazelspeaks Sep 20 '18 at 19:08
  • I can disable specific checkboxes using the active part of the checkboxes, Is there some way to call this callback at the start when loading the image so that only say image 1 and 3 show up at the start? – azazelspeaks Sep 20 '18 at 21:21
  • played around with it and figured out how to do ^. I'll update the answer. – azazelspeaks Sep 20 '18 at 21:23
0
s1.tags, s2.tags, s3.tags = ['Foo'], ['Bar'], ['Arr'] # name your plots
plots = [s1, s2, s3]
labels = [(plots[i].tags[0]) for i in range(len(plots))]
active = list(range(0, len(plots)))

chkbx = CheckboxButtonGroup(labels=labels, active=active)

callback = CustomJS(args=dict(plots=plots, chkbx=chkbx), code="""
    for (let i = 0; i < plots.length; i++){
        plots[i].visible = chkbx.active.includes(i)
    }
    """)

chkbx.js_on_click(callback)

show(column([chkbx] + plots))

Thanks to @bigreddot and their answer for laying foundation for this solution.

Voy
  • 5,286
  • 1
  • 49
  • 59