如何加快bokeh中Select / MultiSelect小部件的更新?

时间:2019-06-27 09:21:34

标签: python bokeh

我对bokeh很陌生,并试图通过Select和MultiSelect小部件与我绘制的数据进行交互。我注意到,当为这些小部件的options参数提供一长串(> 34k项)时,性能会大大降低。从我看到的内容来看,Select仅充当mylist[mylist.index('selected_value')],而MultiSelect充当selected_vals.append(mylist[mylist.index('selected_value')]),因此,如果确实如此,我不明白为什么小部件返回值如此之慢,因为python可以轻松处理这些操作具有任意长度的列表。尽管我正在使用多维大型数据集,但是我确定加载的数据并没有真正起作用,因为我已经尝试将绘图更新与小部件解耦,并且仅打印从下拉菜单中选择的返回值(这可能会占用到30秒,甚至仅打开菜单也要花费几秒钟)。我尝试缩短传递给options参数的列表(不更改已加载数据的大小),并且小部件的行为符合预期。是否有解决方法/修复程序? 这里的一些代码

import numpy as np
import pandas as pd
from bokeh.layouts import row, column
from bokeh.models import Select, MultiSelect, ColumnDataSource, CDSView, GroupFilter
from bokeh.palettes import Viridis256
from bokeh.plotting import curdoc, figure
from bokeh.transform import log_cmap

data = np.random.rand(11000, 3)
normExpr = np.random.rand(11000, 35000)
gene_names = np.array(np.random.rand(35000), dtype='str')
clusters = list(np.array(range(20), dtype='str'))
normExpr = pd.DataFrame(normExpr, columns=gene_names)
data = pd.DataFrame(data, columns=['PHATE1', 'PHATE2', 'color'])
data['cluster'] = clusters*550
COLORS = Viridis256[::-1]
columns = list(gene_names)[:20]

def first_fig():
    s = slice(len(data['color']))
    source = ColumnDataSource(data)
    kw = dict()
    kw['title'] = "Expression of gene %s in %s" % (gene.value.title(), cluster.value.title())
    p = figure(plot_height=500, plot_width=550, tools='pan,box_zoom,hover,reset',
               toolbar_location="above", output_backend='webgl', **kw)
    p.background_fill_color="#fafafa"
    p.xaxis.axis_label = 'X-values'
    p.yaxis.axis_label = 'Y-values'
    if gene.value != 'None' and cluster.value != 'All tissue':
        view = CDSView(source=source, filters=[GroupFilter(column_name='cluster', group=cluster.value)])
        new = normExpr[gene.value]
        source.patch({'color': [(s, new)]})
        p.circle(x='PHATE1', y='PHATE2', source=source, view=view, radius=0.002, color=log_cmap('color', COLORS, 0, 1),
                 hover_color='white', hover_alpha=0.5)

    elif gene.value == 'None' and cluster.value != 'All tissue':
        view = CDSView(source=source, filters=[GroupFilter(column_name='cluster', group=cluster.value)])
        p.circle(x='PHATE1', y='PHATE2', source=source, view=view, radius=0.002, color="#31AADE",
                 hover_color='white', hover_alpha=0.5)
    elif gene.value != 'None' and cluster.value == 'All tissue':
        new = normExpr[gene.value]
        source.patch({'color': [(s, new)]})
        p.circle(x='PHATE1', y='PHATE2', source=source, radius=0.002, color=log_cmap('color', COLORS, 0, 1),
                 hover_color='white', hover_alpha=0.5)

    else:
        p.circle(x='PHATE1', y='PHATE2', source=source, radius=0.002, color='#31AADE',
                 hover_color='white', hover_alpha=0.5)
    return p


def update(attr, old, new):
    layout.children[1] = first_fig()


cluster = Select(title='Cluster', value='All tissue', options=['All tissue'] + clusters)
cluster.on_change('value', update)
gene = Select(title='Gene', value='None', options=['None'] + columns)
gene.on_change('value', update)


controls = column([cluster, gene], width=100)
layout = row(controls, first_fig())

curdoc().add_root(layout)
curdoc().title = "Gene mapping"

2 个答案:

答案 0 :(得分:0)

  • 首先,应该强调的是,对于每个新连接,此代码都将完全执行。特别是,顶部的第一个“数据设置”代码块需要近5秒钟才能在笔记本电脑上执行。散景不是魔术,它不能使真正的CPU工作花费的时间少于花费的时间。但是,如果可以在会话之间共享此数据(最好是只读),则可以使用Lifecycle Hooks确保仅在服务器启动后一次进行此初始化。您可以看到此技术in this example

  • 的具体用法
  • 接下来,值得一提的是始终建议的最佳常规做法:

      

    在更新中总是尽可能少地更改

    一个相关的结论是:

      

    先建好图和布局,先,然后再更改数据

    这是因为Bokeh经过高度优化,可以处理对数据的更新(对ColumnDataSource中的列或现有对象的属性值)。当像在update函数中一样“从头开始”重新创建所有内容时,这是使用Bokeh的极其无效的方法。换句话说,应用程序的总体轮廓总是最好的,例如:

    p = figure(...)
    
    view = GroupFilter(...)
    source = ColumnDataSource(...)
    
    # create all the glyphs you will *ever* need up front
    # can set unused ones .visible = False
    
    select = Select(...)
    
    def update(attr, old, new):
        # Update existing source or view here, toggle .visible on glyphs, etc
        # But don't make new objects
    
    curdoc().add_root(column(plot, select)
    
  • 最后,首先尝试关闭WebGL。它目前没有维护人员,并且存在一些问题。 11k点通常应在标准Bokeh画布渲染范围内,除非可能存在很多重叠和Alpha合成。在这种情况下,您可能要考虑可以Holoviews一起驱动Bokeh和Datashader的情况。

不幸的是,根据这些准则,我无法参与整个示例的重写,但是希望它们能为您指明正确的方向。

答案 1 :(得分:0)

看来,仅在使用Microsoft Edge时,该问题才会出现。我将浏览器更改为Chrome,脚本运行正常。使用Edge时,仍然无法解释性能对选择小部件提供的选项列表长度的依赖性。