tutoriales.com

Revelando el Flujo: Creación de Diagramas de Sankey con Plotly en Python

Descubre cómo utilizar Plotly en Python para generar potentes diagramas de Sankey. Este tutorial te guiará paso a paso en la visualización de flujos complejos, desde la preparación de datos hasta la personalización avanzada, permitiéndote desentrañar patrones y relaciones ocultas.

Intermedio15 min de lectura19 views
Reportar error

Los diagramas de Sankey son una herramienta de visualización de datos extremadamente poderosa para representar flujos de información, energía, materiales o costos entre diferentes etapas o categorías. Son ideales para mostrar cómo un recurso se distribuye o se transforma a lo largo de un proceso, revelando cuellos de botella, eficiencias y pérdidas.

En este tutorial, exploraremos cómo construir estos diagramas impactantes utilizando la biblioteca Plotly en Python, conocida por sus visualizaciones interactivas y de alta calidad.

🎯 ¿Qué son los Diagramas de Sankey?

Imagina un río con sus afluentes y cómo se bifurca en diferentes arroyos. Un diagrama de Sankey es la representación visual de ese tipo de flujo. Se componen de nodos (las etapas o categorías) y enlaces (las conexiones entre nodos), donde el ancho del enlace es proporcional a la cantidad del flujo que representa.

Esto los hace excepcionalmente útiles para:

  • Análisis de energía: Flujo de energía en sistemas eléctricos o industriales.
  • Cadena de suministro: Movimiento de bienes desde el origen hasta el consumidor.
  • Finanzas: Distribución de presupuestos o gastos.
  • Ecología: Flujo de nutrientes o biomasa en ecosistemas.
  • Análisis web: Rutas de usuarios a través de un sitio web.
💡 Consejo: Piensa en Sankey cuando necesites mostrar 'de dónde viene y a dónde va' un cierto volumen o cantidad a través de múltiples etapas.

🛠️ Requisitos Previos

Antes de sumergirnos en el código, asegúrate de tener lo siguiente:

  • Python instalado (versión 3.7 o superior).
  • pip (el instalador de paquetes de Python).
  • Un entorno de desarrollo como Jupyter Notebook, VS Code o cualquier IDE de tu preferencia.

Necesitaremos instalar la biblioteca plotly. Abre tu terminal o Anaconda Prompt y ejecuta el siguiente comando:

pip install plotly pandas

pandas nos será útil para la manipulación de datos, aunque para ejemplos simples no es estrictamente necesario.


📝 Entendiendo la Estructura de Datos para Sankey

La clave para crear un diagrama de Sankey con Plotly es entender cómo debe estar estructurada la información. Plotly requiere dos componentes principales para definir el flujo:

  1. Nodos (nodes): Una lista de todas las categorías o etapas que participarán en el flujo. Cada nodo debe tener una etiqueta única.
  2. Enlaces (links): Una lista de las conexiones entre los nodos. Cada enlace necesita un source (origen), un target (destino) y un value (el volumen del flujo).

Es importante que los source y target de los enlaces hagan referencia al índice numérico (0, 1, 2, ...) de los nodos en tu lista de nodes, no a sus nombres.

Ejemplo Simple de Estructura de Datos

Imaginemos un flujo de estudiantes que, después de terminar el bachillerato, eligen diferentes carreras y luego diferentes especializaciones.

ID NodoEtiqueta del Nodo
------
0Bachillerato
1Ingeniería
------
2Medicina
3Artes
------
4Software
5Bioquímica
------
6Diseño Gráfico
Fuente (ID)Destino (ID)Valor
---------
01100
0270
---------
0350
1460
---------
1540
2530
---------
3650
📌 Nota: Los `values` de los enlaces que salen de un nodo no necesariamente tienen que sumar los `values` de los enlaces que llegan a ese nodo si hay pérdidas o ganancias en el proceso. Sin embargo, para un flujo conservativo (como el de energía), la suma sí debe ser consistente.

🚀 Primer Diagrama de Sankey Básico

Vamos a construir nuestro primer diagrama de Sankey utilizando el ejemplo de los estudiantes.

import plotly.graph_objects as go

# 1. Definir los nodos
labels = [
    "Bachillerato", 
    "Ingeniería", 
    "Medicina", 
    "Artes",
    "Software", 
    "Bioquímica", 
    "Diseño Gráfico"
]

# 2. Definir los enlaces (source, target, value)
# Recuerda que source y target son los ÍNDICES de los labels
source = [0, 0, 0, 1, 1, 2, 3]
target = [1, 2, 3, 4, 5, 5, 6]
value = [100, 70, 50, 60, 40, 30, 50]

# Crear el diagrama de Sankey
fig = go.Figure(data=[
    go.Sankey(
        node=dict(
            pad=15,  # Espacio entre nodos
            thickness=20, # Grosor de los nodos
            line=dict(color="black", width=0.5),
            label=labels, # Etiquetas de los nodos
            # color="blue" # Puedes asignar un color general a todos los nodos
        ),
        link=dict(
            source=source, # Índice de los nodos de origen
            target=target, # Índice de los nodos de destino
            value=value,   # Valores del flujo
            # color="lightgray" # Puedes asignar un color general a todos los enlaces
        )
    )
])

fig.update_layout(title_text="Flujo de Estudiantes por Carreras y Especializaciones", font_size=10)
fig.show()

Al ejecutar este código, verás una ventana emergente o el gráfico incrustado en tu Jupyter Notebook, mostrando un diagrama de Sankey interactivo. Pasa el ratón por encima de los nodos y enlaces para ver los detalles del flujo. ¡Es mágico!

Bachillerato (220) Ingeniería (100) Medicina (70) Artes (50) Software (60) Bioquímica (70) Diseño Gráfico (50)

🎨 Personalización y Estilo Avanzado

Plotly ofrece una gran cantidad de opciones para personalizar la apariencia de tus diagramas de Sankey.

Colores de Nodos y Enlaces

Puedes asignar colores específicos a cada nodo y enlace para mejorar la legibilidad y resaltar información clave.

# ... (definición de labels, source, target, value)

# Colores para los nodos (uno por cada etiqueta)
node_colors = [
    "#FFD700", # Bachillerato - Oro
    "#4682B4", # Ingeniería - Azul Acero
    "#DC143C", # Medicina - Carmesí
    "#228B22", # Artes - Verde Bosque
    "#6A5ACD", # Software - Púrpura Pizarra
    "#FF6347", # Bioquímica - Tomate
    "#8A2BE2"  # Diseño Gráfico - Azul Violeta
]

# Colores para los enlaces (uno por cada enlace)
# Puedes basar los colores en la fuente, el destino o el valor
link_colors = [
    "rgba(70, 130, 180, 0.4)", # Ingeniería
    "rgba(220, 20, 60, 0.4)",  # Medicina
    "rgba(34, 139, 34, 0.4)",  # Artes
    "rgba(106, 90, 205, 0.4)", # Software
    "rgba(255, 99, 71, 0.4)",  # Bioquímica (desde Ingeniería)
    "rgba(255, 99, 71, 0.4)",  # Bioquímica (desde Medicina)
    "rgba(138, 43, 226, 0.4)"  # Diseño Gráfico
]

fig = go.Figure(data=[
    go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color="black", width=0.5),
            label=labels,
            color=node_colors # Asignamos los colores a los nodos
        ),
        link=dict(
            source=source,
            target=target,
            value=value,
            color=link_colors # Asignamos los colores a los enlaces
        )
    )
])

fig.update_layout(title_text="Flujo de Estudiantes con Colores Personalizados", font_size=10)
fig.show()
🔥 Importante: Para los colores de los enlaces, a menudo se usa un formato `rgba` para incluir transparencia. Esto ayuda a visualizar los flujos superpuestos sin ocultar completamente los enlaces de fondo.

Posición y Alineación de Nodos

Plotly permite controlar la posición horizontal (x) y vertical (y) de los nodos, así como su alineación (align). Esto es útil para organizar diagramas complejos.

  • x: Una lista de valores (entre 0 y 1) que representan la posición horizontal de cada nodo. 0 es la izquierda, 1 es la derecha.
  • y: Una lista de valores (entre 0 y 1) que representan la posición vertical de cada nodo. 0 es la parte inferior, 1 es la parte superior.
  • align: 'left', 'right', 'center'. Define la alineación de los nodos dentro de su columna vertical.
# ... (definición de labels, source, target, value, node_colors, link_colors)

# Posiciones manuales para los nodos
# Para un diagrama simple, Plotly lo organiza bien por defecto, pero puedes ajustarlo.
# Estas son solo de ejemplo para mostrar cómo se usarían.
node_x = [0.1, 0.4, 0.4, 0.4, 0.7, 0.7, 0.7]
node_y = [0.5, 0.8, 0.5, 0.2, 0.8, 0.5, 0.2]

fig = go.Figure(data=[
    go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color="black", width=0.5),
            label=labels,
            color=node_colors,
            x=node_x, # Posición X
            y=node_y  # Posición Y
        ),
        link=dict(
            source=source,
            target=target,
            value=value,
            color=link_colors
        )
    )
])

fig.update_layout(title_text="Flujo de Estudiantes con Posición de Nodos Controlada", font_size=10)
fig.show()
¿Por qué ajustar las posiciones manualmente? A veces, Plotly puede organizar los nodos de una manera que no es óptima para la legibilidad o la estética, especialmente con muchos nodos o cruces de enlaces. Ajustar `x` e `y` manualmente te da control total sobre el diseño. Por ejemplo, puedes querer que nodos relacionados estén verticalmente alineados o que ciertos flujos sean más prominentes.

📊 Un Caso de Uso Real: Análisis del Flujo de Energía

Ahora, apliquemos lo aprendido a un escenario más práctico: la visualización del flujo de energía en un sistema. Usaremos datos ficticios que representan cómo la energía se genera, se transforma y se consume.

Consideremos el siguiente flujo:

  • Generación: Solar, Eólica, Nuclear
  • Transformación/Transmisión: Red Eléctrica, Almacenamiento
  • Consumo: Hogares, Industria, Vehículos Eléctricos
import pandas as pd
import plotly.graph_objects as go

# Datos de flujo de energía
data = {
    'source': ['Solar', 'Eólica', 'Nuclear', 'Red Eléctrica', 'Red Eléctrica', 'Red Eléctrica', 'Almacenamiento'],
    'target': ['Red Eléctrica', 'Red Eléctrica', 'Red Eléctrica', 'Hogares', 'Industria', 'Almacenamiento', 'Vehículos Eléctricos'],
    'value': [50, 70, 80, 60, 90, 30, 20]
}
df_energy = pd.DataFrame(data)

# Obtener todas las etiquetas de nodos únicas
all_nodes = list(pd.unique(df_energy[['source', 'target']].values.ravel('K')))

# Crear un mapeo de etiqueta a índice
label_to_index = {label: i for i, label in enumerate(all_nodes)}

# Convertir source y target a índices numéricos
df_energy['source_id'] = df_energy['source'].map(label_to_index)
df_energy['target_id'] = df_energy['target'].map(label_to_index)

# Definir colores de nodos y enlaces (ejemplo)
node_colors_energy = [
    "#FFC300", # Solar
    "#DAF7A6", # Eólica
    "#FF5733", # Nuclear
    "#C70039", # Red Eléctrica
    "#900C3F", # Almacenamiento
    "#581845", # Hogares
    "#A0C4FF", # Industria
    "#B8D8F7"  # Vehículos Eléctricos
]

link_colors_energy = [
    "rgba(255, 195, 0, 0.4)", # Solar -> Red
    "rgba(218, 247, 166, 0.4)", # Eólica -> Red
    "rgba(255, 87, 51, 0.4)",  # Nuclear -> Red
    "rgba(199, 0, 57, 0.4)",  # Red -> Hogares
    "rgba(144, 12, 63, 0.4)",  # Red -> Industria
    "rgba(88, 24, 69, 0.4)",   # Red -> Almacenamiento
    "rgba(160, 196, 255, 0.4)"  # Almacenamiento -> Vehículos
]

fig = go.Figure(data=[
    go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color="black", width=0.5),
            label=all_nodes,
            color=node_colors_energy
        ),
        link=dict(
            source=df_energy['source_id'],
            target=df_energy['target_id'],
            value=df_energy['value'],
            color=link_colors_energy
        )
    )
])

fig.update_layout(title_text="Flujo de Energía en un Sistema (MW)", font_size=12)
fig.show()

En este ejemplo, usamos pandas para gestionar los datos, lo que es muy común en proyectos de ciencia de datos. Primero, recolectamos todos los nodos únicos y luego creamos un diccionario para mapear sus nombres a índices numéricos, que es lo que Plotly espera.

💡 Consejo: El uso de `pd.unique(df[['source', 'target']].values.ravel('K'))` es una forma eficiente de obtener todas las etiquetas únicas de origen y destino de un DataFrame de Pandas.

✨ Consejos Avanzados y Buenas Prácticas

  1. Datos Limpios: Asegúrate de que tus datos de source, target y value sean consistentes y no contengan errores. Los diagramas de Sankey son sensibles a la calidad de los datos.
  2. Escalabilidad: Para un gran número de nodos y enlaces, el diagrama puede volverse abrumador. Considera agrupar nodos o filtrar flujos menos significativos si la complejidad es muy alta.
  3. Interactividad: Aprovecha la interactividad de Plotly. Los usuarios pueden hacer zoom, pan y ver detalles al pasar el ratón, lo que es invaluable para explorar datos complejos.
  4. Colores Significativos: Usa colores para diferenciar categorías de nodos o tipos de flujos, pero no abuses de ellos. La paleta de colores debe ser coherente y añadir valor, no confusión.
  5. Etiquetas Claras: Las etiquetas de los nodos deben ser concisas y descriptivas.
  6. Narrativa: Un diagrama de Sankey es una herramienta de storytelling. Úsalo para contar una historia sobre cómo los recursos se mueven y transforman. Acompaña el gráfico con texto explicativo que guíe al lector.
⚠️ Advertencia: Evita cruces excesivos de enlaces si es posible, ya que pueden dificultar la interpretación del flujo. A veces ajustar `x` e `y` de los nodos puede ayudar.

Añadiendo información adicional en los tooltips

Plotly permite personalizar el texto que aparece cuando pasas el ratón sobre los nodos o enlaces (hovertemplate o hoverinfo). Esto puede ser muy útil para mostrar detalles adicionales sin saturar el gráfico.

Por ejemplo, para los enlaces:

# ... (código anterior para df_energy y all_nodes, label_to_index, etc.)

fig = go.Figure(data=[
    go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color="black", width=0.5),
            label=all_nodes,
            color=node_colors_energy,
            hovertemplate='Nodo: %{label}<br>Flujo Entrante: %{value}<extra></extra>' # Personalizar hover para nodos
        ),
        link=dict(
            source=df_energy['source_id'],
            target=df_energy['target_id'],
            value=df_energy['value'],
            color=link_colors_energy,
            hovertemplate='Origen: %{source.label}<br>Destino: %{target.label}<br>Cantidad: %{value} MW<extra></extra>' # Personalizar hover para enlaces
        )
    )
])

fig.update_layout(title_text="Flujo de Energía con Hovers Personalizados", font_size=12)
fig.show()

El hovertemplate utiliza una sintaxis específica de Plotly con placeholders como %{label}, %{value}, %{source.label}, etc., para mostrar información dinámica.


🔄 Flujos Cíclicos y Retroalimentación

Los diagramas de Sankey también pueden representar flujos cíclicos o de retroalimentación, donde el flujo de un nodo puede volver a uno anterior. Plotly gestiona esto automáticamente, aunque la visualización puede requerir un cuidadoso posicionamiento de los nodos para evitar un desorden excesivo.

Considera un proceso donde parte del resultado se recicla o se reintroduce en una etapa anterior.

# Ejemplo de flujo cíclico (simplificado)
labels_cycle = ["Proceso A", "Proceso B", "Producto Final", "Reciclaje"]

source_cycle = [0, 0, 1, 3]
target_cycle = [1, 2, 2, 0] # Reciclaje (3) vuelve a Proceso A (0)
value_cycle = [80, 20, 100, 15] # 15 unidades de reciclaje de vuelta a Proceso A

fig_cycle = go.Figure(data=[
    go.Sankey(
        node=dict(
            pad=15,
            thickness=20,
            line=dict(color="black", width=0.5),
            label=labels_cycle,
            color=["lightblue", "lightcoral", "lightgreen", "lightgray"]
        ),
        link=dict(
            source=source_cycle,
            target=target_cycle,
            value=value_cycle,
            color=["rgba(173, 216, 230, 0.4)", "rgba(240, 128, 128, 0.4)", "rgba(144, 238, 144, 0.4)", "rgba(211, 211, 211, 0.4)"]
        )
    )
])

fig_cycle.update_layout(title_text="Diagrama de Sankey con Flujo Cíclico/Reciclaje", font_size=10)
fig_cycle.show()
80 20 100 15 Proceso A Proceso B Producto Final Reciclaje Flujo de Producción Circular

conclusiones y Siguientes Pasos ✅

Has aprendido a crear y personalizar diagramas de Sankey impactantes con Plotly en Python. Estas visualizaciones son invaluables para comprender y comunicar flujos complejos en una variedad de dominios, desde la economía hasta la biología.

Repaso de los Pasos Clave:

Paso 1: Entender la naturaleza de los diagramas de Sankey y sus aplicaciones.
Paso 2: Preparar los datos en el formato adecuado de nodos y enlaces (origen, destino, valor).
Paso 3: Mapear las etiquetas de los nodos a índices numéricos para `source` y `target`.
Paso 4: Utilizar `plotly.graph_objects.Sankey` para generar el diagrama.
Paso 5: Personalizar colores, posiciones y tooltips para mejorar la claridad y el atractivo visual.
Paso 6: Aplicar buenas prácticas para crear diagramas legibles y significativos.

¿Qué Sigue?

  • Explora más opciones de Plotly: La documentación de Plotly es muy extensa. Investiga más a fondo go.Sankey y otras propiedades de layout.
  • Datos Reales: Busca conjuntos de datos reales de flujos (ej. migración, energía, finanzas) e intenta visualizarlos.
  • Integración: Aprende a integrar estos gráficos interactivos en aplicaciones web con Dash (también de Plotly).
  • Animaciones: Para series temporales de flujos, considera cómo podrías animar los diagramas de Sankey.

Esperamos que este tutorial te haya proporcionado las herramientas y la confianza para empezar a revelar el flujo en tus propios datos. ¡La visualización de datos es un arte y una ciencia, y los diagramas de Sankey son una de sus herramientas más elegantes!

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!