☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Callback not responding to value

Community Supportcustomjsbokeh
Tranquil_Oshan
Tranquil_Oshan

I have a dataframe and a template of bar plots I would like as below:

df= pd.DataFrame({
    'A':[12,5,8],
    'B':[18,12,8],
    'C':[6,18,12],
    'D':[4,5,2],
    'Year':['2000', '2005', '2010']
})

source = ColumnDataSource(df)

p1=figure(x_range=['2000'],x_axis_label ='2000', y_axis_label = 'Bar Plot')
p1.vbar(x=dodge('Year', -0.3, range=p1.x_range), top='A', source=source,  width=0.19, color="#c9d9d3", legend_label="A")
p1.vbar(x=dodge('Year',  -0.1,  range=p1.x_range), top='B', source=source,  width=0.19, color="#718dbf", legend_label="B")
p1.vbar(x=dodge('Year',  0.1, range=p1.x_range), top='C', source=source,  width=0.19, color="#e84d60", legend_label="C")
p1.vbar(x=dodge('Year',  0.3, range=p1.x_range), top='D', source=source,  width=0.19, color="#555555", legend_label="D")      
p1.x_range.range_padding = 0.1
p1.xgrid.grid_line_color = None
p1.legend.orientation = "horizontal"

I would like the menu items plots change each time. But it doesnt seem to be working:

sel_src = ColumnDataSource(data={'Year':[]})

callback = CustomJS(args=dict(source=source, sel_src=sel_src), code="""
var f = cb_obj.value

sel_src.data['Year']=[]
sel_src.data['A']=[]
sel_src.data['B']=[]
sel_src.data['C']=[]
sel_src.data['D']=[]
for(var i = 0; i <= source.get_length(); i++){
    
        if (f==source.data['Year'][i]){
            sel_src.data['A'].push(source.data['A'][i]);
            sel_src.data['B'].push(source.data['B'][i]);
            sel_src.data['C'].push(source.data['C'][i]);
            sel_src.data['D'].push(source.data['D'][i]);
            sel_src.data['Year'].push(source.data['Year'][i])
     }
}   

sel_src.change.emit();
""")

menu = Select(options=list(df['Year']),value='2000', title = 'Year')  # drop down menu
menu.js_on_change('value', callback) # calling the function on change of selection
layout=column(menu,p1)
show(layout) 

How do i make the individual values (each year) respond to the callback so that there are 3 different plots for 3 years in the menu?

⌁   Link to post
Bryan
Bryan

By far, the simplest thing to do is to create all the plots up front, and put them all in a column (or whatever) and then have the CustomJS just toggle the .visible attributtes of the plots approprtiately, based on the dropdown value.

Trying to update an existing plot with several glyphs and a legend “in-place” is more work, and more fragile.

⌁   Link to post
Bryan
Bryan

It depends, on how much data is in each plot and/or whether you can share the same data source between the different plots (ideally yes). The simplest thing to do is just give it a try and see if it works for your situation. If not, then next thing might be to ad all the glyphs up front to a single plot, and use the CustomJS to toggle the visibility of the glyphs. But you will probably need to manage the legend in manually in that case (but that’s also the case with your original approach).

⌁   Link to post
gmerritt123
gmerritt123

Kinda an aside but setup for legend updating could be vastly simplified if this feature ever became a thing: [FEATURE] GlyphLegendItem for arbitrary legend items · Issue #10776 · bokeh/bokeh · GitHub

You could just build a dictionary with a key for each dropdown item, and store the datasource, the plot renderers and the legend renders in each dict entry, e.g.

d = {'A': {'src':ColumnDataSource(),'rend':p.line(...), 'leg_entries':[GlyphLegendItem(..)] }}

Then just pass d into CustomJS and update the pieces accordingly based on dropdown item active change. This whole setup works really nicely now, except for the legend piece.

⌁   Link to post

End of archived discussion · Replies are disabled