13 June 2020

Юпитер и интерактивность - кнопки

Одна из прелестей Юпитера - возможность интерактивности.
Например можно использовать @interact и перерисовывать графики.
Хороший пример можно посмотреть тут Интерактивность в Jupyter Notebook

Однако если использовать перерисовку непостредственно по слайдеру, то это более тормознуто - график моргает при перемещении движка. Причем он может делать это с запаздыванием. Поэтому я стал смотреть возможности использования кнопок.
В самом деле - мне удобнее подвигать движки и потом, нажав кнопку, получить результат. Пример кнопок есть тут How to create buttons in Jupyter

Получилось это у меня не стразу - то при нажатии ничего не рисовалось, то наоборот рисовалось одно за другим - т.е. новый график просто добавлялся, что было неудобно.
Поэтому пришлось сделать пример и разобраться как оно работает

Для начала экспортируем то, что потребуется

import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import interact
import ipywidgets as widgets
from IPython.display import clear_output


Далее создаем два слайдера и кнопку

button = widgets.Button(description='My Button')

sF = widgets.FloatSlider(
         value=1,
         min=0,
         max=10.0,
         step=0.1,)
sPhase = widgets.FloatSlider(
         value=1,
         min=0,
         max=10.0,
         step=0.1,)

Далее мне хотелось это вертикально разместить одно за другим - через  VBox.
Однако, если результат записать в переменную вот так:

box = widgets.VBox([sF, sPhase, button ])

То ничего мы не увидим пока явно не выведем эту переменную например так


Но можно сделать проще - не записывать это в переменную, вот так:

widgets.VBox([sF, sPhase, button ])


Тогда это сразу отобразится.
Теперь настало время добавить функцию-обработчик, чтобы получить значения и напечатать их. Для доступа к значению у слайдера используется свойство value, причем поскольку создали мы его выше, то сначала внутри функции надо их объявить как глобальные, чтобы иметь доступ именно к созданным ранее



После запуска данной строки создается и два слайдера и кнопка и при нажатии кнопки печатается Clicked плюс значения слайдеров.
Все работает, но есть один ньюанс - при каждом нажатии печатаеся новая строка. Ровно тоже самое будет с графиками - они начнут плодиться, что неудобно.
Для очистки надо воспользоваться объектом widgets.Output() и обрамить функцию для его использования, используя конструкцию with



При запуске этого кода мы получим элемены управления но ... ничего происходить не будет.
Т.е. при нажатии кнопки мы вообще ничего не увидим. Поэтому строкой ниже можно просто вывести созданный Output() - вот там все и будет отображаться



Теперь все заработало как надо - строка обновляется и не рисуется еще одна.
Ровно то же можно использовать для графиков.
На понимание этого у меня ушло пару недель "шаманства" - понял я это не сразу.

No comments:

Post a Comment