Bokeh Python: Select 下拉列表正在更新 ColumnDataSource 但没有更新图表

Bokeh Python: Select dropdown is updating ColumnDataSource but not updating the graph

我是 Bokeh 的新手,我正在尝试创建天气数据的交互式图表。有两个 Select 菜单,一个用于传感器 ID(132、133,...),一个用于变量(温度、露点,...)。当用户更改任一值时,图表应该使用所选数据进行更新。

我使用的数据在 Panda Dataframe 中,其中有一列 'dt' 包含一分钟间隔的日期时间对象,数据位于遵循命名约定的列中 'Temp132'、'Temp 133'、'Dew132'、'Dew133' 等。理想情况下,用户从 Select 菜单中选择的值将组合成一个可用于提取的字符串来自 df 的数据系列('Temp' + '132' 将用于调用 df['Temp132'])。

使用 print 语句,我可以看到当用户更改 Select 菜单中的值时,ColumnDataSource 正在更新。但是,它没有更新图表。我想我在 "make_plot" 函数上做错了什么。另外,我 运行 使用 Bokeh 服务器 (bokeh serve --show bokeh_test.py)。

下面是我的代码的摘录:

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

def get_dataset(src, height, var, dt):
    var_str = var_z[var]['var']
    z_str   = var_z[height]['z']
    df_sub =src[[var_str+z_str]].copy()
    df_sub['dt'] = dt
    df_sub = pd.DataFrame(data=df_sub.values, columns=[var_str+height, 'dt'])
    return ColumnDataSource(data=df_sub)

def make_plot(in_source, y_label_var):
    var = variable_select.value
    z   = height_select.value
    var_str = var_z[var]['var']
    plot = figure(plot_width=800, plot_height=800, title="Data ", x_axis_label = 'Date and Time', y_axis_label = y_label_var)
    plot.line('dt', var_str+z, line_width=2, source=in_source)
    plot.xaxis.formatter=DatetimeTickFormatter( days=["%m/%d/%Y %H:%M"],
        months=["%m/%d/%Y %H:%M"],
        hours=["%m/%d/%Y %H:%M"],
        minutes=["%m/%d/%Y %H:%M"])
    plot.xaxis.major_label_orientation = pi/4

    return plot

def update_plot(attr, old, new):
    var = variable_select.value
    z   = height_select.value
    plot.title.text = var_z[var]['title'] + " " + var_z[z]['title']
    src = get_dataset(df, var_z[z]['z'], var_z[var]['title'], dt)

    print(source.data)
    source.data = src.data
    print(source.data)

#-----------------------------------------------------------------------------

init_height = '132'
init_var    = 'Temperature'

var_z = {'Temperature'        : {'var': 'Temp',         'title': 'Temperature',},
         'Dew Point'          : {'var': 'Dew',          'title': 'Dew Point',},
         'Mean Wind Direction': {'var': 'MeanWindDir',  'title': 'Mean Wind Direction',},
         'Mean Wind Speed'    : {'var': 'MeanWindSpeed','title': 'Mean Wind Speed',},
         'Peak Wind Speed'    : {'var': 'PeakWindSpeed','title': 'Peak Wind Speed',},
         'Peak Wind Direction': {'var': 'PeakWindDir',  'title': 'Peak Wind Direction',},
         'Relative Humidity'  : {'var': 'RH',           'title': 'Relative Humidity',},
         '132' : {'z': '132', 'title': '132',},
         '133' : {'z': '133', 'title': '133',},
         '134' : {'z': '134', 'title': '134',},
         '257' : {'z': '257', 'title': '257',},
         '258' : {'z': '258', 'title': '258',},
         '259' : {'z': '259', 'title': '259',},
         '382' : {'z': '382', 'title': '382',},
         '383' : {'z': '383', 'title': '383',},
         '384' : {'z': '384', 'title': '384',},
         '457' : {'z': '457', 'title': '457',},
         '458' : {'z': '458', 'title': '458',},
         '459' : {'z': '459', 'title': '459',}}

height_select  = Select(value=init_height, title='Height', options = ["132","133","134","257","258","259","382","383","384","457","458","459"])
variable_select= Select(value=init_var, title = 'Variable', options = ["Temperature", "Dew Point", "Mean Wind Direction", "Mean Wind Speed", "Peak Wind Speed", "Peak Wind Direction", "Relative Humidity"] )

df = pd.read_csv('My/File/Path')
dt = df['dt'].to_list()
source = get_dataset(df, init_height, init_var, dt)
plot = make_plot(source, var_z[init_var]['var'])

height_select.on_change('value', update_plot)
variable_select.on_change('value', update_plot)

controls = column(height_select, variable_select)

curdoc().add_root(row(plot,controls))

感谢您的帮助!

您不应将 .data 从一个 CDS 分配给另一个 CDS。在即将推出的 Bokeh 2.0 中,尝试这样做将引发明确的错误消息。尽管它的行为类似于 dict,但事实并非如此。为了支持 Python 和 JS 之间的所有自动同步,CDS .data 实际上是一个非常专业的数据结构,它与许多其他事物有联系,并且 "re-homing" 它们从一个 CDS 到另一个不支持。您应该只从 plain python dict

分配给 .data
source.data = { ... } # plain python dict

如果您需要调整 DataFrame,CDS 上有一个 .from_df 方法可以创建适当的普通 python 字典结构,您可以使用它来分配。