函数 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-editor
当 a == 1
时,此代码的结果是一个空图,但当 a
的值不是 1
时,结果非常奇怪,如代码下方的图像所示。
- 所有的点都具有相同的颜色
- 例如,当改变滑块时,一些点被冻结并且永远不会改变,这在上面的工作示例中不是这种情况。
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
没有更新,一旦其中一个选项 Test1
和 Test3
已被选中。
当我们像这样更改第一行中的默认值时
a_widget = pn.widgets.Select(name='A', value='Test2', options=['Test','Test1', 'Test2'])
现在 Test2
没有正确更新。
所以看起来这是 DynamicMap
使用 NdOverlay
的问题。
因此,我建议您向开发人员报告此问题(如果尚未完成),等待新版本发布或使用不同的方法(例如,如上所示)。
当我有一个生成指向 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-editor
当 a == 1
时,此代码的结果是一个空图,但当 a
的值不是 1
时,结果非常奇怪,如代码下方的图像所示。
- 所有的点都具有相同的颜色
- 例如,当改变滑块时,一些点被冻结并且永远不会改变,这在上面的工作示例中不是这种情况。
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
没有更新,一旦其中一个选项 Test1
和 Test3
已被选中。
当我们像这样更改第一行中的默认值时
a_widget = pn.widgets.Select(name='A', value='Test2', options=['Test','Test1', 'Test2'])
现在 Test2
没有正确更新。
所以看起来这是 DynamicMap
使用 NdOverlay
的问题。
因此,我建议您向开发人员报告此问题(如果尚未完成),等待新版本发布或使用不同的方法(例如,如上所示)。