Tutorial: Dashboard Ejecutivo con Flask y Chart.js para Datos de vehículos

En este tutorial, aprenderás a construir un Dashboard de Análisis de Datos desde cero utilizando Python y Flask para el backend, y Chart.js para visualizaciones interactivas. Analizaremos un dataset real de vehículos nuevos en Ecuador (SRI) con más de 130,000 registros.

1. Arquitectura del Proyecto

El proyecto sigue una estructura limpia, separando la lógica de datos del diseño visual. Utilizaremos un estilo Ejecutivo Light con colores profesionales para una presentación impecable.

Estructura de Carpetas

Para comenzar, organiza tu directorio de la siguiente manera:

  • app.py: El corazón de nuestra aplicación (Backend).
  • Data/: Donde guardaremos nuestro archivo CSV.
  • templates/index.html: La interfaz de usuario.
  • static/css/style.css: Estilos y diseño del dashboard.
  • static/js/dashboard.js: Lógica de gráficas y filtros dinámicos.
  • static/images/: Espacio para el logotipo de tu marca.

2. El Motor: Backend con Python y Flask

El backend tiene tres responsabilidades críticas:

  1. Carga Eficiente: Leemos el CSV de 21 MB una sola vez al iniciar la aplicación para que las consultas sean instantáneas.
  2. Limpieza de Datos: El dataset del SRI usa comas para decimales (ej. 75290,00). Usamos Pandas para limpiar estos valores, convertir fechas y estandarizar textos.
  3. API REST: Creamos endpoints (rutas) que entregan datos en formato JSON para que el navegador pueda graficarlos sin recargar la página.

KPIs Calculados:

  • Total de vehículos registrados.
  • Avalúo total y promedio del mercado.
  • Ranking de marcas líderes.
  • Porcentaje de adopción de vehículos eléctricos.

3. El Diseño: Estilo Ejecutivo Light

Hemos optado por una interfaz clara y moderna. Utilizamos una paleta de colores profesional:

  • Teal Oscuro (#005f73): Para encabezados y bordes de énfasis.
  • Océano (#0077b6): Para botones de acción y KPIs principales.
  • Carmesí (#9e2a2b): Para alertas o datos que requieren atención.

El diseño es totalmente responsivo, lo que significa que el dashboard se adaptará automáticamente si se consulta desde un celular o una tablet.


4. Interactividad: Gráficas y Filtros con JS

La verdadera magia ocurre en el frontend con Chart.js. El dashboard no es estático; incluye un sistema de filtros combinados que permiten explorar los datos por:

  • Marca del vehículo.
  • Clase (Jeep, Camión, Auto, etc.).
  • Tipo de Combustible.
  • Cantón de registro.

Cada vez que aplicas un filtro, el archivo JavaScript realiza una petición al servidor, recibe los nuevos datos y actualiza las gráficas con transiciones suaves, permitiendo comparar, por ejemplo, cuántos vehículos eléctricos se venden en Quito frente a Guayaquil.


5. Visualizaciones Incluidas

El tutorial implementa tres tipos de visualizaciones estratégicas:

  1. Ranking de Marcas: Gráfico de barras horizontales para identificar fácilmente a los líderes del mercado.
  2. Análisis de Combustible: Gráfico de dona (Doughnut) para visualizar la cuota de mercado de Gasolina, Diésel y Eléctricos.
  3. Distribución por Clase: Barras verticales para entender qué segmentos (SUV, Livianos, Pesados) dominan el sector.

Conclusión

Este proyecto demuestra que no se necesitan herramientas costosas para crear herramientas de Business Intelligence potentes. Con Flask y Pandas, manejamos miles de datos en segundos, y con Chart.js, los presentamos de forma estética y funcional.

¿Estás listo para implementarlo? Solo necesitas instalar tus dependencias, colocar tu dataset en la carpeta Data y ejecutar tu servidor local. ¡El análisis de datos nunca se vio tan bien!

Los datos los pueden bajar de: https://descargas.sri.gob.ec/download/datosAbiertos/SRI_Vehiculos_Nuevos_2026.csv

Prompt que Utilizamos:

Crea una aplicación web completa con Flask y Chart.js para visualizar 
datos de vehículos nuevos registrados en el SRI de Ecuador.

## ESTRUCTURA DEL PROYECTO
sri_vehiculos_dashboard/
├── app.py
├── data/
│   └── SRI_Vehiculos_Nuevos_2026.csv   ← ya existe, no crear
├── templates/
│   └── index.html
├── static/
│   ├── css/
│   │   └── style.css
│   └── js/
│       └── dashboard.js
└── requirements.txt
## DATOS: CSV con separador ";" ubicado en Data/SRI_Vehiculos_Nuevos_2026.csv

Columnas del CSV (separador punto y coma):
- CATEGORÍA
- CÓDIGO DE VEHÍCULO
- TIPO TRANSACCIÓN
- MARCA
- MODELO
- PAIS
- AÑO MODELO
- CLASE (CAMION, JEEP, etc.)
- SUB CLASE
- TIPO (PESADO, LIVIANO, etc.)
- AVALÚO  ← puede tener espacios o tabs antes del decimal, limpiar al leer
- FECHA PROCESO (DD/MM/AAAA)
- TIPO SERVICIO
- CILINDRAJE
- TIPO COMBUSTIBLE (DIESEL, ELECTRICO, GASOLINA, etc.)
- FECHA COMPRA (DD/MM/AAAA)
- CANTÓN  ← código numérico
- COLOR 1
- COLOR 2
- PERSONA NATURAL - JURIDICA  ← valores: NATURAL, JURIDICA

## BACKEND (app.py)

- Usar Flask
- Leer el CSV UNA SOLA VEZ al iniciar la app con pandas, 
  guardarlo en memoria como variable global (el CSV tiene ~500k filas)
- Limpiar la columna AVALÚO: remover espacios, tabs y caracteres 
  invisibles, convertir a float
- Parsear fechas FECHA PROCESO y FECHA COMPRA con formato DD/MM/AAAA
- Endpoint GET /  → renderiza index.html
- Endpoint GET /api/kpis → retorna JSON con:
    - total_vehiculos: conteo total de registros
    - avaluo_total: suma total de avalúos
    - avaluo_promedio: promedio de avalúo
    - top_marca: marca con más registros
    - pct_electricos: porcentaje de vehículos eléctricos
    - pct_natural: porcentaje de personas naturales vs jurídicas

- Endpoint GET /api/marcas?limite=15 → top N marcas por cantidad de vehículos
  retorna: [{marca, cantidad, avaluo_promedio}]

- Endpoint GET /api/combustible → distribución por tipo de combustible
  retorna: [{tipo_combustible, cantidad, pct}]

- Endpoint GET /api/clase → distribución por CLASE de vehículo
  retorna: [{clase, cantidad}]

- Endpoint GET /api/filtrado → acepta query params opcionales:
  marca, clase, combustible, canton
  Aplica filtros combinados sobre el DataFrame global y retorna:
    - kpis filtrados (misma estructura que /api/kpis)
    - top marcas filtradas (top 10)
    - distribución combustible filtrada
  Retorna también listas únicas para poblar los dropdowns:
    GET /api/opciones → {marcas: [], clases: [], combustibles: [], cantones: []}

## FRONTEND (templates/index.html + static/)

Diseño dark ejecutivo con estas variables CSS base:
  --bg-primary: #0f1117
  --bg-card: #1a1d27
  --bg-card-hover: #1f2335
  --accent: #6c63ff
  --accent2: #00d4aa
  --accent3: #ff6b6b
  --text-primary: #e8eaf6
  --text-secondary: #8b8fa8
  --border: #2a2d3e

Layout: sidebar izquierdo con filtros + área principal con dashboard

### SECCIÓN 1 — KPI Cards (fila superior)
6 tarjetas animadas con:
  🚗 Total Vehículos
  💰 Avalúo Total (formato $X,XXX,XXX)
  📊 Avalúo Promedio
  🏆 Marca Líder
  ⚡ % Eléctricos
  👤 % Personas Naturales

### SECCIÓN 2 — Ranking de Marcas
Gráfico de barras horizontal (Chart.js) con top 15 marcas por volumen.
Tooltip muestra cantidad + avalúo promedio.

### SECCIÓN 3 — Análisis de Combustible
Gráfico de dona (Chart.js) con distribución de tipos de combustible.
Paleta: eléctrico=#00d4aa, diesel=#ff6b6b, gasolina=#6c63ff, 
híbrido=#ffd93d, otros=#8b8fa8

### SECCIÓN 4 — Distribución por Clase
Gráfico de barras verticales con CLASE de vehículo (JEEP, CAMION, etc.)

### SIDEBAR — Filtros interactivos
Dropdowns para: Marca, Clase, Tipo Combustible, Cantón
Botón "Aplicar Filtros" y "Limpiar Filtros"
Al aplicar, hacer fetch a /api/filtrado y actualizar TODOS los gráficos 
y KPIs sin recargar la página.

## RENDIMIENTO (importante por el tamaño del CSV)

- El CSV se carga una sola vez al arrancar con pd.read_csv()
- Todos los endpoints trabajan sobre el DataFrame en memoria con pandas
- Los endpoints de filtrado usan .query() o boolean indexing
- Agregar un spinner de carga mientras se renderizan los gráficos
- Los datos de /api/marcas, /api/combustible y /api/clase 
  se pre-calculan al inicio y se cachean como variables globales 
  (solo se recalculan si hay filtros activos)

## REQUISITOS (requirements.txt)
flask
pandas
gunicorn

## INSTRUCCIONES ADICIONALES
- Usar Chart.js desde CDN (no instalar)
- Todo el JS en static/js/dashboard.js, todo el CSS en static/css/style.css
- Los gráficos deben ser responsivos (responsive: true en Chart.js)
- Fuente: Inter desde Google Fonts
- Añadir un footer con: "Fuente: SRI Ecuador | Vehículos Nuevos 2026"
- Comentar el código en español
- El archivo CSV tiene separador ";" — usar pd.read_csv(..., sep=";")

Comentarios

Deja un comentario