如何基于下拉菜单更新数据源?Bokeh图表不更新问题求助
Hey Vikram, I see exactly where the issue is with your callback! The problem isn't with select.js_on_change itself—it's how you're updating the data source in your CustomJS code.
The Root Cause
In your current callback, you're creating a new data object and then doing rect = {...}. But rect was just a reference to rc.data_source.data when you passed it into the callback. Reassigning it like this breaks that reference, so Bokeh never gets notified that the underlying data has changed. You need to directly modify the existing data source object and then trigger a change event for Bokeh to update the plot.
Modified Callback Code
Here's the fixed version of your CustomJS, with key changes highlighted:
callback = CustomJS(args = {'rect_source': rc.data_source, 'source': source}, code = """ var x = source.data var select = cb_obj.value var data = {"AGE_GROUP": [], "CAUSE": [], "DEATHS": [], "RATE": [], "YEAR": []} // Get indices where cause matches the selected option var indices = x.CAUSE.map((e,i) => e === select ? i : null).filter(i => i !== null) // Populate the filtered data with a single loop indices.forEach(i => { data.AGE_GROUP.push(x.AGE_GROUP[i]) data.CAUSE.push(x.CAUSE[i]) data.DEATHS.push(x.DEATHS[i]) data.RATE.push(x.RATE[i]) data.YEAR.push(x.YEAR[i]) }) // Directly update the rect's data source fields (preserves Bokeh's reference) rect_source.data.AGE_GROUP = data.AGE_GROUP rect_source.data.CAUSE = data.CAUSE rect_source.data.DEATHS = data.DEATHS rect_source.data.RATE = data.RATE rect_source.data.YEAR = data.YEAR // Trigger Bokeh's change event to refresh the plot rect_source.change.emit() console.log("Updated data:", rect_source.data) """ )
Key Changes Explained
- Renamed
recttorect_source: Makes it clearer we're working with the full data source object, not just the raw data dictionary. - Direct field updates: Instead of reassigning the entire data object, we update each field of
rect_source.dataindividually. This keeps the reference Bokeh is tracking intact. - Added
rect_source.change.emit(): This tells Bokeh the data source has changed, triggering a plot re-render with the new filtered data. - Simplified loops: Swapped multiple separate loops for a single
forEach—cleaner and more efficient.
Bonus: More Concise Filtering
You can streamline the code even further by filtering rows directly, which is easier to maintain if you add more columns later:
callback = CustomJS(args = {'rect_source': rc.data_source, 'source': source}, code = """ var x = source.data var select = cb_obj.value // Convert row-based data to column-based after filtering var filtered = x.CAUSE.map((cause, idx) => ({ AGE_GROUP: x.AGE_GROUP[idx], CAUSE: cause, DEATHS: x.DEATHS[idx], RATE: x.RATE[idx], YEAR: x.YEAR[idx] })).filter(row => row.CAUSE === select) // Map filtered rows back to column format rect_source.data = { AGE_GROUP: filtered.map(r => r.AGE_GROUP), CAUSE: filtered.map(r => r.CAUSE), DEATHS: filtered.map(r => r.DEATHS), RATE: filtered.map(r => r.RATE), YEAR: filtered.map(r => r.YEAR) } rect_source.change.emit() """ )
Give either version a try—your rect chart should now update correctly when you select different options from the dropdown!
内容的提问来源于stack exchange,提问作者Vikram Arul Adityan

