Simple Bokeh app: Chart does not update as expected
所以我一直在尝试从那里的散景示例中构建一些东西:
https://demo.bokeh.org/weather.
我的数据集非常相似,这应该非常简单,但我有一个无法解释的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import os , pickle import pandas as pd from bokeh.io import curdoc from bokeh.layouts import row, column from bokeh.models import ColumnDataSource, Select from bokeh.plotting import figure base_path = '/Users/xxxxxx/Desktop/data/' domain = 'IEM_Domain' metric = 'total_area_burned' def get_dataset(dic , selection , scenario): def _get_mean(thing): _df = pd.DataFrame(thing) _df = _df.mean(axis = 1).cumsum(axis=0) return _df data = { model : _get_mean( dic[model] ) for model in dic.keys() if all([scenario in model , selection in model])} df = pd.DataFrame(data) return ColumnDataSource(data=df) def make_plot(source, title): plot = figure(x_axis_type="datetime", plot_width=800, tools="") plot.title.text = title for _df in source : for col in _df.to_df().columns : if 'index' not in col : plot.line( _df.to_df()['index'] , _df.to_df()[col] , source = _df) else : pass # fixed attributes plot.xaxis.axis_label = 'Year' plot.yaxis.axis_label ="Area burned (km)" plot.axis.axis_label_text_font_style ="bold" return plot def update_plot(attrname, old, new): rcp45 = rcp45_select.value rcp85 = rcp85_select.value src45 = get_dataset(dic , rcp45 , 'rcp45') src85 = get_dataset(dic , rcp85 , 'rcp85') source45.data = src45.data source85.data = src85.data rcp45 = 'CCSM4_rcp45' rcp85 = 'CCSM4_rcp85' dic = pickle.load(open(os.path.join(base_path ,"_".join([domain , metric ]) + '.p'), 'rb'),encoding='latin1') rcp45_models = [ i for i in dic.keys() if 'rcp45' in i] rcp85_models = [ i for i in dic.keys() if 'rcp85' in i] rcp45_select = Select(value=rcp45, title='RCP 45', options=sorted(rcp45_models)) rcp85_select = Select(value=rcp85, title='RCP 85', options=sorted(rcp85_models)) source45 = get_dataset(dic , rcp45 , 'rcp45') source85 = get_dataset(dic , rcp85 ,'rcp85') print(source45.data) plot = make_plot([source45 , source85],"Total area burned") rcp45_select.on_change('value', update_plot) rcp85_select.on_change('value', update_plot) controls = column(rcp45_select, rcp85_select) curdoc().add_root(row(plot, controls)) curdoc().title ="Total Area burned" |
在我尝试更改下拉列表中的值之前,一切都会运行查找,我可以看到函数
我试图简化 make_plot() 以查看它是否可以来自那里,但这并没有改变任何东西,所以我没有想法。
我发现但无法应用它:散景:pandas 数据帧中的图表不会在触发器上更新
第一次回答后编辑
我尝试使用 columndatasource 并将其替换为传统字典,但仍然遇到同样的问题。
这是更新的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | import os , pickle import pandas as pd from bokeh.io import curdoc from bokeh.layouts import row, column from bokeh.models import ColumnDataSource, Select from bokeh.plotting import figure base_path = '/Users/julienschroder/Desktop/data/' domain = 'IEM_Domain' metric = 'total_area_burned' scenarios = ['rcp45','rcp85'] def get_dataset(dic ,selection , scenario = scenarios): #function taking the raw source as dic and a selection of models, it return a dictionnary # like this {scenario : pd.Dataframe(models)} that way i can plot each scenario on their own def _get_mean_cumsum(df ,name): #Extract, average and cumsum the raw data to a dataframe _df = pd.DataFrame(df) _df = _df.mean(axis = 1).cumsum(axis=0) _df = _df.to_frame(name=name) return _df #Just one model at a time for now but hoping to get multilines and so multi models in the future data = { scenario : pd.concat([_get_mean_cumsum(dic[model] , model) for model in selection if scenario in model ] ,axis=1) for scenario in scenarios } return data def make_plot(source, title): plot = figure(x_axis_type="datetime", plot_width=800, tools="") plot.title.text = title #for now it will just deal with one model at a time but in the future I hope to have some multiline plotting hence the for loops for col in source['rcp45']: plot.line(source['rcp45'].index,source['rcp45'][col] ) for col in source['rcp85']: plot.line(source['rcp85'].index , source['rcp85'][col]) # fixed attributes plot.xaxis.axis_label = 'Year' plot.yaxis.axis_label ="Area burned (km)" plot.axis.axis_label_text_font_style ="bold" return plot def update_plot(attrname, old, new): rcp45 = rcp45_select.value rcp85 = rcp85_select.value source = get_dataset(dic,[rcp45 ,rcp85]) #check to see if source gets updated print(source) # <- gets updated properly after dropdown action rcp45 = 'CCSM4_rcp45' rcp85 = 'CCSM4_rcp85' # dic = pickle.load(open(os.path.join(base_path ,"_".join([domain , metric ]) + '.p'), 'rb'),encoding='latin1') dic = pickle.load(open('IEM_Domain_total_area_burned.p', 'rb'),encoding='latin1') #data available there : https://github.com/julienschroder/Bokeh_app/tree/master/1 rcp45_models = [ i for i in dic.keys() if 'rcp45' in i] rcp85_models = [ i for i in dic.keys() if 'rcp85' in i] rcp45_select = Select(value=rcp45, title='RCP 45', options=sorted(rcp45_models)) rcp85_select = Select(value=rcp85, title='RCP 85', options=sorted(rcp85_models)) source = get_dataset(dic,[rcp45 ,rcp85]) plot = make_plot(source ,"Total area burned") rcp45_select.on_change('value', update_plot) rcp85_select.on_change('value', update_plot) controls = column(rcp45_select, rcp85_select) curdoc().add_root(row(plot, controls)) curdoc().title ="Total Area burned" |
我得到了我的前两行,但使用下拉菜单时没有任何反应。
如果有人想试用数据,我在此 github 页面上上传了一个较小的数据集
https://github.com/julienschroder/Bokeh_app/tree/master/1
好吧,我不能 100% 肯定地说,因为我无法在没有数据的情况下运行代码,但我很清楚问题可能出在哪里。
1 2 3 4 | In [4]: s = ColumnDataSource(data=dict(a=[1,2], b=[3,4])) In [5]: type(s.data) Out[5]: bokeh.core.property.containers.PropertyValueDict |
它实际上是一个经过特殊package的字典,可以在其内容发生更改时自动发出事件通知。这是让 Bokeh 以如此方便的方式自动响应和更新事物的机制的一部分。我猜想通过使用另一个来源的
因此,建议立即解决问题:不要在
还有一个请求:这个限制可能会被修复。否则,如果用户这样做,肯定有可能发出响亮的警告。请在 GitHub 问题跟踪器上提交包含所有这些信息的错误报告。