Web-сервисы, Визуализация, Графики

Визуализация данных с помощью веб-фреймворка Dash

Время прочтения: 5 мин.

Dash является довольно интересным Веб-фреймворком для визуализации данных и имеет в себе довольно много полезных функций в сочетании с простотой их применения.

Сам Dash это некий коллаб  HTML, React.Js, Flask  и CSS и предоставляет python классы для всех своих визуальных компонентов.

В качестве демонстративного датасета я возьму датасет diamonds с сайта kaggle.

Если описывать полностью все функции, которые предоставляет dash, уйдет довольно много времени, исходя из этого, предлагаю в качестве простого примера визуализировать более камерную задачу. Допустим, вывести гистограмму количества драгоценных камней в зависимости от нескольких факторов: качество огранки, уровень чистоты и цвет. При этом выбор нужной  гистограммы происходит непосредственно в веб интерфейсе.

Пример сэмпла датасета:

Важные для нас столбцы это cut — огранка, color — цвет, и clarity — уровень чистоты. У уровня чистоты собственная маркировка. Ее расшифровка подробнее описана в источнике.

Для начала установим библиотеку dash (в качестве инструмента разработки я использую pyCharm, для jupyter notebook или jupyterLab разработчик советует устанавливать Jupyter-dash).

Pip install dash

И далее импортируем необходимые модули

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd
from dash.dependencies import Input, Output

Для начала отметим что работу в dash  можно разделить на две части внешнюю(layout) то есть создание визуальной составляющей дашборда, и внутреннюю(callbacks) в которых мы описываем логику взаимодействия с объектами на дашборде.

В начале инициализируем класс dash, а также подгружаем dataset

app = dash.Dash(__name__)
df  = pd.read_csv('C://Users//User//Desktop//Учеба//diam.csv',sep = ';')

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

Определяем компонент html.Div а также вносим в него заголовок(html.h1) и абзац(html.P)

app.layout = html.Div(children=[

    html.Div(
        children=[
            html.H1(children='Analysis diamonds dataset', className= 'header-title'),

            html.P(children='maybe this demo will be useful to someone (:', className= 'header-description')и 
                ], className= 'header')])

ClassName является ссылкой на css файл

Который можно подгрузить внутрь проекта создав для него папку assets.

Вид структуры должен быть подобный

И запустим наше приложение

if __name__ == '__main__':
    app.run_server(debug=True)

Заголовок готов, теперь можно приступить к созданию объекта dropdown. Это будет меню для выбора необходимой гистограммы.

Данный элемент в коде будет выглядеть вот так

html.Div([
    dcc.Dropdown(
        id='demo_drop',
        options=[
            {'label': 'Огранка', 'value': 'cut'},
            {'label': 'Ясность(чистота)', 'value': 'clarity'},
            {'label': 'Цвет', 'value': 'color'}
        ],
        value='cut', className="dropdown"
    )])

В данном случае id означает уникальный идентификатор объекта он нам понадобится, когда будем описывать логику. Как можно понять из кода функционал данного объекта можно описать через словарь.  Атрибут value означает дефолтное выбранное значение.

Далее добавляем графический объект.

dcc.Graph(id='output_graph')],className="card")

Далее нам нужно сделать так что бы наше приложение реагировало на запрос пользователя и для этого нужно использовать функции обратного вызова.  В них и будет описана связь между объектами Dropdown  и graph.

@app.callback(
 	   Output(component_id='output_graph', component_property='figure'),
    [	Input(component_id='demo_drop', component_property='value')]
)

В данном случае в input у нас заносится уникальный идентификатор dropdown объекта и его значения, которые мы описывали в словаре атрибута options.

А output возвращает гистограмму и ее значения.

Остается только прописать логику для обработки информации.

Чтобы понять сколько было драгоценных камней для каждого уровня огранки, нужно сгруппировать данные по уровням огранки и вычислить количество строк внутри группы.

Для pandas это будет выглядеть вот так:

h = df.groupby(['cut'], as_index=False, sort=False)['carat'].count()

Теперь вплетаем данное вычисление в функцию

def update_output(value):
    	if value == 'cut':
        		h = df.groupby(['cut'], as_index=False, sort=False)['carat'].count()
    	elif value == 'clarity':
        		h = df.groupby(['clarity'], as_index=False, sort=False)['carat'].count()
    	elif value == 'color':
        		h = df.groupby(['color'], as_index=False, sort=False)['carat'].count()
    	fig = px.bar(h, x=value, y="carat", labels = {"carat" : "Count"} )
    	 return fig

То есть если описывать, то каждая вариация выбора пользователя связана со значением, которое используется в алгоритме. А переменная fig создает гистограмму. Таким образом у нас выходит такого вида интерфейс с выбором параметра группировки.

Итоговый код

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd
from dash.dependencies import Input, Output

app = dash.Dash(__name__)
df  = pd.read_csv('C://Users//User//Desktop//Учеба//diam.csv',sep = ';')
 
app.layout = html.Div(children=[

    html.Div(
        children=[
            html.H1(children='Analysis diamonds dataset', className= 'header-title'),
 

            html.P(children='maybe this demo will be useful to someone (:', className= 'header-description')
                ], className= 'header'),
 
    #html.Label('Количество'),
    html.Div([
        dcc.Dropdown(
            id='demo_drop',
            options=[
                {'label': 'Огранка', 'value': 'cut'},
                {'label': 'Ясность(чистота)', 'value': 'clarity'},
                {'label': 'Цвет', 'value': 'color'}
            ],
            value='cut', className="dropdown"
        ),  dcc.Graph(id='output_graph')],className="card")
 
])
@app.callback(
    Output(component_id='output_graph', component_property='figure'),
    [Input(component_id='demo_drop', component_property='value')]
)
def update_output(value):
    if value == 'cut':
        h = df.groupby(['cut'], as_index=False, sort=False)['carat'].count()
    elif value == 'clarity':
        h = df.groupby(['clarity'], as_index=False, sort=False)['carat'].count()
    elif value == 'color':
        h = df.groupby(['color'], as_index=False, sort=False)['carat'].count()
    fig = px.bar(h, x=value, y="carat", labels = {"carat" : "Count"} )
    return fig
 
if __name__ == '__main__':
    app.run_server(debug=True)

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

Советуем почитать