问题
I'm new to Bokeh and I'm trying to create an interactive plot of weather data. There are two Select menus, one for sensor ID (132, 133, ...), and one for variable (Temperature, Dew Point, ...). When the user changes either value, the graph is supposed to update with the selected data.
The data I'm using is in a Panda Dataframe, where there is a column 'dt' which contains the one minute interval datetime objects, and the data are in columns that follow the naming convention 'Temp132', 'Temp 133', 'Dew132', 'Dew133', etc. Ideally, the user selected values from the Select menus would be combined to make a string that could be used to extract a data series out of df ('Temp' + '132' would be used to call df['Temp132']).
Using print statements, I can see that when the user changes a value in the Select menu, the ColumnDataSource is getting updated. However, it is not updating the graph. I think I'm doing something wrong with the "make_plot" function. Also, I am running this using the Bokeh server (bokeh serve --show bokeh_test.py
).
Below is an excerpt of my code:
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))
Thank you for your help!
回答1:
You should not assign the .data
from one CDS to another CDS. In the upcoming Bokeh 2.0 trying to do this will raise an explicit error message. Although it behaves similar to a dict
, it is not. In order to support all the automatic synchronization between Python and JS the CDS .data
is actually a very specialized data structure that has linkages to many other things, and "re-homing" them from one CDS to another is not supported. You should only ever assign to .data
from a plain python dict
source.data = { ... } # plain python dict
If you need to adapt a DataFrame there is a .from_df
method on CDS that will create the appropriate plain python dict structure you can use to assign from.
来源:https://stackoverflow.com/questions/58238699/bokeh-python-select-dropdown-is-updating-columndatasource-but-not-updating-the