Странное поведение, когда функция возвращает NdOverlay в DynamicMap

Я столкнулся с чем-то очень странным, когда имел функцию, которая генерирует NdOverlay точек для DynamicMap, где функция привязана к виджетам панели (я не думаю, что виджеты панели важны).

Приведенный ниже код является рабочим примером, который дает ожидаемое поведение. Каждый раз, когда вы меняете значения виджета, создается новый график с наложенными двумя наборами точек, с разными цветами и соответствующими записями легенды. Изображение показано под кодом.

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)

image

Второй пример, показанный ниже, предназначен для демонстрации того, что в определенных ситуациях вам может потребоваться просто вернуть пустой график, и то, как я сделал это в этом примере, выполняется так же, как в этом примере: http://holoviews.org/gallery/demos/bokeh/box_draw_roi_editor.html#bokeh-gallery-box-draw-roi-editor Результатом этого кода является пустой график, как и ожидалось, когда a == 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)

image


person Martin Rindarøy    schedule 29.11.2019    source источник
comment
Привет, Мартин, наверное, лучше всего разместить ссылку на ваш SO-вопрос здесь: gitter.im/pyviz/pyviz так что разработчики holoviews могут помочь вам с этим (и другими вопросами)   -  person Sander van den Oord    schedule 29.11.2019
comment
Привет. Спасибо за совет. Я вошел в комнату и попросил помощи :)   -  person Martin Rindarøy    schedule 29.11.2019


Ответы (1)


Хотя я не могу помочь с наблюдаемой проблемой с 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)

Способ использования NdOverlay, описанный в документации для NdOverlay, отличается с учетом вашего подхода, это может быть причиной наблюдаемых проблем.


В любом случае, чтобы сузить, какая часть кода отвечает за наблюдаемую проблему, я удалил весь код, который не нужен для ее воспроизведения.

Для ясности я переименовал значения a, а также убедился, что задано начальное значение для a.

При тестировании кода выяснилось, что оператор _7 _-_ 8_ не важен, поэтому я его тоже удалил.

И чтобы убедиться, что переменные ведут себя так, как ожидалось, я добавил несколько 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() 

При запуске этого кода и выборе различных параметров в виджете выбора оказывается, что параметр Test не обновляется после выбора одного из параметров Test1 и Test3.

Когда мы меняем значение по умолчанию в первой строке следующим образом

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

теперь Test2 некорректно обновляется.

Похоже, это проблема DynamicMap при использовании NdOverlay. Поэтому я предлагаю вам сообщить об этой проблеме разработчикам (если это еще не сделано), либо дождаться новой версии, либо использовать другой подход (например, как показано выше).

person mdk    schedule 05.12.2019
comment
b_widget используется ... (?) Тем не менее, мой пример сильно напоминает пример на holoviews.org, на который я ссылаюсь в вопросе. - person Martin Rindarøy; 06.12.2019
comment
@ Мартин Риндарёй: Я обновил свой ответ. Теперь он содержит часть, основанную на вашем коде и связанном примере. - person mdk; 09.12.2019