2017-09-26 52 views
0

我想在使用Python 3的Bokeh中使用带有回调的滑块来过滤我的ColumnDataSource对象(源自DataFrame)的行。更具体地说,如果一个选项为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与使回调本地(不是基于服务器)一个CustomJSFilter。您也可以使用CDSView编写其他回调函数,并使绘图完全独立于服务器。

+0

我走了你的第一个解决方案,它的工作很好。太感谢了! – ScottP

相关问题