2017-01-05 16 views
1

そこで私はそこにあるbokehの例から少しのものを構築しようとしています:https://demo.bokehplots.com/apps/weatherシンプルなBokehアプリ:チャートは更新されません

私のデータセットは本当に似ていますが、これは非常に単純ですが、私は説明できない問題があります。

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" 

すべては私がドロップダウンリストの値を変更しようとするまで、私はドロップダウンを使用した場合にデータを更新、機能update_plot()は仕事をしていることを確認できます実行されます。しかし、何らかの理由でプロットが変化しない場合でも、この例はうまく動作します。私はコードのどこでも掘り下げてきたが、私が間違っていることを見つけることはできないようだ。

私はmake_plot()を単純化しようとしましたが、それはそこから来るかもしれないが、それは何も変更していないので、私はアイデアがありません。

私はそれを見つけたが、それを適用することができませんでした:Bokeh: chart from pandas dataframe won't update on trigger

編集私はcolumndatasourceの乗り心地を取得しようと伝統dictionnaryことによってそれを置き換え、それでも同じに実行

最初に答えた後、問題。私は2つの最初の行を取得するが、ドロップダウンを使用した場合、何も起こりません

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" 

: はここに更新されたコードです。 私は誰かがデータ https://github.com/julienschroder/Bokeh_app/tree/master/1

答えて

2

を試してみたい場合はまあ、私はデータなしでコードを実行することはできませんので、私は100%の確信を持って言うことはできませんが、私はこのgithubのページに小さなデータセットをアップロードまあまあ良い考えですそれは実際にその内容が変更されたときに自動的にイベント通知を発することができる、特別に包まれた辞書だ

In [4]: s = ColumnDataSource(data=dict(a=[1,2], b=[3,4])) 

In [5]: type(s.data) 
Out[5]: bokeh.core.property.containers.PropertyValueDict 

.data属性1 ColumnDataSourceは実際に簡単なPythonの辞書ではありません。これはBokehがそのような便利な方法で物事に自動的に反応して更新させる機械の一部です。私は.dataの別のソースを使用して1つのソースの.dataを設定することが何とか問題を引き起こしていると推測しています。私は、.dataを実際のPythonディクテーション以外に設定すると、イベントハンドラが正しく配線されないことを仮定しています。

したがって、短期的な回避策の提案:get_datasetColumnDataSourceを構成しないでください。単純なPython辞書を作成して返します。 df.to_dictはちょうどあなたにちょうど正しい種類のdictを与えてくれる可能性があります。または、必要な列を入れて手書きで作成することもできます。

リクエスト:この制限を修正できる可能性があります。そうでない場合は、ユーザーがこれを行うと大きな警告が出る可能性があります。これらのすべての情報を含むGitHub issue trackerのバグレポートを提出してください。

+0

ありがとうございました。私は提案を試みた(または私がやったと思う)が、まだ更新されたプロットを得ていない。小さなデータセットへのリンクを追加しました。私は掘り続けます。 – User18981898198119

+0

*すべての列データソースで '.data'を更新していないので、今更新していません。 'sourceのようなコードが必要です。data = some_real_python_dict'ここで、左側の 'source'はグリフやグリフの列データソースです。以前の問題は、一部の列データソースから '.data'を取り出し、割り当ての*右*側で使用していました。あなたはまだ 'source.data = somethign'をCDSの左側に置かなければなりません(プロットを更新するもの) – bigreddot

関連する問題