在 Jupyter Notebook 中渲染后将字形添加到散景图

Add glyphs to a bokeh plot after it is rendered in the Jupyter Notebook

我正在尝试在 Jupyter Notebook 中创建一个仪表板,其中包含交互式散景图和 ipywidgets 作为控制图的小部件。我的用例有点复杂,因为我想创建一个带有不同标记的图,这些标记在散点图中指定不同的组,并且我想让用户能够更改组的划分(从而更改显示在情节)。

我考虑过两种不同的方法:

  1. 使用散景图API生成不同标记的散点图。除非我弄错了,这将不允许我更新情节,而是我将不得不根据用户的每一次更改重新创建它。

  2. 使用 bokeh.plotting API 自己创建情节。为此,我必须自己将数据分成几组,并分别为每组标记更新数据的坐标。

我已经开始尝试第二个选项,因为我想尝试自己更新情节而不是重新创建情节。我创建了一个简单的例子,它已经给我带来了一些问题。这是代码:

p = figure()
s = widgets.Dropdown(options=['circle', 'square'])

x = np.random.normal(size=10)
y = np.random.normal(size=10)

data = ColumnDataSource(dict(x=x, y=y))

r = p.scatter(source=data, x='x', y='y', size=14)

def select_value(change):
    renderers = [x for x in p.renderers if x.__view_model__ == "GlyphRenderer"]
    for r in renderers:
        p.renderers.remove(r)
    if change['new'] == 'circle':
        r = p.circle(x, y, size=14)
    else:
        r = p.square(x, y, size=14)
    push_notebook()


s.observe(select_value, 'value')
display(s)
show(p, notebook_handle=True)

这个代码块已经不能正常工作了。当我从小部件 select a 'square' 时,圆圈被删除,但只在绘图中间添加一个正方形,而不是在圆圈的先前位置。我尝试使用产生相同结果的 p.add_glyph 函数,并确保正方形的数据源与圆圈的数据源相同(确实如此)。

如有任何帮助,我们将不胜感激! 干杯, 暗利

首先,我无法让 widgets.Dropdownoptions 一起工作,我使用了 bokeh.models.widgets.Select。它可能是散景版本,我使用的是 0.12.4 版本。 其次,在 select_value 更新函数中,我添加字形,使用 bokeh.io.push_notebook(),然后删除原始渲染器,然后再次 bokeh.io.push_notebook()

在我的其中一个单元格中:

import bokeh
import bokeh.plotting
import numpy as np
from ipywidgets import interact
bokeh.io.output_notebook()

p = bokeh.plotting.figure()
s = bokeh.models.widgets.Select(options=['circle', 'square'])

x = np.random.normal(size=10)
y = np.random.normal(size=10)

source = bokeh.models.ColumnDataSource(dict(x=x, y=y))

scatter_plot = p.scatter(source=source, x='x', y='y',color="blue",marker="circle", size=14)

def select_value(change):
    renderers = [x for x in p.renderers if x.__view_model__ == "GlyphRenderer"]
    for r in renderers:
        if change == 'circle':
            myglyph = bokeh.models.Circle(x="x",y="y",fill_color="blue", line_color="blue",size=14)
        elif change == 'square':
            myglyph = bokeh.models.Square(x="x",y="y",fill_color="blue", line_color="blue",size=14)
        r.glyph = myglyph
        p.add_glyph(source,myglyph)
        bokeh.io.push_notebook()
        p.renderers.remove(r)
        bokeh.io.push_notebook()

bokeh.io.show(p, notebook_handle=True)

创建图形:

在另一个单元格中我有:

interact(select_value,change=['circle', 'square']);

创建交互工具:

更新

另一种方法是使用 visible 参数。你创建所有你想要的标记类型,然后你让你的选择可见,而其他的不可见:

import bokeh
import bokeh.plotting
import numpy as np
from ipywidgets import interact
bokeh.io.output_notebook()

p = bokeh.plotting.figure()
s = bokeh.models.widgets.Select(options=['circle', 'square'])

x = np.random.normal(size=10)
y = np.random.normal(size=10)

source = bokeh.models.ColumnDataSource(dict(x=x, y=y))

scatter_circle = p.scatter(source=source, x='x', y='y',color="blue", marker='circle', size=14)
scatter_square = p.scatter(source=source, x='x', y='y',color="blue", marker='square', size=14)
scatter_square.visible=False
handle = bokeh.io.show(p, notebook_handle=True)

def select_value(change):
    if change == 'circle':
        scatter_circle.visible=True
        scatter_square.visible=False
    elif change == 'square':
        scatter_square.visible=True
        scatter_circle.visible=False

    bokeh.io.push_notebook(handle=handle)