【问题标题】:Why is Bokeh's plot not changing with plot selection?为什么 Bokeh 的情节不会随着情节选择而改变?
【发布时间】:2020-03-25 14:25:59
【问题描述】:

难以理解为什么这种散景视觉效果不允许我更改绘图并查看预测数据。绘图和选择(下拉式)菜单出现,但我无法更改菜单中项目的绘图。

通过 Anaconda 运行 Bokeh 1.2.0。该代码已在 Jupyter 内部和外部运行。运行代码时不会显示错误。我浏览了一些与同一问题相关的 SO 帖子,但我无法成功应用相同的解决方案。

我不知道如何从中创建一个玩具问题,所以除了下面的代码示例之外,完整的代码(包括回归代码和相应的数据)可以在我的 github 找到 here (代码: Regression&Plotting.ipynb数据: pred_data.csvhistorical_data.csvfeatures_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 中没有显示错误。

2) CLI 显示 UserWarning: Pandas doesn't allow columns to be careated via a new attribute name,引用 `historical_data.data = ColumnDatasource.from_df(new_hist_source)。

最终,该图应该有一条线表示历史数据,另一条线或点表示来自 sklearn 的预测数据。它还有一个下拉菜单,可以选择要绘制的每个项目(一次一个)。

【问题讨论】:

    标签: python-3.x pandas plot scikit-learn bokeh


    【解决方案1】:

    您的update_plot 是一个空操作,实际上不会对散景模型状态进行任何更改,而这是更改散景图所必需的。更改 Bokeh 模型状态意味着将新值分配给 Bokeh 对象上的属性。通常,要更新绘图,您会计算一个新的数据字典,然后从中设置一个现有的 CDS:

    source.data = new_data  # plain python dict
    

    或者,如果您想从 DataFame 更新:

    source.data = ColumnDataSource.from_df(new_df)
    

    顺便说一句,不要将.data 从一个 CDS 分配给另一个:

    source.data = other_source.data  # BAD
    

    相比之下,您的update_plot 会计算一些新数据,然后将其丢弃。请注意,从任何 Bokeh 回调中返回任何内容都没有任何目的。回调由 Bokeh 库代码调用,它不期望或使用任何返回值。

    最后,我不认为任何最后的 JS 控制台错误是由 BokehJS 生成的。

    【讨论】:

    • 感谢@bigreddot。我按照您的建议更新了代码。命令行产生一个AttributeError("'ColumnDataSource' object has no attribute 'copy'")。我从 get_historical_dataget_prediction_data 函数中删除了 .copy() 方法,但仍然有错误。将更改分配回保存数据的原始变量(即data = data.drop())是否符合“复制”的条件?
    • 我也尝试将上述函数中的数据保留为数据框,但随后出现错误Pandas doesn't allow columns to be created via anew attribute name,但我相信您在另一位用户的帖子中提到您不熟悉 Pandas 的内容错误意味着......我认为如果可能的话,最好在整个过程中将其保留为 CSD。
    • from_df 用于将 DataFrames 调整为 CDS 格式,因此您的 get_historical_data 应该返回 DataFrame,而不是 CDS。只需完全删除行 prediction_data = ColumnDataSource(prediction_data)
    • 这也是我的想法,因此也是我在第二条评论中采取行动的原因。不幸的是,我收到了同样的警告(我在上面的评论中错误地将其称为“错误”)。
    • 太好了,我已经开始讨论了。非常感谢您在此处关闭一个问题,这样就不会有一个挥之不去的未回答的项目问题。
    猜你喜欢
    • 2019-01-21
    • 2019-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-14
    • 2022-07-21
    相关资源
    最近更新 更多