带滑块滤镜的直方图

时间:2017-10-09 10:24:00

标签: python bokeh

我想创建一个直方图,其中密度图在散景图中与滑块滤镜相结合。 Atm,我有块来创建一个散景直方图,其中包含来自另一个线程的密度图。我不知道如何创建回调函数来更新数据并重新渲染绘图。

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.sampledata.autompg import autompg as df

from numpy import histogram, linspace
from scipy.stats.kde import gaussian_kde

pdf = gaussian_kde(df.hp)

x = linspace(0,250,50)

p = figure(plot_height=300)
p.line(x, pdf(x))

# plot actual hist for comparison
hist, edges = histogram(df.hp, density=True, bins=20)
p.quad(top=hist, bottom=0, left=edges[:-1], right=edges[1:], alpha=0.4)

show(p)

1 个答案:

答案 0 :(得分:1)

在Bokeh中有两种实现回调的方法:

  • JS code。在这种情况下,绘图仍然是一个独立的对象,你需要在Javascript中进行任何数据操作的约束(这个声明有一个小警告,但在这里不相关:scipy无法从这样的调用回调)
  • 通过在Bokeh server中执行回调,在这种情况下,您可以使用完整的python库。成本是,绘制和分发图表比在第一种情况下要多一些(但这并不困难,参见示例)。

考虑到每次更改过滤条件时都需要重新设置kde,第二种方式是唯一的选择(除非您想在javascript中执行此操作...)。

你就是这样做的(例如在cyl上使用过滤器):

from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
from bokeh.io import output_notebook, show
from bokeh.layouts import column
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, Select
from bokeh.sampledata.autompg import autompg as df

from numpy import histogram, linspace
from scipy.stats.kde import gaussian_kde

output_notebook()

def modify_doc(doc):
    x = linspace(0,250,50)

    source_hist = ColumnDataSource({'top': [], 'left': [], 'right': []})
    source_kde = ColumnDataSource({'x': [], 'y': []})

    p = figure(plot_height=300)
    p.line(x='x', y='y', source=source_kde)
    p.quad(top='top', bottom=0, left='left', right='right', alpha=0.4, source=source_hist)

    def update(attr, old, new):
        if new == 'All':
            filtered_df = df
        else:
            condition = df.cyl == int(new)
            filtered_df = df[condition]

        hist, edges = histogram(filtered_df.hp, density=True, bins=20)
        pdf = gaussian_kde(filtered_df.hp)

        source_hist.data = {'top': hist, 'left': edges[:-1], 'right': edges[1:]}
        source_kde.data = {'x': x, 'y': pdf(x)}

    update(None, None, 'All')

    select = Select(title='# cyl', value='All', options=['All'] + [str(i) for i in df.cyl.unique()])
    select.on_change('value', update)
    doc.add_root(column(select, p))

# To run it in the notebook:
plot = Application(FunctionHandler(modify_doc))
show(plot)

# Or to run it stand-alone with `bokeh serve --show myapp.py`
# in which case you need to remove the `output_notebook()` call
# from bokeh.io import curdoc
# modify_doc(curdoc())

一些注意事项:

  • 这是在jupyter笔记本中运行的(参见output_notebook()和最后一条未注释的两行)。
  • 在外面运行,评论笔记本行(见上文)并取消注释最后两行。然后,您可以从命令行运行它。
  • Select只会处理str个值,因此您需要转换(创建时)和输出(使用值时:oldnew
  • 对于多个过滤器,您需要同时访问每个Select的状态。你可以通过在定义Select函数之前实例化update来做到这一点(但没有任何回调,但是!)并保持对它们的引用,使用your_ref.value访问它们的值并构建条件接着就,随即。在update定义之后,您可以在每个Select上附加回调。

最后,一个有多个选择的例子:

def modify_doc(doc):
    x = linspace(0,250,50)

    source_hist = ColumnDataSource({'top': [], 'left': [], 'right': []})
    source_kde = ColumnDataSource({'x': [], 'y': []})

    p = figure(plot_height=300)
    p.line(x='x', y='y', source=source_kde)
    p.quad(top='top', bottom=0, left='left', right='right', alpha=0.4, source=source_hist)
    select_cyl = Select(title='# cyl', value='All', options=['All'] + [str(i) for i in df.cyl.unique()])
    select_ori = Select(title='origin', value='All', options=['All'] + [str(i) for i in df.origin.unique()])

    def update(attr, old, new):
        all = pd.Series(True, index=df.index)
        if select_cyl.value == 'All':
            cond_cyl = all
        else:
            cond_cyl = df.cyl == int(select_cyl.value)
        if select_ori.value == 'All':
            cond_ori = all
        else:
            cond_ori = df.origin == int(select_ori.value)
        filtered_df = df[cond_cyl & cond_ori]

        hist, edges = histogram(filtered_df.hp, density=True, bins=20)
        pdf = gaussian_kde(filtered_df.hp)

        source_hist.data = {'top': hist, 'left': edges[:-1], 'right': edges[1:]}
        source_kde.data = {'x': x, 'y': pdf(x)}

    update(None, None, 'All')

    select_ori.on_change('value', update)
    select_cyl.on_change('value', update)

    doc.add_root(column(select_ori, select_cyl, p))