Привет, Хабр! Хочу поделиться опытом в быстром создание интерфейса в Jupyter Notebook. Если у тебя есть какая-то задача, для которой нужен простой UI, и ты почему-то захотел сделать её в Юпитере, то добро пожаловать под кат.  Передо мной встала задача: реализовать наглядный интерфейс для машины Тьюринга. Наверное, самый простой вариант – реализовать это с помощью С# или Java для десктопа, а может даже на JS в браузере. Так как я занимаюсь датасаенсом и у меня юпитерголовногомозга – я решил делать с помощью Jupyter Widgets. На хабре я не нашел информации об этой технологии, нужно это исправлять. Пост подразумевает, что читатель уже знаком с языком Python и работал в Jupyter Notebook. Jupyter Widgets – это интерактивные HTML-виджеты для Jupyter Notebook. Их прямое назначение – сделать ноутбук более динамичным, добавить в него различные элементы управления. У нас появляется возможность добавлять слайдеры, кнопки, прогресс бары и другие элементы в несколько строчек без знаний CSS. Как я вижу, основное применение этой технологии – быстрая разработка прототипов (особенно для ML-проектов) в которых нужен простой UI. Если вам нужно показать заказчику что-то интерактивное, а не просто таблицу или график, то первое, что я бы попробовал, — это виджеты в юпитере (ну а потом plotly и Dash). Более повседневный вариант использования для датасаентистов — удобная отладка с помощью функции interact. Interact – наверное самая часто используемая функция этой библиотеки. Она создает слайдер и вызывает некоторую функцию (callback) при его изменении. Все это реализуется в одну строчку. Ему можно придумать массу полезных применений: например, можно смотреть, как ваша модель машинного обучения реагирует на изменение какого-то параметра или признака, просто двигая слайдер. Для примера я не стал импортировать xgboost, а просто построил график полинома, степень которого можно менять с помощью этого самого interact.  Машина Тьюринга – это расширение идеи конечного автомата, с помощью которого, теоретически, можно представить любой алгоритм. Она может быть формализована через алфавит, разрешенные состояния, входные символы, начальное состояние и функцию переходов. Основная часть машины — это лента с символами алфавита, которые последовательно обрабатываются движущейся влево и вправо считывающей головкой в соответствии с функцией переходов. Пусть машина сейчас в состоянии "q1" и прочитан символ "A". Проводится проверка функции переходов, и если есть комбинация "q1 A", то мы знаем, в какое следующее состояние должен осуществиться переход, какой символ записывается в текущую позицию на ленте, и куда дальше двигается считывающая головка. Если такой комбинации ("состояние-символ") нет, то работа машины завершается. Этих знаний должно быть достаточно, чтобы понять, что нужно отобразить в интерфейсе. Пример готового класса машины Тьюринга на питоне можно найти тут, я немного изменил его для своих нужд. Для наглядности, рассмотрим следующую задачу. Дан массив из букв "А" и "В". Нужно сжать массив, удалив все буквы "В", но оставив буквы "А". Решение состоит в замене всех символов "В" на символ "*", а затем разбросанные в разных позициях буквы "А" следует сдвинуть вправо. Пример входа: "#BAABABA#". Выход для него: "####AAAA#". Здесь "#" — служебный пустой символ. Функция переходов под спойлером. Прежде всего нужно понять, какие UI элементы должны отображаться. Строки с текстом можно представить с помощью класса ipywidgets.HTML. Это виджет для отображения html, работа с ним выглядит так: При изменение значения поля value, виджет автоматически перерисовывается. Три строки с текстом создадим с помощью трех разных html-виджетов. Кнопки генерации строки и выполнения команды делаются с помощью ipywidgets.Button. Слайдер представляется классом ipywidgets.IntSlider. Атрибутами можно передавать границы допустимых значений. Обработка событий от UI-элементов происходит с помощью колбеков: функций, которые вызываются при возникновении событий. В нашем случае для кнопок нужно подписаться на событие клика, а для слайдера — на событие изменения значения элемента. Внутри этих колбеков будет происходить изменение значений html-виджетов. Для отрисовки элементов можно передать их все в функцию display. Выводя все вместе, получим:  Все работает! На этом можно было бы остановиться, но согласитесь, выглядит довольно сумбурно. Попробуем это исправить. Соберем контролы в более привычном виде. Перед каждой html строкой добавим лейбл, кнопки разместим в одну линию, вокруг этого сделаем красивую рамочку. Это можно сделать с помощью ipywidgets.Layout и ipywidgets.Box. Box – это контейнер, в который можно добавлять несколько виджетов в виде списка. Управлять отображением элементов внутри бокса легко с помощью атрибута layout. Благодаря технологии Flexbox из современного CSS можно красиво расположить элементы относительно друг друга. Здесь можно найти множество примеров, на основе которых достаточно просто собрать что-то свое. В итоге у меня получилось так:  В этом посте мы познакомились с Jupyter Widgets на примере визуализатора для машины Тьюринга. Теперь вы сможете удивить заказчика добавить интерактивности в свои ноутбуки. Если вам не хватает функциональности существующих виджетов, вы можете создавать свои, но для этого необходимы хотя бы базовые знания JS. Единственный минус, с которым я столкнулся – виджеты пока не отображаются на github при просмотре ноутбуков (даже после Widgets -> Save Notebook Widget State). Надеюсь, скоро это пофиксят. Всем красивых и динамичных ноутбуков! PS: ссылка на github репозиторий Machine Learning