2017-10-13 10 views
1

bokeh serve機能を使用せずにコールバック関数を使用して棒グラフの対話のようなダッシュボードを作成しようとしています。最終的には、2つのドロップダウンメニューのいずれかが変更された場合、プロットを変更することができます。これまでのところ、これはしきい値がハードコードされている場合にのみ機能します。私はcb_objの値を抽出する方法しか知りませんが、実際には呼び出されないドロップダウンからは抽出しません。私はthisthis最初の試みを公式に答えて見ました。ダッシュボードのようなやりとりを生成するためにBokehコールバックでデータを切り取ります

from bokeh.io import show, output_notebook, output_file 
from bokeh.models import ColumnDataSource, Whisker 
from bokeh.plotting import figure 
from bokeh.transform import factor_cmap 
from bokeh.models import CustomJS, ColumnDataSource, Slider, Select 
from bokeh.layouts import column 

import numpy as np 
import pandas as pd 


def generate_data(factor=10): 
    rawdata = pd.DataFrame(np.random.rand(10,4)*factor, columns = ["A","B","C","D"]) 
    idx = pd.MultiIndex.from_product([["Exp "+str(i) for i in range(5)], 
           [20,999]],names=["Experiment","Threshold"]) 
    rawdata.index = idx 

    return rawdata.reset_index() 

# Generate data 
output_notebook() 
count_data = generate_data() 
error_data = generate_data(factor=2) 
groups = ["A","B","C","D"] 
initial_counts = count_data[(count_data.Experiment == "Exp 0") 
          & (count_data.Threshold == 20)][["A","B","C","D"]].values[0] 
initial_errors = error_data[(error_data.Experiment == "Exp 0") 
          & (error_data.Threshold == 20)][["A","B","C","D"]].values[0] 

# Create primary sources of data 
count_source = ColumnDataSource(data=count_data) 
error_source = ColumnDataSource(data=error_data) 

# Create plotting source of data 
source = ColumnDataSource(data=dict(groups=groups, counts=initial_counts, 
            upper=initial_counts+initial_errors, 
            lower=initial_counts-initial_errors)) 

# Bar chart and figure 
p = figure(x_range=groups, plot_height=350, toolbar_location=None, title="Values", y_range=(0,20)) 
p.vbar(x='groups', top='counts', width=0.9, source=source, legend="groups", 
     line_color='white', fill_color=factor_cmap('groups', palette=["#962980","#295f96","#29966c","#968529"], 
                factors=groups)) 

# Error bars 
p.add_layout(
    Whisker(source=source, base="groups", upper="upper", lower="lower", level="overlay") 
) 

def callback(source=source, count_source = count_source, error_source=error_source, window=None): 

    def slicer(data_source, experiment, threshold, dummy_col, columns): 
     """ Helper function to enable lookup of data.""" 
     count = 0 
     for row in data_source[dummy_col]: 
      if (data_source["Experiment"][count] == experiment) & (data_source["Threshold"][count] == threshold): 
       result = [data_source[col][count] for col in columns] 

      count+=1 

     return result 

    # Initialise data sources 
    data = source.data 
    count_data = count_source.data 
    error_data = error_source.data 

    # Initialise values 
    experiment = cb_obj.value 
    threshold = 20 
    counts, upper, lower = data["counts"], data["upper"], data["lower"] 

    tempdata = slicer(count_data, experiment, threshold,"Experiment", ["A","B","C","D"]) 
    temperror = slicer(error_data, experiment, threshold,"Experiment", ["A","B","C","D"]) 

    # Select values and emit changes 
    for i in range(len(counts)): 
     counts[i] = tempdata[i] 

    for i in range(len(counts)): 
     upper[i] = counts[i]+temperror[i] 
     lower[i] = counts[i]-temperror[i] 

    source.change.emit() 


exp_dropdown = Select(title="Select:", value="Exp 0", options=list(count_data.Experiment.unique()))  
thr_dropdown = Select(title="Select:", value="12", options=list(count_data.Threshold.astype(str).unique()))  

exp_dropdown.callback = CustomJS.from_py_func(callback) 


p.xgrid.grid_line_color = None 
p.legend.orientation = "horizontal" 
p.legend.location = "top_center" 

layout = column(exp_dropdown,thr_dropdown, p) 

show(layout) 

答えて

1

質問に対する解決策がSelectメニューは、コールバック関数の前に定義する必要があることである:

は、ここに私のコードです。このコードの動作:

from bokeh.io import show, output_notebook, output_file 
from bokeh.models import ColumnDataSource, Whisker 
from bokeh.plotting import figure 
from bokeh.transform import factor_cmap 
from bokeh.models import CustomJS, ColumnDataSource, Slider, Select 
from bokeh.layouts import column 

import numpy as np 
import pandas as pd 


def generate_data(factor=10): 
    rawdata = pd.DataFrame(np.random.rand(10,4)*factor, columns = ["A","B","C","D"]) 
    idx = pd.MultiIndex.from_product([["Exp "+str(i) for i in range(5)], 
           [20,999]],names=["Experiment","Threshold"]) 
    rawdata.index = idx 

    return rawdata.reset_index() 

# Generate data 
output_notebook() 
count_data = generate_data() 
error_data = generate_data(factor=2) 
groups = ["A","B","C","D"] 
initial_counts = count_data[(count_data.Experiment == "Exp 0") 
          & (count_data.Threshold == 20)][["A","B","C","D"]].values[0] 
initial_errors = error_data[(error_data.Experiment == "Exp 0") 
          & (error_data.Threshold == 20)][["A","B","C","D"]].values[0] 

# Create primary sources of data 
count_source = ColumnDataSource(data=count_data) 
error_source = ColumnDataSource(data=error_data) 

# Create plotting source of data 
source = ColumnDataSource(data=dict(groups=groups, counts=initial_counts, 
            upper=initial_counts+initial_errors, 
            lower=initial_counts-initial_errors)) 

# Bar chart and figure 
p = figure(x_range=groups, plot_height=350, toolbar_location=None, title="Values", y_range=(0,20)) 
p.vbar(x='groups', top='counts', width=0.9, source=source, legend="groups", 
     line_color='white', fill_color=factor_cmap('groups', palette=["#962980","#295f96","#29966c","#968529"], 
                factors=groups)) 
# Error bars 
p.add_layout(
    Whisker(source=source, base="groups", upper="upper", lower="lower", level="overlay") 
)  

exp_dropdown = Select(title="Select:", value="Exp 0", options=list(count_data.Experiment.unique()))  
thr_dropdown = Select(title="Select:", value="20", options=list(count_data.Threshold.astype(str).unique())) 

def callback(source=source, count_source = count_source, error_source=error_source, exp_dropdown = exp_dropdown, 
      thr_dropdown=thr_dropdown,window=None): 

    def slicer(data_source, experiment, threshold, dummy_col, columns): 
     """ Helper function to enable lookup of data.""" 
     count = 0 
     for row in data_source[dummy_col]: 
      if (data_source["Experiment"][count] == experiment) & (data_source["Threshold"][count] == threshold): 
       result = [data_source[col][count] for col in columns] 

      count+=1 

     return result 

    # Initialise data sources 
    data = source.data 
    count_data = count_source.data 
    error_data = error_source.data 

    # Initialise values 
    experiment = exp_dropdown.value 
    threshold = thr_dropdown.value 
    counts, upper, lower = data["counts"], data["upper"], data["lower"] 

    tempdata = slicer(count_data, experiment, threshold,"Experiment", ["A","B","C","D"]) 
    temperror = slicer(error_data, experiment, threshold,"Experiment", ["A","B","C","D"]) 

    # Select values and emit changes 
    for i in range(len(counts)): 
     counts[i] = tempdata[i] 

    for i in range(len(counts)): 
     upper[i] = counts[i]+temperror[i] 
     lower[i] = counts[i]-temperror[i] 

    source.change.emit() 


exp_dropdown.callback = CustomJS.from_py_func(callback) 
thr_dropdown.callback = CustomJS.from_py_func(callback) 

p.xgrid.grid_line_color = None 
p.legend.orientation = "horizontal" 
p.legend.location = "top_center" 

layout = column(exp_dropdown,thr_dropdown, p) 

show(layout) 
+0

こんにちは@Matt。私は上記のコードをテストしましたが、ドロップダウンメニューの値を変更するときにボックスプロットの更新を取得していないようです。ここでどんな素早い考え? – gussilago

+0

HI @ gussilago、はい、私はBokehの最新バージョンに更新するまでは機能しませんでした。どのバージョンを実行していますか? – Matt

関連する問題