从Bokeh图中删除线条

7

我是Bokeh的新手。我制作了一个小部件,当我点击复选框时,我希望能够在Bokeh图中添加/删除一条线。我有20个这样的复选框,我不想重新绘制整个图形,只需在取消选中复选框时删除1条线。

这是通过回调完成的,我可以访问图形对象。我想象中应该有一种方法可以做到这一点:

F=figure()
F.line('x', 'y', source=source, name='line1')
F.line('x', 'z', source=source, name='line2')

%%in callback
selected_line_name = 'line1' # this would be determined by checkbox
selected_line = F.children[selected_line_name]
delete(selected_line)

然而,我无法弄清如何: 1)从父对象中访问字形 2)删除一个字形

我试过设置数据源“y” = [],但是由于所有列数据源必须具有相同的大小,因此这将删除所有绘图...

2个回答

9
这将有助于维护共享的“x”数据源列,如果将glyphs分配为变量并赋予名称属性。 remove函数使用NaN填充适当的“y”列,而restore函数用原始值替换NaN。
这些函数需要导入numpy和bokeh GlyphRenderer。我不确定在简单的可见/隐藏选项下是否值得采用此方法,但无论如何,我还是发布了它,以防在其他用例中有所帮助。
要删除或恢复的glyphs由包含在列表中的glyph名称引用。
src_dict = source.data.copy()

def remove_glyphs(figure, glyph_name_list):
    renderers = figure.select(dict(type=GlyphRenderer))
    for r in renderers:
        if r.name in glyph_name_list:
            col = r.glyph.y
            r.data_source.data[col] = [np.nan] * len(r.data_source.data[col])

def restore_glyphs(figure, src_dict, glyph_name_list):
    renderers = figure.select(dict(type=GlyphRenderer))
    for r in renderers:
        if r.name in glyph_name_list:
            col = r.glyph.y
            r.data_source.data[col] = src_dict[col]

例子:

from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models import Range1d, ColumnDataSource
from bokeh.models.renderers import GlyphRenderer

import numpy as np

output_notebook()

p = figure(plot_width=200, plot_height=150,
           x_range=Range1d(0, 6),
           y_range=Range1d(0, 10),
           toolbar_location=None)

source = ColumnDataSource(data=dict(x=[1, 3, 5],
                                    y1=[1, 1, 2],
                                    y2=[1, 2, 6],
                                    y3=[1, 3, 9]))

src_dict = source.data.copy()

line1 = p.line('x', 'y1',
               source=source,
               color='blue',
               name='g1',
               line_width=3)

line2 = p.line('x', 'y2',
               source=source,
               color='red',
               name='g2',
               line_width=3)

line3 = p.line('x', 'y3',
               source=source,
               color='green',
               name='g3',
               line_width=3)
print(source.data)
show(p)

输出:

{'x': [1, 3, 5], 'y1': [1, 1, 2], 'y2': [1, 2, 6], 'y3': [1, 3, 9]}

enter image description here

remove_glyphs(p, ['g1', 'g2'])
print(source.data)
show(p)

输出:

{'x': [1, 3, 5], 'y1': [nan, nan, nan], 'y2': [nan, nan, nan], 'y3': [1, 3, 9]}

enter image description here

restore_glyphs(p, src_dict, ['g1', 'g3'])
print(source.data)
show(p)

“g3”已经在图表上,不受影响。

输出:

{'x': [1, 3, 5], 'y1': [1, 1, 2], 'y2': [nan, nan, nan], 'y3': [1, 3, 9]}

enter image description here

restore_glyphs(p, src_dict, ['g2'])
print(source.data)
show(p)

输出:

{'x': [1, 3, 5], 'y1': [1, 1, 2], 'y2': [1, 2, 6], 'y3': [1, 3, 9]}

enter image description here


9
有几种方法:
# Keep the glyphs in a variable:
line2 = F.line('x', 'z', source=source, name='line2')

# or get the glyph from the Figure:
line2 = F.select_one({'name': 'line2'})

# in callback:
line2.visible = False

谢谢@Alex,这太棒了!有没有办法不仅隐藏行(我认为这会使其保留在内存中并减慢系统),而是完全删除它? - DankMasterDan
1
我猜测是这样的:F.renderers.remove(line2)(renderers 表现为一个列表,所以您可以像操作任何 Python 列表一样操作它),但我想优化很小,因为您的数据仍将存储在源中。这只会节省 Bokeh 不必解析该图形并检查其可见性。虽然我从未对其进行过分析,也不太熟悉内部情况,无法确定。如果您对其进行了分析,请告诉我们! - Alex
1
谢谢!有没有自动删除图表上所有线条或者重置它的方法? - DankMasterDan
1
没有这个功能。我们可以考虑为此添加API,但说实话,在那时创建一个新的图表可能同样简单和有效。 - bigreddot
@bigreddot 有没有一种简单的方法可以删除 Bokeh 绘图? - DankMasterDan
1
只需像从Python列表中删除任何对象一样,替换或从布局子项中删除它,例如:https://github.com/bokeh/bokeh/blob/master/examples/app/crossfilter/main.py#L59 - bigreddot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接