Bokeh Python: выберите раскрывающийся список обновляет ColumnDataSource, но не обновляет график - PullRequest
1 голос
/ 04 октября 2019

Я новичок в Bokeh и пытаюсь создать интерактивный график данных о погоде. Существует два меню выбора, одно для идентификатора датчика (132, 133, ...) и одно для переменной (температура, точка росы, ...). Когда пользователь изменяет любое значение, график должен обновляться с выбранными данными.

Данные, которые я использую, находятся в кадре данных Panda, где есть столбец «dt», который содержит объекты даты и времени с интервалом в одну минуту, а данные находятся в столбцах, которые соответствуют соглашению об именовании «Temp132»,«Temp 133», «Dew132», «Dew133» и т. Д. В идеале выбранные пользователем значения из меню «Выбор» должны объединяться в строку, которая может использоваться для извлечения ряда данных из 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))

Спасибо за помощь!

1 Ответ

0 голосов
/ 04 октября 2019

Вы не должны назначать .data с одного CDS на другой CDS. В следующем Bokeh 2.0 попытка сделать это вызовет явное сообщение об ошибке. Хотя он ведет себя подобно dict, это не так. Чтобы поддерживать всю автоматическую синхронизацию между Python и JS, CDS .data на самом деле является очень специализированной структурой данных, которая имеет связи со многими другими вещами, и «переназначение» их с одного CDS на другой не поддерживается. Вам следует назначать .data только из простого python dict

source.data = { ... } # plain python dict

Если вам нужно адаптировать DataFrame, на CDS есть метод .from_df, который создаст соответствующийпростая структура python dict, которую вы можете использовать для назначения.

...