Using js_link to hide multiple plots from single legend

hi all,

this post seemed to provide a nice solution to what I was trying to do:

according to the author, this:

def link_legend_glyphs(ref_fig, target_figs):
    cb = CustomJS(
        args = {'target_figs': target_figs},
        code = '''
            const glyph_name = cb_obj.name;
            for (const element of target_figs) {
              const r = element.select(name = glyph_name)[0];
              //r.muted = cb_obj.muted;
              r.visible = cb_obj.visible;
            }
        ''')
    for i in ref_fig.legend[0].items:
        r = i.renderers[0]
        #r.js_on_change('muted', cb)
        r.js_on_change('visible', cb)
        

c = plotter(df, colors)
k = -0.75

c_sqrt = plotter(np.sqrt(df), colors, add_legend = True)
c_pow = plotter(np.power(df, k), colors)
link_legend_glyphs(c_sqrt, [c, c_pow])

save(row(c, c_sqrt, c_pow))

should have the same effect as:

def link_glyphs(ref_fig, target_fig):
    for i in colors:
        r = ref_fig.select(name = i)[0]
        t = target_fig.select(name = i)[0]
        r.js_link('muted', t, 'muted')
        

c = plotter(df, colors)
k = -0.75

c_sqrt = plotter(np.sqrt(df), colors, add_legend = True)
c_pow = plotter(np.power(df, k), colors)
link_glyphs(c_sqrt,c)
link_glyphs(c_sqrt,c_pow)

save(row(c, c_sqrt, c_pow))

but the latter doesn’t provide the desired result, i.e.: clicking on a legend item I can only hide the curves in a single graph. What am I missing?

@nlosacco No sure why it does not work for you, which version of Bokeh are you using? My example below works in 3.4.0.

from bokeh.io import output_file, save
from bokeh.plotting import figure, row, column
import pandas as pd
import numpy as np
from bokeh.models import Legend

output_file('shared_legend_hide.html')

x = list(range(11))
df = pd.DataFrame(data = {
    'x' : x,
    'y0' : x,
    'y1' : [10 - i for i in x],
    'y2' : [abs(i - 5) for i in x]})

colors = ['red', 'blue', 'yellow']

def plotter(df, colors, add_legend = False):
    legend_it = []
    c = figure(width=400, height=300, title=None)
    for idx, i in enumerate(['y0', 'y1', 'y2']):
        s = c.scatter(
            x = 'x', y = i, 
            marker = 'circle',
            source = df, size=10,
            color = colors[idx], alpha=0.7,
            name = colors[idx]
            )
        
        if add_legend:
            legend_it.append((i, [s]))
            
    if add_legend:
        legend = Legend(items=legend_it)
        legend.click_policy="mute"
        legend.orientation = 'horizontal'
        c.add_layout(legend, 'below')

    return c

def link_glyphs(ref_fig, target_fig):
    for i in colors:
        r = ref_fig.select(name = i)[0]
        t = target_fig.select(name = i)[0]
        r.js_link('muted', t, 'muted')

c = plotter(df, colors)
k = -0.75
c_sqrt = plotter(np.sqrt(df), colors, add_legend = True)
c_pow = plotter(np.power(df, k), colors)

link_glyphs(c_sqrt, c)
link_glyphs(c_sqrt, c_pow)

save(row(c, c_sqrt, c_pow))