Let say I have 2 different lines:
df[0]=fig.line(x = 'x', y = 'y',..., name = 'toto0',source=s0)
df[1]=fig.line(x = 'x', y = 'y',..., name = 'toto1',source=s1)
If I want to have to possibility to hide them, I use this piece of code:
checkbox = CheckboxGroup(labels=['toto0','toto1'], active=2, width=100)
callback = CustomJS(args=dict(l0=df[0],l1=df[1],checkbox=checkbox),
code="""
l0.visible = 0 in checkbox.active;
l1.visible = 1 in checkbox.active;
""")
checkbox.js_on_change('active', callback)
layout = row(fig,checkbox)
show(layout)
Now let's say I have 20 different lines. How to proceed to compact the code below ?
callback = CustomJS(args=dict(l0=df[0],...,l19=df[19],checkbox=checkbox),
code="""
l0.visible = 0 in checkbox.active;
l1.visible = 1 in checkbox.active;
...
l19.visible = 19 in checkbox.active;
""")
This is a Python and a JavaScript question ... thanks !
The main idea is to collect all line renderes in a list and pass this list to the CustomJS. There you can loop over this list again and apply your changes.
Minimal Example
import pandas as pd
from bokeh.plotting import figure, show, output_notebook
from bokeh.models import CheckboxGroup, CustomJS
from bokeh.layouts import row
output_notebook()
df = pd.DataFrame(
{'x':range(5),
'red':range(5),
'blue':list(range(5))[::-1],
'green':[2]*5}
)
fig = figure(width=300, height=300)
line_renderer = []
names = list(df.columns[1:])
for name in names:
line_renderer.append(
fig.line(
x = 'x',
y = name,
color=name,
name =name,
source=df
)
)
checkbox = CheckboxGroup(labels=names, active=list(range(len(names))), width=100)
callback = CustomJS(args=dict(lines=line_renderer,checkbox=checkbox),
code="""
for(var i=0; i<lines.length; i++){
lines[i].visible = checkbox.active.includes(i);
}
"""
)
checkbox.js_on_change('active', callback)
layout = row(fig,checkbox)
show(layout)
Output