You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bokeh交互式可视化图表不更新问题求助

Hey there! Let's figure out why your Bokeh Select tool isn't updating your COVID stats chart—this is a super common gotcha when you're just starting out with Bokeh's interactivity, so you're not alone here.

First, let's break down the core issue: Bokeh charts are data-source driven. That means every element you see (lines, bars, etc.) is tied to a ColumnDataSource. If your chart isn't updating when you switch the Select option, it almost always means your callback isn't properly modifying this data source, or isn't telling Bokeh that the data has changed.

Let's walk through a fixed example based on what you described, plus explain the key fixes:

Example Fixed Code (Static HTML with JS Callback)

This works for generating a standalone HTML file that doesn't need a server:

from bokeh.plotting import figure, show, output_file
from bokeh.models import ColumnDataSource, Select, CustomJS
from bokeh.layouts import column
import pandas as pd

# Mock COVID data (replace this with your actual dataset)
data = {
    'Date': pd.date_range(start='2020-01-01', periods=100),
    'US_cases': [i*100 for i in range(100)],
    'US_deaths': [i*10 for i in range(100)],
    'India_cases': [i*80 for i in range(100)],
    'India_deaths': [i*8 for i in range(100)]
}
df = pd.DataFrame(data)

# Initialize the data source with default country (US)
source = ColumnDataSource(data=dict(
    x=df['Date'],
    cases=df['US_cases'],
    deaths=df['US_deaths']
))

# Prepare all country data for the JS callback (so it can access it client-side)
all_country_data = {
    'US': {'cases': df['US_cases'].tolist(), 'deaths': df['US_deaths'].tolist()},
    'India': {'cases': df['India_cases'].tolist(), 'deaths': df['India_deaths'].tolist()}
}

# Create the plot
p = figure(x_axis_type='datetime', title='COVID-19 Cases & Deaths by Country', 
           x_axis_label='Date', y_axis_label='Number of People')
p.line('x', 'cases', source=source, color='#1f77b4', legend_label='Confirmed Cases')
p.line('x', 'deaths', source=source, color='#ff4b5c', legend_label='Deaths')

# Add the Select dropdown
country_select = Select(title='Choose a Country:', value='US', options=['US', 'India'])

# The critical part: CustomJS callback to update the data source
update_callback = CustomJS(
    args=dict(source=source, all_data=all_country_data),
    code="""
        // Get the selected country from the dropdown
        const selected = cb_obj.value;
        // Pull the corresponding data from our prepped dataset
        const new_data = all_data[selected];
        
        // Update the data source's fields
        source.data.cases = new_data.cases;
        source.data.deaths = new_data.deaths;
        
        // Tell Bokeh the data has changed (this is easy to forget!)
        source.change.emit();
    """
)

# Link the callback to the Select dropdown's value change
country_select.js_on_change('value', update_callback)

# Combine dropdown and plot into a layout
layout = column(country_select, p)
output_file('covid_interactive.html')
show(layout)

If You Need a Bokeh Server (Python Callback)

If you're doing more complex data processing (like fetching live data), use a Python callback with Bokeh Server:

from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Select
from bokeh.layouts import column
import pandas as pd

# Mock COVID data
data = {
    'Date': pd.date_range(start='2020-01-01', periods=100),
    'US_cases': [i*100 for i in range(100)],
    'US_deaths': [i*10 for i in range(100)],
    'India_cases': [i*80 for i in range(100)],
    'India_deaths': [i*8 for i in range(100)]
}
df = pd.DataFrame(data)

source = ColumnDataSource(data=dict(
    x=df['Date'],
    cases=df['US_cases'],
    deaths=df['US_deaths']
))

p = figure(x_axis_type='datetime', title='COVID-19 Cases & Deaths by Country', 
           x_axis_label='Date', y_axis_label='Number of People')
p.line('x', 'cases', source=source, color='#1f77b4', legend_label='Confirmed Cases')
p.line('x', 'deaths', source=source, color='#ff4b5c', legend_label='Deaths')

country_select = Select(title='Choose a Country:', value='US', options=['US', 'India'])

def update_plot(attr, old_value, new_value):
    # Fetch the new data based on selected country
    new_cases = df[f'{new_value}_cases']
    new_deaths = df[f'{new_value}_deaths']
    
    # Update the entire data source (Bokeh detects this change automatically)
    source.data = dict(
        x=df['Date'],
        cases=new_cases,
        deaths=new_deaths
    )

# Link the callback to the dropdown
country_select.on_change('value', update_plot)

curdoc().add_root(column(country_select, p))

Run this with bokeh serve --show your_script.py

Key Fixes to Note

  1. Always Update the ColumnDataSource: This is the backbone of Bokeh interactivity. If you don't modify this source, your chart will never change.
  2. Trigger Data Change (JS Callback): In CustomJS, you must call source.change.emit() after updating data—this tells Bokeh to re-render the chart.
  3. Use Correct Callback Type: Static HTML needs CustomJS; server-side logic needs Python callbacks with Bokeh Server.
  4. Match Dropdown Options to Data: Make sure your Select's options exactly match the prefix/suffix of your data columns (e.g., "US" maps to "US_cases" and "US_deaths").

If your original code was missing any of these steps, adding them should fix the update issue. If you still run into trouble, feel free to share your exact code and we can tweak it further!

内容的提问来源于stack exchange,提问作者Indranil Mallick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 12:12:35