Bokeh下拉菜单选择城市后图表不更新问题求助
Hey there! Let's dig into why your dropdown menu isn't updating the chart. This is a super common gotcha when starting out with Bokeh's interactive features, so let's break it down step by step.
1. First, Check How You're Updating the Data Source
The #1 reason dropdowns fail to update charts is that developers often create a new ColumnDataSource instead of modifying the existing one. Bokeh charts bind to a specific source instance—if you replace it entirely, the chart won't recognize the new data.
Wrong approach:
# Don't do this in your callback! source = ColumnDataSource(new_city_data)
Correct approach:
Update the data property of your existing source:
# This tells the chart to refresh with new values source.data = new_city_data
2. Pick the Right Callback Type for Your Use Case
Your choice of callback depends on whether you're using Bokeh Server or a static (browser-only) plot:
Option A: Static Plot with CustomJS (No Server)
If you're not running Bokeh Server, you need to load all city data upfront (since browsers can't read local HDF files directly). Pass all your test data to the CustomJS callback, then swap out the source data when the dropdown changes:
from bokeh.models import Select, CustomJS, ColumnDataSource from bokeh.plotting import figure, show from bokeh.layouts import column # Test data matching your expected structure city_data = { "Beijing": {"days": list(range(1,13)), "sun_hours": [6.2,7.3,9.1,11.2,13.5,14.7,14.1,12.8,10.5,8.3,6.5,5.8]}, "Shanghai": {"days": list(range(1,13)), "sun_hours": [5.8,6.7,8.2,10.1,12.3,13.5,12.9,11.7,9.8,7.6,6.1,5.5]}, "Guangzhou": {"days": list(range(1,13)), "sun_hours": [4.5,5.2,6.8,8.5,10.2,11.3,10.8,9.7,8.3,6.9,5.7,4.9]} } # Initialize with default city data source = ColumnDataSource(data=city_data["Beijing"]) p = figure(x_axis_label='Month', y_axis_label='Sun Hours', title='Monthly Sunlight Duration') p.line(x='days', y='sun_hours', source=source, line_width=2) # Dropdown setup select = Select(title="Select City:", value="Beijing", options=list(city_data.keys())) # JS callback to swap data callback = CustomJS(args=dict(source=source, city_data=city_data, select=select), code=""" const selected = select.value; source.data = city_data[selected]; """) select.js_on_change('value', callback) show(column(select, p))
Option B: Bokeh Server (For Reading HDF Files)
If you need to read HDF files dynamically when the dropdown changes, you must use Bokeh Server (since only the server can access local files). Here's a simplified example:
from bokeh.models import Select from bokeh.plotting import figure, curdoc from bokeh.layouts import column from bokeh.models import ColumnDataSource import pandas as pd # Empty initial source source = ColumnDataSource(data={'days': [], 'sun_hours': []}) p = figure(x_axis_label='Month', y_axis_label='Sun Hours', title='Monthly Sunlight Duration') p.line(x='days', y='sun_hours', source=source, line_width=2) select = Select(title="Select City:", value="Beijing", options=["Beijing", "Shanghai", "Guangzhou"]) def update_plot(attr, old, new): # Read HDF data for the selected city df = pd.read_hdf('your_data.h5', key=new) # Adjust key to match your HDF structure source.data = { 'days': df['days'].tolist(), 'sun_hours': df['sun_hours'].tolist() } # Bind dropdown change to update function select.on_change('value', update_plot) # Load initial data update_plot(None, None, select.value) curdoc().add_root(column(select, p))
Run this with bokeh serve --show your_script.py
3. Double-Check Data Structure Consistency
Make sure every city's data (whether test or from HDF) has exactly the same column names as your initial ColumnDataSource. If your source expects days and sun_hours, but a city's data uses month or sunlight_hours, the chart won't update—Bokeh can't map mismatched fields.
4. Verify Callback Binding
Ensure you're listening to the right dropdown attribute. The standard attribute to watch is value, so your callback should be attached with select.js_on_change('value', callback) (for CustomJS) or select.on_change('value', update_plot) (for server callbacks).
内容的提问来源于stack exchange,提问作者dan

