You can control the visibility property of all figure renderers with CustomJS. Just pass the figure instance as an arg, and loop through its renderers property, turning visibility of each on/off.
Here’s a rough example building on yours, using a button to accomplish this. Other widgets may obviously be more appropriate for your use case:
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, Button
from bokeh.layouts import row
import numpy as np
from bokeh.models import Button
x = np.linspace(0, 2*np.pi, 101)
fig = figure()
fig.line(x, np.cos(x), color="red", legend_label="cos(x)")
fig.line(x, np.sin(x), color="green", legend_label="sin(x)")
fig.line(x, np.cos(x) + 1, color="blue", legend_label="cos(x) + 1")
fig.legend.location = "right"
fig.legend.click_policy = "hide"
btn = Button(label='Hide All')
cb = CustomJS(args=dict(fig=fig,btn=btn)
,code='''
if (btn.label=='Hide All'){
for (var i=0; i<fig.renderers.length; i++){
fig.renderers[i].visible=false}
btn.label = 'Show All'
}
else {for (var i=0; i<fig.renderers.length; i++){
fig.renderers[i].visible=true}
btn.label = 'Hide All'}
''')
btn.js_on_click(cb)
show(row([fig,btn]))
Now a good follow up I don’t have the answer to:
I could add an extra LegendItem to the existing legend, say an extra item with the label “Show/Hide All” . However, it does not appear that the ability to trigger CustomJS on clicking a particular LegendItem is exposed, meaning I don’t think you can do this. This gets me thinking further → I think what happens when you say legend.click_policy = ‘hide’ is a CustomJS gets auto-generated and attributed to each LegendItem, but that CustomJS is not available/exposed to the user. Or is it and I just can’t find it? I would enjoy an explanation/correction of my understanding of these mechanics too 