Быстрые дашборды на Python с помощью DashExpress

от автора

Сегодня дашборды используются повсеместно: от быстрых отчетов «на лету» до демонстрации возможностей AI.

Существует множество замечательных продуктов для создания дашбордов: PowerBI, Tableu, Apache SuperSet и много других со своими плюсами и минусами. Однако все они являются отдельными приложениями в которые нужно дополнительно загружать данные, что часто бывает неудобно, если нужно быстро проанализировать датасет. И, если мы говорим про аналитиков, как правило все используют Python для анализа и ad-hoc исследований.

Для Python существует open source фреймворк построения дашбордов: PLotly Dash. Но те, кто его использовал, знают, насколько сложным может быть создание симпатичного интерфейса, и как скучно писать функции обратного вызова для каждого графика и фильтра. С этим еще можно мириться, если вы делаете дашборд для постоянного длительного использования, но с ad-hoc аналитикой этот вариант не годится.

Осознав проблему, я решил написать обертку над Dash, позволяющую создавать полноценные дашборды в 10-15 строк и запускать их прямо в jupiter-notebook и при этом отказаться от необходимости писать callback-функции. Так родился DashExpress. Документация

Концепция

Библиотека DashExpress в основном предназначена для ускорения разработки приложений Dash, но так же содержит ряд оптимизаций для более быстрой работы.

DashExpress опирается на 4 крупных проекта:

  1. Plotly Dash — для web-части

  2. Pandas — для хранения данных

  3. Dash Mantine — для симпатичного интерфейса

  4. Dash Leaflet — для построения карт

Установка

Библиотека устанавливается стандартно, через pip:

pip install dash-express 

Это также установит компоненты Plotly Dash, Pandas, Dash Mantine Components и Dash Leaflet.

Создание DashExpress-приложения

Вот код минимального приложения с одним графиком и тремя фильтрами:

import pandas as pd import plotly.graph_objects as go import dash_mantine_components as dmc  from dash_express import DashExpress, Page   # Получаем данные get_df = lambda: pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')  # Инициализируем приложение app = DashExpress(logo='DashExpress')  # Создаем страницу дашборда page = Page(     app=app,                    # DashExpress app     url_path='/',               # Путь страницы     name='Owerview',            # Название старницы     get_df=get_df,              # Функция получения дашборда     )  # Функция построения графика def bar_func(df):     pv = pd.pivot_table(df, index='continent', values='lifeExp').reset_index()     fig = go.Figure([go.Bar(x=pv['continent'], y=pv['lifeExp'])])     return fig  # Размечаем макет page.layout = dmc.SimpleGrid(     page.add_graph(h='calc(100vh - 138px)',render_func=bar_func)     )  # По каким колонкам фильтруем page.add_autofilter('continent', multi=True) page.add_autofilter('country', multi=True) page.add_autofilter('lifeExp', multi=True)  app.run() 

Запущенное приложение будет выглядеть так:

Минимальное приложение

Минимальное приложение

Приложение так же можно запустить прямо в jupiter-notebook, только перед этим нужно установить дополнительный пакет:

pip install jupyter-dash 
Jupiter

Jupiter

Теперь расскажу подробнее о некоторых шагах и начну с получения данных.

Получение таблицы с данными

В параметр get_df нужно передать функцию получения таблицы. По умолчанию результат функции DashExpress куширует на 1 час.
Если вы исследуете данные в jupiter notebook и у вас уже есть таблица, которую не нужно обновлять, просто передайте ее через функцию:

get_df = lambda: your_df 

Если у вас большой датасет используйте оптимизации на стороне pandas:

def get_df():     # Загружаем только нужные колонки     df =  pd.read_csv('titanic.csv', usecols=['survived', 'age', 'class', 'who', 'alone'])      # Преобразуем к оптимальным форматам     df.age = df.age.fillna(0)     df = df.astype(         {             'survived': 'int8',             'age': 'int8',             'class': 'category',             'who': 'category',             'alone': 'bool'         }     )       return df 

Разметка страницы

Разметьте страницу с помощью grid сетки, и вставьте графики, карты и KPI c помощью методов .add_graph, .add_map и .add_kpi. Рекомендую использовать компаненты dash mantine. (dmc.Grid & dmc.SimpleGrid)

page.layout = dmc.SimpleGrid(     ...     ) 

KPI cards

KPI карточки являются основной частью мониторинга эффективности бизнеса и отслеживания актуальной информации. Любая карта состоит из постоянной части (контейнера) и переменной части (показателя KPI).

Система рендеринга KPI основана на использовании класса KPI, который содержит контейнерное представление и логику расчета показателя. Простейшая реализация KPI с автоматической генерацией функции расчета представлена в классе FastKPI:

app.add_kpi(FastKPI('survived', agg_func=np.mean) 

Графики Plotly

Библиотека построения графиков Plotly содержит более 50 типов диаграмм на выбор. Чтобы встроить их в приложение Dash Express, вам нужно ответить на 2 вопроса:

  1. Где находится график

  2. Как построить график

Ответ на первый вопрос закладывается при разработке макета, путем вызова метода page.add_graph(…) в расположении графика, простой пример:

dmc.SimpleGrid(     [         page.add_graph(render_func=bar_chart),         page.add_graph(render_func=line_chart),     ],     cols=2     ) 

На второй вопрос отвечает параметр render_func, представляющий собой функцию принимающую DataFrame, и возвращающую график plotly.

Карты Leaflet

Если вы используете GeoPandas, вы можете добавлять карты на свою панель мониторинга, это так же просто, как добавить график:

dmc.SimpleGrid(     [         page.add_map(geojson_func=None),     ],     cols=1     ) 

geojson_func — должен возвращать geojson для построения карты. Если вам не нужны какие-либо дополнительные преобразования, не указывайте этот параметр, DashExpress все сделает за вас.

def geojson_func(gdf):     gdf = gdf[gdf.geometry.geom_type == 'Polygon']     return gdf.__geo_interface__ 

Фильтрация

Последним действием является добавление фильтров, которое выполняется простым вызовом метода page.add_filter и указанием столбца фильтрации.

page.add_autofilter('continent', multi=True) page.add_autofilter('country', multi=True) page.add_autofilter('lifeExp', multi=True) 

Заключение

DashExpress не только быстрое решение, но и гибкое: Вы можете полностью изменить внешний вид интерфейса переопределив класс BaseAppShell. Подробнее об этом расскажу в одной из следующих статей.

Помимо этого Dash Express заботится о повышении производительности вместо вас, вот способы, встроенные по умолчанию:

  1. Использование обратных вызовов на стороне клиента — Большинство обратных вызовов реализовано на стороне клиента, а не на сервере в Python.

  2. Частичные обновления свойств — Функции создания графиков автоматически преобразуются в Patch объекты, обновляя только те части свойства, которые вы хотите изменить.

  3. Кэширование — Dash Express использует библиотеку Flask-Caching, которая сохраняет результаты в базе данных с общей памятью, такой как Redis, или в виде файла в вашей файловой системе.

  4. Сериализация данных с помощью orson — Dash Express использует or json для ускорения сериализации в JSON и, в свою очередь, повышения производительности обратного вызова

Спасибо за прочтение!


ссылка на оригинал статьи https://habr.com/ru/articles/752084/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *