为什么Bokeh的地块不会随着地块选择而改变? [英] Why is Bokeh's plot not changing with plot selection?
问题描述
努力理解为什么这个散景效果视图不允许我更改图并查看预测数据.出现图和选择(下拉菜单)菜单,但我无法更改菜单中项目的图.
Struggling to understand why this bokeh visual will not allow me to change plots and see the predicted data. The plot and select (dropdown-looking) menu appears, but I'm not able to change the plot for items in the menu.
通过Anaconda运行Bokeh 1.2.0.该代码已在内部&在Jupyter之外.运行代码时没有错误显示.我已经浏览了与同一问题相关的少数SO帖子,但未能成功应用相同的解决方案.
Running Bokeh 1.2.0 via Anaconda. The code has been run both inside & outside of Jupyter. No errors display when the code is run. I've looked through the handful of SO posts relating to this same issue, but I've not been able to apply the same solutions successfully.
我不确定如何由此产生玩具问题,因此,除了下面的代码示例外,完整的代码(包括回归代码和相应的数据)都可以在我的github
I wasn't sure how to create a toy problem out of this, so in addition to the code sample below, the full code (including the regression code and corresponding data) can be found at my github here (code: Regression&Plotting.ipynb
, data: pred_data.csv
, historical_data.csv
, features_created.pkd
.)
import pandas as pd
import datetime
from bokeh.io import curdoc, output_notebook, output_file
from bokeh.layouts import row, column
from bokeh.models import Select, DataRange1d, ColumnDataSource
from bokeh.plotting import figure
#Must be run from the command line
def get_historical_data(src_hist, drug_id):
historical_data = src_hist.loc[src_hist['ndc'] == drug_id]
historical_data.drop(['Unnamed: 0', 'date'], inplace = True, axis = 1)#.dropna()
historical_data['date'] = pd.to_datetime(historical_data[['year', 'month', 'day']], infer_datetime_format=True)
historical_data = historical_data.set_index(['date'])
historical_data.sort_index(inplace = True)
# csd_historical = ColumnDataSource(historical_data)
return historical_data
def get_prediction_data(src_test, drug_id):
#Assign the new date
#Write a new dataframe with values for the new dates
df_pred = src_test.loc[src_test['ndc'] == drug_id].copy()
df_pred.loc[:, 'year'] = input_date.year
df_pred.loc[:, 'month'] = input_date.month
df_pred.loc[:, 'day'] = input_date.day
df_pred.drop(['Unnamed: 0', 'date'], inplace = True, axis = 1)
prediction = lin_model.predict(df_pred)
prediction_data = pd.DataFrame({'drug_id': prediction[0][0], 'predictions': prediction[0][1], 'date': pd.to_datetime(df_pred[['year', 'month', 'day']], infer_datetime_format=True, errors = 'coerce')})
prediction_data = prediction_data.set_index(['date'])
prediction_data.sort_index(inplace = True)
# csd_prediction = ColumnDataSource(prediction_data)
return prediction_data
def make_plot(historical_data, prediction_data, title):
#Historical Data
plot = figure(plot_width=800, plot_height = 800, x_axis_type = 'datetime',
toolbar_location = 'below')
plot.xaxis.axis_label = 'Time'
plot.yaxis.axis_label = 'Price ($)'
plot.axis.axis_label_text_font_style = 'bold'
plot.x_range = DataRange1d(range_padding = 0.0)
plot.grid.grid_line_alpha = 0.3
plot.title.text = title
plot.line(x = 'date', y='nadac_per_unit', source = historical_data, line_color = 'blue', ) #plot historical data
plot.line(x = 'date', y='predictions', source = prediction_data, line_color = 'red') #plot prediction data (line from last date/price point to date, price point for input_date above)
return plot
def update_plot(attrname, old, new):
ver = vselect.value
new_hist_source = get_historical_data(src_hist, ver) #calls the function above to get the data instead of handling it here on its own
historical_data.data = ColumnDataSource.from_df(new_hist_source)
# new_pred_source = get_prediction_data(src_pred, ver)
# prediction_data.data = new_pred_source.data
#Import data source
src_hist = pd.read_csv('data/historical_data.csv')
src_pred = pd.read_csv('data/pred_data.csv')
#Prep for default view
#Initialize plot with ID number
ver = 781593600
#Set the prediction date
input_date = datetime.datetime(2020, 3, 31) #Make this selectable in future
#Select-menu options
menu_options = src_pred['ndc'].astype(str) #already contains unique values
#Create select (dropdown) menu
vselect = Select(value=str(ver), title='Drug ID', options=sorted((menu_options)))
#Prep datasets for plotting
historical_data = get_historical_data(src_hist, ver)
prediction_data = get_prediction_data(src_pred, ver)
#Create a new plot with the source data
plot = make_plot(historical_data, prediction_data, "Drug Prices")
#Update the plot every time 'vselect' is changed'
vselect.on_change('value', update_plot)
controls = row(vselect)
curdoc().add_root(row(plot, controls))
已更新:错误:
1)Jupyter Notebook中没有错误显示.
1) No errors show up in Jupyter Notebook.
2)CLI显示了一个 UserWarning:Pandas不允许通过新的属性名称来复制列
,引用的是"historical_data.data = ColumnDatasource.from_df(new_hist_source)".
2) CLI shows a UserWarning: Pandas doesn't allow columns to be careated via a new attribute name
, referencing `historical_data.data = ColumnDatasource.from_df(new_hist_source).
最终,该图应该具有一条历史数据线,以及一条来自sklearn的预测数据线或点.它还具有一个下拉菜单,用于选择要绘制的每个项目(一次选择一个).
Ultimately, the plot should have a line for historical data, and another line or dot for predicted data derived from sklearn. It also has a dropdown menu to select each item to plot (one at a time).
推荐答案
您的 update_plot
是空操作,实际上不会对Bokeh模型状态进行任何更改,这是更改的必要条件散景图.更改散景模型状态意味着为散景对象上的属性分配新值.通常,要更新图,您将计算一个新的数据字典,然后从中设置一个现有的CDS:
Your update_plot
is a no-op that does not actually make any changes to Bokeh model state, which is what is necessary to change a Bokeh plot. Changing Bokeh model state means assigning a new value to a property on a Bokeh object. Typically, to update a plot, you would compute a new data dict and then set an existing CDS from it:
source.data = new_data # plain python dict
或者,如果您想从DataFame更新:
Or, if you want to update from a DataFame:
source.data = ColumnDataSource.from_df(new_df)
顺便说一句,请勿将 .data
从一个CDS分配给另一CDS:
As an aside, don't assign the .data
from one CDS to another:
source.data = other_source.data # BAD
通过对比,您的 update_plot
计算一些新数据,然后将其丢弃.请注意,从任何Bokeh回调中返回任何内容都没有任何目的.回调由Bokeh库代码调用,该代码不期望或不使用任何返回值.
By contrast, your update_plot
computes some new data and then throws it away. Note there is never any purpose to returning anything at all from any Bokeh callback. The callbacks are called by Bokeh library code, which does not expect or use any return values.
最后,我认为最后的JS控制台错误都不是BokehJS产生的.
Lastly, I don't think any of those last JS console errors were generated by BokehJS.
这篇关于为什么Bokeh的地块不会随着地块选择而改变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!