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

Bokeh Select组件无法更新图表问题排查求助

问题分析与修复方案

我帮你梳理下代码里的几个关键问题,这些就是导致图表无法更新的核心原因:

1. 数据源格式不匹配

df.to_dict()默认生成的是嵌套字典(结构为{列名: {行索引: 值}}),但ColumnDataSource要求的是列优先的扁平字典(结构为{列名: [值列表]})。你需要把to_dict()改成to_dict('list'),才能让Bokeh正确识别并更新数据。

2. 冗余的数据源创建与不直观的选项映射

你手动创建了d1到d11共11个字典,不仅代码冗余繁琐,而且Select的选项用'd1'、'd2'这种字符串,既不直观还容易出错。我们可以直接用主题名称作为选项,通过字典映射关联对应的数据源,代码会简洁很多。

3. 更新逻辑的冗余与一致性问题

原代码里的多个if判断重复且易出错,而且初始数据源和更新用的数据源格式不一致,导致切换时无法正确渲染。


修复后的完整代码

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

# 读取数据
df = pd.read_excel('data.xlsx')

# 构建主题到数据源的映射:用直观的主题名作为key,列格式字典作为value
subject_sources = {
    "全部数据": df[['Polarity', 'Subjectivity']].to_dict('list'),
    "赞美": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'compliment'].to_dict('list'),
    "投诉": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'complaint'].to_dict('list'),
    "基础设施": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'infrastructure'].to_dict('list'),
    "管理部门": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'autority'].to_dict('list'),
    "财务": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'finance'].to_dict('list'),
    "英语相关": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'english'].to_dict('list'),
    "安全风险": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'danger'].to_dict('list'),
    "健康": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'health'].to_dict('list'),
    "运动": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'sport'].to_dict('list'),
    "其他": df[['Polarity', 'Subjectivity']].loc[df['Subject'] == 'remaining'].to_dict('list'),
}

# 初始化数据源:默认显示全部数据
source = ColumnDataSource(data=subject_sources["全部数据"])

# 创建图表(添加标题和坐标轴标签提升可读性)
p = figure(title="情感极性与主观性分布", x_axis_label='Polarity(情感极性)', y_axis_label='Subjectivity(主观性)')
r = p.circle(x='Polarity', y='Subjectivity', source=source, alpha=0.6)

# 创建Select组件:选项用直观的主题名称
select = Select(title="选择主题分类", options=list(subject_sources.keys()), value="全部数据")

# 简化更新逻辑:用字典映射替代重复的if判断
def update_plot(attr, old, new):
    source.data = subject_sources[new]

# 绑定选择事件
select.on_change('value', update_plot)

# 构建布局并添加到文档
layout = column(row(select, width=400), p)
curdoc().add_root(layout)

额外优化建议

如果你的数据量较大(11000行),可以考虑用CDSView配合GroupFilter来过滤数据,不用提前创建多个数据源,更节省内存:

from bokeh.models import CDSView, GroupFilter

# 初始用完整数据集的数据源
source = ColumnDataSource(df)
# 默认显示所有数据的视图
view = CDSView(source=source)

# 创建图表时指定view
p = figure(title="情感极性与主观性分布", x_axis_label='Polarity', y_axis_label='Subjectivity')
r = p.circle(x='Polarity', y='Subjectivity', source=source, view=view, alpha=0.6)

# 更新函数改成切换过滤器
def update_plot(attr, old, new):
    if new == "全部数据":
        view.filters = []
    else:
        # 匹配主题名称与数据集中的Subject值
        subject_map = {
            "赞美": "compliment",
            "投诉": "complaint",
            # 其他主题的映射关系...
            "其他": "remaining"
        }
        view.filters = [GroupFilter(column_name='Subject', group=subject_map[new])]

这种方式直接在原始数据源上动态过滤,代码更高效,也避免了重复创建数据源的冗余。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:15:59