Bokeh回调中动态更新多线图时遇属性数组检索错误
Hey there, let's tackle this Bokeh dynamic multi-line plot issue you're facing. That "attempted to retrieve property array for none..." error usually pops up when your glyphs or legends are still clinging to old column names that don't exist in the new dataset you're switching to. Since your datasets have variable columns and data types, we need a flexible approach that fully resets and rebuilds the plot elements whenever the country selection changes.
Core Issue Breakdown
When you switch datasets without cleaning up old plot components:
- Existing
Lineglyphs still reference column names from the previous country's data - The legend remains linked to these outdated glyphs
- Bokeh tries to fetch data for columns that no longer exist in the new
ColumnDataSource, triggering the error
Step-by-Step Solution
We'll build a dynamic system that:
- Tracks current plot renderers to clean them up on switch
- Rebuilds glyphs and legend items based on the active dataset's columns
- Fully replaces the data source with the new country's data
Full Working Code Example
from bokeh.io import curdoc from bokeh.models import ColumnDataSource, Select, Legend from bokeh.plotting import figure from bokeh.layouts import column import pandas as pd # Sample datasets with variable columns (matching your use case) country_datasets = { "USA": pd.DataFrame({ "year": [2010, 2011, 2012, 2013], "gdp": [15, 15.5, 16, 16.5], "unemployment": [9, 8.5, 8, 7.5] }), "Japan": pd.DataFrame({ "year": [2010, 2011, 2012, 2013], "gdp": [5, 5.2, 5.1, 5.3], "exports": [1.2, 1.3, 1.1, 1.4], "inflation": [0.1, 0.2, -0.1, 0] }), "India": pd.DataFrame({ "year": [2010, 2011, 2012, 2013], "gdp": [1.5, 1.7, 1.9, 2.1] }) } # Initialize plot and core components plot = figure( x_axis_label="Year", y_axis_label="Value", title="Country Economic Metrics", width=800, height=400 ) source = ColumnDataSource() renderers = [] # Track active line renderers for cleanup legend = Legend(items=[], location="top_left") plot.add_layout(legend) # Define update logic def update_plot(selected_country): # 1. Clean up old renderers and legend items for renderer in renderers: plot.renderers.remove(renderer) renderers.clear() legend.items = [] # 2. Load new dataset and update data source current_data = country_datasets[selected_country] source.data = current_data.to_dict("list") # 3. Build new lines and legend items x_column = "year" y_columns = [col for col in current_data.columns if col != x_column] color_palette = ["#2c3e50", "#27ae60", "#e74c3c", "#f39c12"] for idx, y_col in enumerate(y_columns): line = plot.line( x=x_column, y=y_col, source=source, color=color_palette[idx % len(color_palette)], line_width=2 ) renderers.append(line) legend.items.append((y_col, [line])) # Set initial state initial_country = "USA" update_plot(initial_country) # Create selection widget country_selector = Select( title="Select Country:", value=initial_country, options=list(country_datasets.keys()) ) country_selector.on_change("value", lambda attr, old, new: update_plot(new)) # Assemble layout and run layout = column(country_selector, plot) curdoc().add_root(layout)
Key Details to Note
- Renderer Cleanup: We maintain a
rendererslist to track all active line glyphs. When switching countries, we remove these from the plot entirely to eliminate references to old columns. - Dynamic Legend Building: The legend is rebuilt from scratch each time, ensuring only columns present in the current dataset are included.
- Full Data Source Replacement: Since column counts vary, we don't use
patch()—we fully replace thesource.datawith the new dataset's dictionary representation. - Bokeh Server Requirement: This uses Python callbacks, so you'll need to run it with
bokeh serve --show your_script.py(static HTML with CustomJS is far less flexible for variable column scenarios).
Additional Tips
- Ensure your x-axis column (e.g.,
year) exists in all datasets. If even the x-column varies, add logic to detect and update thexparameter in theline()call. - For large datasets, consider optimizing by reusing glyphs instead of rebuilding, but for variable columns, full cleanup/rebuild is the most reliable approach.
内容的提问来源于stack exchange,提问作者Gaurab Ghosh
相关产品推荐
相关产品推荐

