Guia Dash

Guia Prático para Graduandos: Dashboards Interativos com Dash e Plotly

Um guia completo para criar visualizações de dados dinâmicos e impactantes utilizando Python.

Objetivos da Cartilha

Esta cartilha foi desenvolvida para guiar estudantes de graduação na jornada de criação de dashboards interativos. Nossos principais objetivos são:

Introduzir Conceitos

Apresentar os conceitos fundamentais por trás da visualização de dados e a importância dos dashboards na análise de informações.

Ensinar Ferramentas

Capacitar os alunos com o conhecimento prático das bibliotecas Dash e Plotly para a construção de dashboards em Python.

Inspirar com Exemplos

Fornecer exemplos práticos e com código-fonte que sirvam como base e inspiração para projetos futuros dos estudantes.

Instalação e Configuração

Siga estes passos para configurar seu ambiente de desenvolvimento e executar seu primeiro dashboard.

1. Instale o Visual Studio Code

O VS Code é um editor de código-fonte leve, mas poderoso, que é executado em seu desktop e está disponível para Windows, macOS e Linux. Ele vem com suporte integrado para JavaScript, TypeScript e Node.js e tem um rico ecossistema de extensões para outras linguagens (como Python) e tempos de execução.

2. Instale o `uv` (Gerenciador de Pacotes)

`uv` é um instalador e resolvedor de pacotes Python extremamente rápido, escrito em Rust. Ele é projetado como um substituto para `pip` e `pip-tools`. Para instalá-lo, siga as instruções no site oficial.

3. Inicialize seu Projeto

Navegue até a pasta do seu projeto no terminal e execute o comando abaixo. Isso criará um ambiente virtual e o arquivo `pyproject.toml`, que gerencia as dependências do seu projeto.

bash
$ uv init

4. Adicione as Dependências

Agora, instale as bibliotecas Python necessárias para o nosso projeto. Este comando adicionará `dash`, `pandas` e outras bibliotecas úteis ao seu ambiente.

bash
$ uv add dash==3.1.1 dash-ag-grid==32.3.1 dash-iconify>=0.1.2 dash-mantine-components>=2.1.0 dash-player>=1.1.0 pandas>=2.3.1

5. Crie a Aplicação Mínima

Crie um arquivo chamado `main.py` e adicione o código a seguir. Este é um aplicativo Dash interativo para garantir que nossa configuração está funcionando e para testar o hot-reload.

main.py
from dash import Dash, html, dcc, callback, Output, Input
import plotly.express as px
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')

app = Dash()

app.layout = [
    html.H1(children='Title of Dash App', style={'textAlign':'center'}),
    dcc.Dropdown(df.country.unique(), 'Canada', id='dropdown-selection'),
    dcc.Graph(id='graph-content')
]

@callback(
    Output('graph-content', 'figure'),
    Input('dropdown-selection', 'value')
)
def update_graph(value):
    dff = df[df.country==value]
    return px.line(dff, x='year', y='pop')

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

6. Execute e Teste o Hot-Reload

Execute o aplicativo. A opção `debug=True` ativa o "Hot Reload", que recarrega o servidor automaticamente sempre que você salva uma alteração no código.

bash
$ uv run python main.py

Atenção: Se você salvar o arquivo com um erro de sintaxe, o servidor pode parar. Se isso acontecer, corrija o erro e execute o comando `uv run python main.py` novamente.

Construindo o Dashboard: Passo a Passo

Agora que o ambiente está configurado, transforme seu app mínimo em um dashboard completo para análise de dados de ecocardiogramas. Cada passo adiciona uma nova funcionalidade ao nosso projeto.

Página do Kaggle

Passo 1: Baixe o Conjunto de Dados

O primeiro passo é obter os dados.

1. Acesse o Heart Disease Dataset no Kaggle.
2. Baixe e extraia o arquivo `archive.zip`.
3. Mova o `heart.csv` para a pasta do seu projeto.

main.py
# Importações necessárias para o projeto
import dash_mantine_components as dmc
from dash import Dash, Input, Output, clientside_callback, dcc
import dash_ag_grid as dag
import pandas as pd
import plotly.express as px
from dash_iconify import DashIconify

# Inicializa a aplicação Dash
app = Dash()

# Carrega os dados do ecocardiograma
dataframe = pd.read_csv("heart.csv")

# Execute o arquivo para testar se está funcionando
if __name__ == "__main__":
    app.run(debug=True)

Passo 2: Imports e Leitura dos Dados

Apague o código mínimo e comece com as importações específicas. Carregue o arquivo [`heart.csv`](heart.csv:1) que você baixou. Execute para verificar se não há erros de importação.

main.py (estrutura básica)
# Adicione após carregar os dados, antes do if __name__:

# Define a estrutura básica do layout
layout = dmc.AppShell(
    [
        dmc.AppShellHeader(
            dmc.Group(
                [
                    dmc.Title("Dashboard Ecocardiograma", order=1, c="blue"),
                ],
                justify="space-between",
                style={"flex": 1},
                h="100%",
                px="md",
            ),
        ),
        dmc.AppShellMain(
            dmc.Text("Conteúdo será adicionado aqui", size="lg", ta="center", py="xl")
        ),
    ],
    header={"height": 60},
    padding="md",
)

# Aplica o layout usando MantineProvider
app.layout = dmc.MantineProvider(layout)

Passo 3: Estrutura Básica do Layout

Crie a estrutura usando [`dmc.AppShell()`](main.py:1) com cabeçalho ([`AppShellHeader`](main.py:1)) e área principal ([`AppShellMain`](main.py:1)). O [`MantineProvider`](main.py:1) fornece temas consistentes.

main.py (primeiro gráfico)
# Substitua o conteúdo do dmc.AppShellMain por:
dmc.AppShellMain(
    dmc.Container(
        dmc.Card(
            children=[
                dmc.CardSection(
                    dmc.Text("Distribuição das Idades", fw=500, size="lg"),
                    withBorder=True,
                    inheritPadding=True,
                    py="xs"
                ),
                dmc.CardSection(
                    dcc.Graph(
                        figure=px.histogram(
                            dataframe,
                            x="age",
                            nbins=20,
                            title="Histograma das Idades dos Pacientes"
                        )
                    )
                ),
            ],
            withBorder=True,
            shadow="sm",
            radius="md",
            mt="md"
        ),
        size="xl"
    )
)

Passo 4: Primeiro Gráfico

Adicione seu primeiro gráfico usando [`px.histogram()`](main.py:1) dentro de um [`dmc.Card()`](main.py:1). O card possui seções para título e conteúdo, criando uma apresentação organizada.

main.py (múltiplos gráficos)
# Substitua o dmc.AppShellMain com um grid de gráficos:
dmc.AppShellMain(
    dmc.Grid(
        children=[
            # Gráfico 1: Distribuição das Idades
            dmc.GridCol(
                dmc.Card([
                    dmc.CardSection(dmc.Text("Distribuição das Idades", fw=500), withBorder=True, inheritPadding=True, py="xs"),
                    dmc.CardSection(dcc.Graph(figure=px.histogram(dataframe, x="age", nbins=20))),
                ], withBorder=True, shadow="sm", radius="md"),
                span="auto",
            ),
            # Gráfico 2: Distribuição por Sexo
            dmc.GridCol(
                dmc.Card([
                    dmc.CardSection(dmc.Text("Distribuição por Sexo", fw=500), withBorder=True, inheritPadding=True, py="xs"),
                    dmc.CardSection(dcc.Graph(figure=px.bar(
                        dataframe["sex"].value_counts().rename_axis("sex").reset_index(name="count"),
                        x="sex", y="count"
                    ))),
                ], withBorder=True, shadow="sm", radius="md"),
                span="auto",
            ),
            # Gráfico 3: Scatter Plot
            dmc.GridCol(
                dmc.Card([
                    dmc.CardSection(dmc.Text("Colesterol vs. Frequência Máxima", fw=500), withBorder=True, inheritPadding=True, py="xs"),
                    dmc.CardSection(dcc.Graph(figure=px.scatter(dataframe, x="chol", y="thalach", color="target"))),
                ], withBorder=True, shadow="sm", radius="md"),
                span="auto",
            ),
            # Gráfico 4: Box Plot
            dmc.GridCol(
                dmc.Card([
                    dmc.CardSection(dmc.Text("Pressão Arterial por Classe Alvo", fw=500), withBorder=True, inheritPadding=True, py="xs"),
                    dmc.CardSection(dcc.Graph(figure=px.box(dataframe, x="target", y="trestbps"))),
                ], withBorder=True, shadow="sm", radius="md"),
                span="auto",
            ),
        ],
        gutter="xs",
    ),
)

Passo 5: Sistema de Grid com Múltiplos Gráficos

Implemente um sistema de grid usando [`dmc.Grid()`](main.py:1) e [`dmc.GridCol()`](main.py:1) para organizar quatro tipos diferentes de gráficos: histograma, barra, scatter e box plot.

main.py (tabela de dados)
# Adicione após carregar o dataframe, antes do layout:

# Cria a tabela interativa
tabela = dag.AgGrid(
    rowData=dataframe.to_dict("records"),
    columnDefs=[{"field": i} for i in dataframe.columns],
    defaultColDef={"resizable": True, "sortable": True, "filter": True},
    className="ag-theme-alpine",
)

# Depois, adicione ao final do Grid, antes de fechar o children=[]:
            # Tabela de Dados - nova linha completa
            dmc.GridCol(
                dmc.Card([
                    dmc.CardSection(
                        dmc.Text("Tabela de Dados", fw=500),
                        withBorder=True,
                        inheritPadding=True,
                        py="xs"
                    ),
                    dmc.CardSection(tabela),
                ], withBorder=True, shadow="sm", radius="md"),
                span=12,  # Ocupa toda a largura
            ),

Passo 6: Tabela de Dados Interativa

Adicione uma tabela interativa usando [`dag.AgGrid()`](main.py:1) que permite ordenação, filtro e redimensionamento de colunas. A tabela ocupa a largura total com [`span=12`](main.py:1).

main.py (botão de tema)
# Adicione após as importações, antes de carregar o dataframe:

# Botão para alternar entre tema claro e escuro
botao_troca_tema = dmc.Switch(
    offLabel=DashIconify(icon="radix-icons:sun", width=15),
    onLabel=DashIconify(icon="radix-icons:moon", width=15),
    id="color-scheme-switch",
    persistence=True,
    color="grey",
)

# Modifique o cabeçalho para incluir o botão:
        dmc.AppShellHeader(
            dmc.Group(
                [
                    dmc.Title("Dashboard Ecocardiograma", order=1, c="blue"),
                    botao_troca_tema,  # Adiciona o botão aqui
                ],
                justify="space-between",
                style={"flex": 1},
                h="100%",
                px="md",
            ),
        ),

Passo 7: Botão de Alternância de Tema

Adicione um [`dmc.Switch()`](main.py:1) com ícones do [`DashIconify`](main.py:1) para alternar entre temas claro e escuro. O [`persistence=True`](main.py:1) mantém a preferência do usuário.

main.py (callbacks)
# Adicione após definir app.layout, antes do if __name__:

# Callback para alternar o tema usando JavaScript no cliente
clientside_callback(
    """
    (switchOn) => {
        document.documentElement.setAttribute(
            'data-mantine-color-scheme',
            switchOn ? 'dark' : 'light'
        );
        return window.dash_clientside.no_update
    }
    """,
    Output("color-scheme-switch", "id"),
    Input("color-scheme-switch", "checked"),
)

# Adicione também um ID ao AppShell para controle de tema:
# Modifique a linha do dmc.AppShell para incluir:
# dmc.AppShell([...], header={"height": 60}, padding="md", id="appshell")

Passo 8: Callbacks e Interatividade

Implemente um [`clientside_callback()`](main.py:1) que executa JavaScript no navegador para alternar o tema instantaneamente, sem precisar comunicar com o servidor Python.

Passo 9: Dashboard Completo e Interativo

Parabéns! Você construiu um dashboard completo seguindo uma abordagem incremental. Cada passo adicionou uma funcionalidade específica, permitindo compreender como cada elemento contribui para o resultado final.

📚 Conceitos Aprendidos:

  • Importações organizadas: Como estruturar as dependências do projeto
  • Layout responsivo: Uso do AppShell e sistema de Grid
  • Componentes visuais: Cards, seções e elementos de UI
  • Visualizações de dados: Diferentes tipos de gráficos com Plotly
  • Tabelas interativas: AG-Grid com funcionalidades avançadas
  • Temas dinâmicos: Sistema de alternância claro/escuro
  • Callbacks: Interatividade client-side e server-side

Para referência, aqui está o código completo final:

main.py (código completo)
{/* Código final completo será inserido aqui pelo script */}