2017-10-09 98 views
0

我想创建一个带有滑块过滤器的散景中组合密度图的直方图。 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) 

回答

0

有两种方法来实现背景虚化回调:

  • 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()和最后一个未注释的两行)。
  • 在外部运行,注释笔记本行(参见上文)并取消注释最后两行。然后你可以从命令行运行它。所以你需要在转换(创建时)(使用值时:oldnew
  • Select将只处理str值和出
  • 多个过滤器,你需要在访问每个Select的状态同时。通过在定义update函数(但没有任何回调函数,然后!)之前实例化Select,并保留对它们的引用,通过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)) 
+0

感谢您很大的反响。为了正确理解你对多个裁判员的看法,因为这正是我现在想要实现的。我在更新之前定义了两个选择器,如下所示:select = select(title ='#cyl',value ='All',options = ['All'] + [str(i)for i in df.cyl.unique )])'和'select_2 = Select(title =“Car name”,value =“All”,options ['All'] + df.name.unique()'并且替换'condition = df.cyl == int(new)'line with'condition = df [df.cyl == select.val&df.name == select_2.val]' –

+0

增加了一个例子,我使用'origin'而不是'name'作为'name '几乎是独一无二的,所以一个kde在'name'过滤的df上没有任何意义。 – Alex