Why is Bokeh's plot not changing with plot selection?

被刻印的时光 ゝ 提交于 2021-02-05 09:29:17

问题


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.

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.

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))

UPDATED: ERRORS:

1) No errors show up in Jupyter Notebook.

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).

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).


回答1:


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

Or, if you want to update from a DataFame:

source.data = ColumnDataSource.from_df(new_df)

As an aside, don't assign the .data from one CDS to another:

source.data = other_source.data  # BAD

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.

Lastly, I don't think any of those last JS console errors were generated by BokehJS.



来源:https://stackoverflow.com/questions/59114108/why-is-bokehs-plot-not-changing-with-plot-selection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!