函数 returns NdOverlay 到 DynamicMap 时的奇怪行为

Strange behaviour when function returns NdOverlay to DynamicMap

当我有一个生成指向 DynamicMap 的点的 NdOverlay 的函数时,我遇到了一些非常奇怪的事情,其中​​该函数与面板小部件相关联(我认为面板小部件不重要)。

下面的代码是产生预期行为的工作示例。每当您更改小部件值时,都会生成一个新图,其中有两组重叠的点,具有不同的颜色和各自的图例条目。图片显示在代码下方。

a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
b_widget = pn.widgets.IntSlider(name='B', start=10, end=20, value=10)
widget_box = pn.WidgetBox(a_widget, b_widget, align='center')

@pn.depends(a=a_widget.param.value, b=b_widget.param.value)
def get_points(a, b):
    return hv.NdOverlay({x: hv.Points(np.random.rand(10,10)) for x in range(1,3)})

points = hv.DynamicMap(get_points)

pn.Row(widget_box, points)

下面显示的第二个示例旨在说明在某些情况下您可能只想 return 一个空图,而我在这个示例中所做的方式与此相同如本例所示:http://holoviews.org/gallery/demos/bokeh/box_draw_roi_editor.html#bokeh-gallery-box-draw-roi-editora == 1 时,此代码的结果是一个空图,但当 a 的值不是 1 时,结果非常奇怪,如代码下方的图像所示。

  1. 所有的点都具有相同的颜色
  2. 例如,当改变滑块时,一些点被冻结并且永远不会改变,这在上面的工作示例中不是这种情况。
a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
b_widget = pn.widgets.IntSlider(name='B', start=10, end=20, value=10)
widget_box = pn.WidgetBox(a_widget, b_widget, align='center')

@pn.depends(a=a_widget.param.value, b=b_widget.param.value)
def get_points(a, b):
    if a == 1:
        return hv.NdOverlay({None: hv.Points([])})
    else:
        return hv.NdOverlay({x: hv.Points(np.random.rand(10,10)) for x in range(1,3)})

points = hv.DynamicMap(get_points)

pn.Row(widget_box, points)

虽然我无法用 NdOverlay 解决观察到的问题,但可以在 Overlay.

的帮助下创建有或没有内容的图

由于您的代码中从未使用过 b_widget,为简单起见,我删除了它。

a_widget = pn.widgets.Select(name='A', options=[1,2,3,4])
widget_box = pn.WidgetBox(a_widget, align='center')

@pn.depends(a=a_widget.param.value)
def get_points(a):
    images = []
    if a == 3:
        images.append(hv.Points(np.random.rand(10,10), label='None'))
    else:
        for x in range(1,3):
            images.append(hv.Points(np.random.rand(10,10), label=str(x)))
    return hv.Overlay(images)

points = hv.DynamicMap(get_points)

pn.Row(widget_box, points)

documentation for NdOverlay中描述的 NdOverlay 的使用方式与您的方法不同,这可能是观察到的问题的原因。


无论如何,为了缩小代码的哪一部分对观察到的问题负责,我删除了所有不需要重现它的代码。

为清楚起见,我重命名了 a 的值,并且我还确保提供了 a 的起始值。

在测试代码时发现 if-else 语句并不重要,所以我也删除了它。

为了确保变量的行为符合预期,我添加了一些 print 语句。

这给出了以下最小可重现示例:

a_widget = pn.widgets.Select(name='A', value='Test', options=['Test','Test1', 'Test2'])

@pn.depends(a=a_widget.param.value)
def get_points(a):
    dict_ = {}
    dict_[str(a)] = hv.Points(np.random.rand(10,10))

    print(dict_)
    overlay = hv.NdOverlay(dict_)
    print(overlay)

    return overlay

points = hv.DynamicMap(get_points)

# using the server approach here to see the outpout of the
# print-statements
app = pn.Row(a_widget, points)
app.app() 

当 运行 这段代码,并在 select 小部件中选择不同的选项时,事实证明选项 Test 没有更新,一旦其中一个选项 Test1Test3 已被选中。

当我们像这样更改第一行中的默认值时

a_widget = pn.widgets.Select(name='A', value='Test2', options=['Test','Test1', 'Test2'])

现在 Test2 没有正确更新。

所以看起来这是 DynamicMap 使用 NdOverlay 的问题。 因此,我建议您向开发人员报告此问题(如果尚未完成),等待新版本发布或使用不同的方法(例如,如上所示)。