DEV Community

Francisco Júnior
Francisco Júnior

Posted on

Construindo seu Próprio BI com Python: O Fim do Vendor Lock-in (DuckDB, Marimo e Polars)

Se você trabalha com dados, provavelmente já viveu este pesadelo: a diretoria pede um novo dashboard de análise financeira. Você abre a sua ferramenta de BI tradicional (Power BI, Tableau, Looker), conecta no banco de dados, e de repente... a interface congela. O custo de licenciamento sobe a cada novo usuário, e você fica engessado nas limitações visuais da plataforma.

E se nós pudéssemos quebrar essa barreira? E se pudéssemos processar milhões de linhas em milissegundos, criar interfaces 100% customizáveis e rodar tudo sem pagar um centavo de licença por usuário?

Bem-vindo à Modern Data Stack 2.0. Hoje, vamos construir nosso próprio motor de Business Intelligence usando Python.

🏗️ A Arquitetura do Nosso BI Customizado

Para abandonar as ferramentas tradicionais, precisamos de uma arquitetura que suporte extração, processamento analítico (OLAP) e visualização reativa. Nossa stack de elite será:

  1. Ambiente: uv (para gestão de pacotes ultrarrápida) e OrbStack (se precisarmos subir serviços via Docker).
  2. Ingestão e Transformação: Polars (adeus, Pandas e MemoryError!).
  3. Motor OLAP: DuckDB (consultas SQL na velocidade da luz direto do disco).
  4. Frontend Reativo: Marimo (o notebook de nova geração que vira uma aplicação web instantânea).

💻 Mão na Massa: O Caso de Uso Financeiro

Para tornar isso real, vamos construir um mini-BI financeiro que analisa o histórico de ações (como BBAS3, PETR4, VALE3). Queremos extrair os dados, salvar em um formato de alta performance e criar um dashboard interativo.

Passo 1: O Setup "V8"

Esqueça o pip demorado. Vamos inicializar nosso projeto com o uv:

# Inicializa o projeto e cria o ambiente virtual em segundos
uv init meu_bi_python
cd meu_bi_python

# Adiciona as nossas ferramentas de elite
uv add duckdb polars marimo yfinance

Enter fullscreen mode Exit fullscreen mode

Passo 2: Ingestão e Formato de Ouro (Parquet)

BIs de verdade não leem CSV em produção. Eles leem Parquet. Vamos criar um script simples (ingestao.py) para puxar dados da bolsa e salvar de forma otimizada usando Polars.

import yfinance as yf
import polars as pl

print("Extraindo dados financeiros...")
# Baixando histórico de 5 anos do Banco do Brasil
df_pandas = yf.download("BBAS3.SA", period="5y")

# Convertendo para Polars para máxima performance
df_polars = pl.from_pandas(df_pandas).reset_index()

# Salvando no formato de ouro: Parquet
df_polars.write_parquet("historico_bbas3.parquet")
print("Dados salvos com sucesso em Parquet! 🚀")

Enter fullscreen mode Exit fullscreen mode

Ao rodar esse script, você terá um arquivo Parquet ultra-comprimido, pronto para ser lido em milissegundos.

Passo 3: O Motor OLAP encontra o Frontend (DuckDB + Marimo)

Aqui é onde a mágica das ferramentas tradicionais morre de inveja. Vamos criar nosso dashboard. No terminal, inicie o Marimo:

uv run marimo edit dashboard.py

Enter fullscreen mode Exit fullscreen mode

No Marimo, a execução é reativa. Quando um filtro muda, apenas o que depende dele é recalculado. Crie as seguintes células no seu ambiente Marimo:

Célula 1: Imports e Conexão OLAP

import marimo as mo
import duckdb
import polars as pl

# Conectando o DuckDB em memória (ele lerá o arquivo do disco direto)
con = duckdb.connect()

Enter fullscreen mode Exit fullscreen mode

Célula 2: A Interface (UI)
Vamos criar um slider para o usuário do nosso BI escolher quantos dias de histórico ele quer analisar.

# O Marimo cria componentes nativos renderizados na tela
dias_filtro = mo.ui.slider(start=30, stop=1500, step=30, value=365, label="Dias de Histórico:")
dias_filtro

Enter fullscreen mode Exit fullscreen mode

Célula 3: A Query SQL de Alta Performance
Aqui amarramos a interface do Marimo com o motor do DuckDB. O SQL será reexecutado na velocidade da luz toda vez que o slider se mover.

# Query lendo o Parquet com base no filtro reativo da UI
query = f"""
    SELECT Date, Close
    FROM 'historico_bbas3.parquet'
    ORDER BY Date DESC
    LIMIT {dias_filtro.value}
"""

# DuckDB executa o SQL e devolve um DataFrame Polars nativamente!
df_resultado = con.execute(query).pl()

Enter fullscreen mode Exit fullscreen mode

Célula 4: A Visualização

# Renderizando um gráfico de linha interativo
mo.ui.table(df_resultado) # Tabela de dados

Enter fullscreen mode Exit fullscreen mode

(Dica de Ouro: Você pode usar bibliotecas como Altair ou Plotly dentro do Marimo para gráficos ainda mais complexos, o Marimo renderiza nativamente).

Passo 4: Escalando com Redis e OpenSearch (O Próximo Nível)

Se o seu BI começar a escalar para toda a empresa e você precisar analisar logs ou processar filas assíncronas de relatórios pesados, a stack continua flexível:

  • Você sobe um contêiner do Redis via OrbStack para cachear as consultas do DuckDB.
  • Conecta o OpenSearch para adicionar uma barra de pesquisa textual (ex: "Buscar todas as atas de reunião onde 'dividendos' foi mencionado").

Nenhuma ferramenta de caixinha te dá essa liberdade arquitetural.


🎯 Conclusão

Criar seu próprio BI com Python não é mais um bicho de sete cabeças reservado para gigantes da tecnologia. Com DuckDB atuando como motor analítico, Polars quebrando limites de memória, e o Marimo transformando scripts em interfaces reativas, você retoma o controle dos seus dados.

Você ganha performance absoluta, governança de código real (via Git) e zera os custos de licenciamento abusivos. Você deixa de ser um passageiro da ferramenta e se torna o engenheiro da plataforma.

E você, já esbarrou nos limites estruturais de ferramentas como Power BI ou Metabase? Como você resolveu? Deixa aí nos comentários pra gente trocar uma ideia!


🎁 Bônus: Colocando seu BI em Produção (Modo Aplicativo)

Até agora, usamos o comando marimo edit dashboard.py, que abre a interface de desenvolvimento (com as células de código visíveis). Mas, e quando você quiser enviar esse painel para a diretoria ou para os analistas de negócio usarem?

Você não quer que eles vejam o código Python, apenas a interface limpa e reativa.

Para rodar o seu dashboard em modo de produção (como uma aplicação web standalone, ocultando o código e exibindo apenas os componentes visuais), basta usar este comando:

uv run marimo run dashboard.py

Enter fullscreen mode Exit fullscreen mode

Esse comando sobe um servidor local incrivelmente rápido e entrega a experiência final do usuário. Se você quiser expor isso para a rede da empresa, basta adicionar a flag do host:

uv run marimo run dashboard.py --host 0.0.0.0 --port 8080

Enter fullscreen mode Exit fullscreen mode

Pronto! Seu BI customizado, de alta performance e custo zero de licença, está no ar e pronto para ser acessado por qualquer pessoa na rede. 🚀

Top comments (0)