![image](https://habrastorage.org/webt/m-/ve/xo/m-vexoavymihgw_xub0l_ndeobe.jpeg)
Как очевидно из заголовка, речь пойдет о библиотеке Panel, которая позволяет конвертировать Jupyter блокноты в безопасные веб приложения, где начинка скрыта от нетехнических пользователей, но остается свобода манипулирования внутренними параметрами, то есть не просто перестраивать данные, но и делать запросы в кернел. TL;DR Shiny for Python.
Одна из главных проблем бизнес аналитики состоит в том, что какой бы классной она ни была,
она часто не доходит до пользователя, принимающего на ее основе решения. IBM CTO of AI and data science говорит что только 13% проектов в области науки о данных доходят до продакшена и одна из главных причин — затрудненное сотрудничество всех участвующих в проектах. Сократив разрыв между датасатанистом, программистом деплоящим проект и аналитиком предметной области можно существенно повысить общий выхлоп, сократить сроки и сделать конечный продукт более продуманным.
Именно эту проблему решают несколько имеющихся сейчас в данной нише продуктов.
Для хорошего, маштабируемого деплоя есть Dash. В моем прошлом посте я делал небольшую
иллюстрацию на примере анализа рынка подержанных машин. За достоинства Даша нужно платить цену в виде того, что это отдельный апп который надо отдельно писать, из графики поддерживается Plotly, нужно дизайнить интерфейс, подкрутить немного CSS/HTML и при обновлении модели анализа если она в блокнотах — нужно поддерживать два кода, в целом не очень удобно пока проект в стадии развития.
С другого конца проблему решают Voila и Panel ( Voila нужно лихо, по-Д'Артаньяновски голосом Боярского произносить: «Вуаля!»). Voila идет от блокнота и поддерживает Jupyter interactive widgets с помощью которых может из вэб приложения общаться с кернелом, причем независимо от его языка (создатели говорят про независимость от языков, но для R не актуально у них есть Shiny, а на Julia бизнес аналитики не бывает). Вуаля позволяет делать интерактивный апп в два клика (не считая внедрения, например, ipywidgets, там кликов надо порядочно). Panel это решение сугубо для питона и идет к той же проблеме с другой стороны — от сервера, при этом собтвенно блокнот и Jupyter — опциональны. Модель можно сохранить в обычный питоновый файл и сервер не будет требовать всей Jupyter экосистемы. Panel не заточена под конкретную библиотеку для графики (примеры даются на matplotlib, bokeh, altair и plotly).
Оба варианта — Panel и Voila не оптимальны для иcпользования в качестве нагруженных приложений, но они для этого и не предназначены, идея в том чтобы сделать анализ, запилить дашборд с результатами, кинуть ссылку аналитику/менеджеру дать им поиграться с параметрами и запросами, зафиксировать промежуточный результат. Если вдруг требуетсся запилить долгоживущее приложение для широкого круга лиц — можно переводить в Даш и отливать в бронзе.
Далее небольшая иллюстрация как выглядит процесс. Сделаем простой дашборд на основе данных по рынку подержанных машин Франции и Германии (просто потому что есть под рукой, с деталями датасета можно познакомиться в другом посте). Из функционала можно будет на основе статистики предложений по моделям посчитать средние цены в зависимости от возраста и их стандартное отклонение, построить сглаженные от шумов распределения цен внутри.
Действия не отличающиеся от просто анализа в блокноте я оставлю без деталей, их можно увидеть в блокнотах по ссылкам, там ничего нового нет.
Для начала импортируем библиотеки и данные. Я буду использовать для графики Bokeh, потому что она у меня стандартно и есть заготовки для копипасты.
Далее заготовим несколько функций:
wm и std чтобы использовать их при группировке данных в pandas
default_graph и default_bar_plot — создают пустые заготовки графиков
color_picker — для распределения выбранных объектов по цветовой палитре
В основной части объявляем используемые виджеты
# declare panel widgets
multi_select = pn.widgets.MultiSelect(name='Model selection (Ctrl for multiple)', value=['opel corsa (FR)', 'citroen c3 (FR)'],
options=list(raw_data['model'].unique()), size=8)
year_slider = pn.widgets.IntSlider(
name='Year', start=2007, end=2016, step=1, value=2012)
checkbox = pn.widgets.Checkbox(name='Show trend error bars')
далее создаем функцию описываюсшую взаимодействия используя декоратор.
@pn.depends(multi_select.param.value, year_slider.param.value, checkbox.param.value)
def update(models, year, checkbox_status):
Виджеты позволяют выбрать список моделей, выбрать год для просмотра распределия предложений по ценам а также показать/скрыть стандартное отклонение цены от средней по году на графике с трендом.
Внутри взаимодействия создаем наши заготовки графиков, далее для всех выбранных элементов наводим статистику, создаем элементы графика (линии, маркеры, стат погрешности),
собираем все в кучку и возвращаем графики как две вкладки для компактного показа.
return pn.Tabs(('Distribution', bokehdist), ('Trend', bokehfig))
Далее мы создаем наш макет расположив в нем виджеты и вкладки с графиками.
Процесс радует своей дубовой простотой и гибкостью, за счет простого табличого преставления.
pn.Row(pn.Column('### Dashboard demo', multi_select,
year_slider, checkbox), update).servable()
Метод servable() делает наш дашборд доступным для panel сервера чтобы запускать
независимо из командной строки меняя настройки сервера. Если мы продолжаем работать с блокнотом, то нам в нем доступен весь интерактивный функционал. Для пробного просмотра того, как приложение будет выглядеть для внешнего пользователя добавляем метод show(). На этом все наши дополнительные усилия окончены, и они незначительно отличаются от того, чтобы просто построить графики.
Примерно так выглядит дашборд в блокноте.
![image](https://habrastorage.org/webt/aj/mw/gi/ajmwgi5jwzwqo3nmsvezkqmf0lm.png)
Если мы хотим сделать дашборд доступным из-за пределов локалхоста надо разрешить обслуживать запросы извне, осторожным вайтлистингом или широким жестом типа
panel serve Dashboard_demo_panel.ipynb --allow-websocket-origin=*
Приложение которое увидит аналитик не отличается от того что в блокноте
![image](https://habrastorage.org/webt/fc/dw/sq/fcdwsqqnwl22cccoogpw7vzzrcu.png)
Авторы говорят, что исполнять сторонний код оно не позволит, но о степени защиты на недавнем вебинаре говорили несколько уклончиво. Поделиться с аналитиками — хватит, торчать наружу у таких собранных на коленке вещей нет необходимости.
Напоследок сравним как то же самое сделать с использованием Вуаля.
Версия с ipywidgets и bokeh у меня не взлетела, ругаясь на javascript в выводе.
Поэтому я перепилил ее на статичные графики matplotlib.
Собрать из ipywidgets тот же интерфейс с выпадающим списком, ползунком, чекбоксом и двумя вкладками потребовало некоторых усилий и костылей, не хватало той самой табличной гибкости. Тело основной функции пришлось перепилить чтобы растащить графики по вкладкам, то есть блокнот пришлось подстроить значительно больше, чем в первом случае.
Чтобы запустить вэб приложение при установленном расширении для Jupyter достаточно одного клика. Картинка получается достаточно похожей. Из разницы функционала — использованный виджет Interactive не вычисляет функцию по умолчанию, поэтому графики появляются только после первого взаимодействия с пользователем.
![image](https://habrastorage.org/webt/yl/rj/x2/ylrjx26i5len3osr8a9uhucz31g.png)
Лично по моим ощущениям — Panel явно победил по удобству использования. Тот же результат получился за сильно меньшее количество действий и дополнительные усилия чтобы его добавить к блокноту — минимальны. Так что все дружно и радостно переходим на панель!