如何使用Python 3在Bokeh中使用滑块回调过滤ColumnDataSource? [英] How to use a slider callback to filter a ColumnDataSource in Bokeh using Python 3?

查看:190
本文介绍了如何使用Python 3在Bokeh中使用滑块回调过滤ColumnDataSource?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在Bokeh中使用带有回调的滑块使用Python 3来过滤ColumnDataSource对象(源自DataFrame)的行.更具体地说,如果滑块的选项为0到10000000(以100万的倍数)返回的值N例如2000000,那么我希望我的绘图仅显示人口总数为US的县的数据>>2000000.下面是我的代码.一切都按我希望的方式进行,除了滑块回调.

I'm trying to use a slider with a callback in Bokeh using Python 3 to filter the rows of my ColumnDataSource objects (which originate from a DataFrame). More specifically, if a slider with options of 0 to 10000000 (in multiples of 1 million) returns a value N of say 2000000, then I want my plot to only show the data for, in this case, US counties where the population is >= 2000000. Below is my code. Everything works as I want it to except for the slider callback.

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)

推荐答案

对代码进行最少更改的快速解决方案是:

A quick solution with minimal change to your code would be:

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列中创建字典:

When updating data sources, you should replace the data, not the whole object. Here I still create new ColumnDataSource as shortcut. A more direct way (but more verbose too) would be to create the dictionary from the filtered df's columns:

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

请注意,还有另一种解决方案,可以使用 CustomJSFilter .您还可以使用CDSView编写其他回调,并使绘图完全独立于服务器.

Note that there's another solution which would make the callback local (not server based) by using a CDSView with a CustomJSFilter. You can also write the other callback with a CDSView as well make the plot completely server-independent.

这篇关于如何使用Python 3在Bokeh中使用滑块回调过滤ColumnDataSource?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆