2017-09-26 9 views
0

私はPython 3を使用してBokehでコールバックを持つスライダを使用して、(DataFrameからの)ColumnDataSourceオブジェクトの行をフィルタリングしようとしています。具体的には、0〜10000000(100万の倍数)のオプションを持つスライダが、たとえば、2000000という値のNを返した場合、私のプロットは、この場合、集団が> = 2000000。以下は私のコードです。スライダのコールバックを除いて、すべての機能が動作します。あなたのコードに最小限の変更でスライダーコールバックを使用してPython 3を使用してBokehのColumnDataSourceをフィルターする方法は?

from bokeh.io import curdoc 
from bokeh.layouts import layout 
from bokeh.models import HoverTool, ColumnDataSource, Select, Slider 
from bokeh.plotting import figure 

TOOLS='pan,wheel_zoom,box_zoom,reset,tap,save,box_select,lasso_select' 

source1 = ColumnDataSource(df[df.winner == 'Democratic']) 
source2 = ColumnDataSource(df[df.winner == 'Republican']) 

hover = HoverTool(
     tooltips = [ 
      ('County Name', '@county'), 
      ('Population', '@population'), 
      ('Land Area', '@land_area'), 
      ('Pop. Density', '@density'), 
      ('Winning Party', '@winner'), 
      ('Winning Vote %', '@winning_vote_pct'), 
      ] 
     ) 

# Plot 
plot = figure(plot_width=800, plot_height=450, tools=[hover, TOOLS], 
      title='2016 US Presidential Vote % vs. Population Density (by County)', 
      x_axis_label='Vote %', y_axis_label='Population Density (K/sq. mi.)') 

y = 'density' 
size = 'bokeh_size' 
alpha = 0.5 

c1 = plot.circle(x='pct_d', y=y, size=size, alpha=alpha, color='blue', 
      legend='Democratic-Won County', source=source1) 
c2 = plot.circle(x='pct_r', y=y, size=size, alpha=alpha, color='red', 
      legend='Republican-Won County', source=source2) 

plot.legend.location = 'top_left' 

# Select widget 
party_options = ['Show both parties', 'Democratic-won only', 'Republican-won only'] 
menu = Select(options=party_options, value='Show both parties') 

# Slider widget 
N = 2000000 
slider = Slider(start=0, end=10000000, step=1000000, value=N, title='Population Cutoff') 

# Select callback 
def select_callback(attr, old, new): 
    if menu.value == 'Democratic-won only': c1.visible=True; c2.visible=False 
    elif menu.value == 'Republican-won only': c1.visible=False; c2.visible=True 
    elif menu.value == 'Show both parties': c1.visible=True; c2.visible=True 
menu.on_change('value', select_callback) 

# Slider callback 
def slider_callback(attr, old, new): 
    N = slider.value 
    # NEED HELP HERE... 
    source1 = ColumnDataSource(df.loc[(df.winner == 'Democratic') & (df.population >= N)]) 
    source2 = ColumnDataSource(df.loc[(df.winner == 'Republican') & (df.population >= N)]) 
slider.on_change('value', slider_callback) 

# Arrange plots and widgets in layouts 
layout = layout([menu, slider], 
       [plot]) 

curdoc().add_root(layout) 

答えて

2

迅速な解決策は次のようになります。

def slider_callback(attr, old, new): 
    N = new # this works also with slider.value but new is more explicit 
    new1 = ColumnDataSource(df.loc[(df.winner == 'Democratic') & (df.population >= N)]) 
    new2 = ColumnDataSource(df.loc[(df.winner == 'Republican') & (df.population >= N)]) 
    source1.data = new1.data 
    source2.data = new2.data 

データソースを更新するとき、あなたはデータではなく、オブジェクト全体を交換する必要があります。私はまだショートカットとして新しいColumnDataSourceを作成します。より直接的な方法(しかし、あまりにも多くの冗長)フィルタ処理されたDFの列から辞書を作成するには、次のようになります(ないサーバーベースの)コールバックはローカルになるだろう、別の解決策があることを

new1 = { 
     'winner': filtered_df.winner.values, 
     'pct_d': filtered_df.pct_d.values, 
     ... 
    } 
    new2 = {...} 
    source1.data = new1 
    source2.data = new2 

注意してCDSViewを使用して、 a CustomJSFilter。また、他のコールバックをCDSViewで作成し、プロットをサーバーに完全に依存させないようにすることもできます。

+0

私はあなたの最初の解決策と一緒に行きました。これは美しく機能します。感謝万円! – ScottP

関連する問題