tutoriales.com

Visualización Creativa con Gráficos de Waffle en Python: Representando Proporciones de Forma Impactante

Descubre cómo los gráficos de waffle pueden transformar la visualización de proporciones. Este tutorial te guiará paso a paso para crear estos gráficos en Python usando Matplotlib, Pandas y una pizca de creatividad para hacer tus datos más atractivos y fáciles de entender.

Intermedio15 min de lectura12 views
Reportar error

Los gráficos de waffle, también conocidos como square pie charts o grid charts, son una forma elegante y efectiva de visualizar proporciones y porcentajes. A diferencia de los gráficos de pastel o de barras apiladas, que a veces pueden ser difíciles de interpretar con muchas categorías o diferencias sutiles, los gráficos de waffle utilizan una cuadrícula de cuadrados (o cualquier otra forma pequeña) para representar el total, y luego colorean una proporción de esos cuadrados para mostrar las categorías individuales. Esto los hace intuitivos, especialmente cuando se trabaja con datos que suman 100% o que representan fracciones de un todo.

En este tutorial, exploraremos cómo construir gráficos de waffle en Python utilizando bibliotecas populares como Matplotlib y Pandas. Veremos desde la preparación de los datos hasta la personalización avanzada para crear visualizaciones impactantes.

🎯 ¿Por Qué Gráficos de Waffle? La Ventaja Visual

Los gráficos de waffle ofrecen varias ventajas sobre otras visualizaciones de proporciones:

  • Claridad en Proporciones: Son excelentes para mostrar el 'partes de un todo' de una manera muy directa, donde cada cuadrado representa un porcentaje o una unidad. Son especialmente buenos cuando una categoría es muy pequeña y se perdería en un gráfico de pastel.
  • Fácil Comparación: Permiten comparar fácilmente el tamaño relativo de diferentes categorías. La representación discreta de unidades facilita la percepción visual de las diferencias.
  • Estéticamente Agradables: Pueden ser visualmente atractivos y atractivos, lo que ayuda a captar la atención del público.
  • Flexibilidad: Aunque tradicionalmente usan cuadrados, puedes adaptarlos para usar otras formas o iconos, añadiendo un toque creativo y temático a tus visualizaciones.
💡 Consejo: Usa gráficos de waffle cuando necesites enfatizar la composición de un todo en unidades discretas, o cuando quieras evitar las distorsiones visuales que a veces ocurren en los gráficos de pastel con muchas categorías.

🛠️ Herramientas Necesarias

Para seguir este tutorial, necesitarás tener instaladas las siguientes bibliotecas de Python:

  • Matplotlib: Para la creación de los gráficos.
  • Pandas: Para la manipulación y preparación de los datos.
  • Numpy: Para operaciones numéricas, aunque su uso será mínimo.

Si aún no las tienes instaladas, puedes hacerlo fácilmente usando pip:

pip install matplotlib pandas numpy

📖 Paso 1: Entendiendo la Lógica de los Gráficos de Waffle

Antes de sumergirnos en el código, es crucial entender cómo funciona un gráfico de waffle. La idea principal es la siguiente:

  1. Definir un Total: El gráfico representa un 'todo', que generalmente es 100 (o 100 unidades). Esto se visualiza como una cuadrícula total de, por ejemplo, 10x10 cuadrados, sumando 100 cuadrados.
  2. Asignar Proporciones: Cada categoría de datos tiene una proporción o porcentaje del total. Convertimos estas proporciones en un número de cuadrados enteros.
  3. Rellenar la Cuadrícula: Los cuadrados de la cuadrícula se rellenan secuencialmente, coloreando los primeros n cuadrados con el color de la primera categoría, los siguientes m cuadrados con el color de la segunda, y así sucesivamente.

Consideremos un ejemplo simple: distribución de un presupuesto de 100€.

CategoríaPresupuesto (€)Porcentaje (%)
---------
Alquiler4040
Comida2525
---------
Transporte1515
Ocio2020
---------
Total100100

En un gráfico de waffle de 10x10, asignaríamos 40 cuadrados al alquiler, 25 a comida, etc., coloreándolos en orden.

1. Datos de proporciones Ej: Alquiler 40%, Comida 25% 2. Calcular nº de cuadrados 40% de 100 = 40 cuadrados 3. Inicializar cuadrícula Matriz vacía de 10x10 (100 total) 4. Rellenar con colores Relleno secuencial por categorías

✨ Paso 2: Preparación de Datos con Pandas

Para nuestro ejemplo, utilizaremos un conjunto de datos ficticio sobre la distribución de usuarios por plataforma de streaming. Supondremos que tenemos 100 usuarios en total para simplificar, lo que hace que cada usuario represente un 1%.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

# Datos de ejemplo: Distribución de usuarios por plataforma de streaming
data = {
    'Plataforma': ['Netflix', 'Amazon Prime Video', 'Disney+', 'HBO Max', 'Otros'],
    'Usuarios': [45, 25, 15, 10, 5]
}
df = pd.DataFrame(data)

# Asegurarnos de que las sumas sean 100 para un waffle chart de 10x10
# Si no suman 100, podemos normalizarlas o ajustar el tamaño de la cuadrícula
if df['Usuarios'].sum() != 100:
    print("Advertencia: La suma de usuarios no es 100. Normalizando...")
    df['Usuarios'] = (df['Usuarios'] / df['Usuarios'].sum() * 100).round().astype(int)
    # Ajustar para que la suma sea exactamente 100 si hubo redondeo
    while df['Usuarios'].sum() != 100:
        diff = 100 - df['Usuarios'].sum()
        if diff > 0:
            # Añadir a la categoría más grande si falta
            df.loc[df['Usuarios'].idxmax(), 'Usuarios'] += diff
        else:
            # Restar de la categoría más grande si sobra
            df.loc[df['Usuarios'].idxmax(), 'Usuarios'] += diff

print(df)

Salida esperada:

          Plataforma  Usuarios
0            Netflix        45
1  Amazon Prime Video        25
2            Disney+        15
3            HBO Max        10
4              Otros         5
🔥 Importante: Para un gráfico de waffle 10x10 (100 cuadrados), es ideal que tus valores sumen 100. Si tus datos no lo hacen, deberás normalizarlos o decidir un tamaño de cuadrícula diferente. Aquí, hemos incluido una lógica para asegurar que sumen 100, ajustando el redondeo si es necesario.

⚙️ Paso 3: Construyendo el Gráfico de Waffle Básico

Ahora, vamos a crear la función principal para generar nuestro gráfico de waffle.

def create_waffle_chart(data, categories, values, title, colors, rows=10, cols=10):
    fig = plt.figure(figsize=(10, 8))
    plt.title(title, fontsize=16, pad=20)

    # Inicializar la cuadrícula vacía con un color base (gris claro)
    waffle_chart = np.zeros((rows, cols))
    
    # Mapear categorías a números enteros para rellenar la cuadrícula
    category_labels = categories.tolist()
    category_values = values.tolist()
    
    current_idx = 0
    for i, category_value in enumerate(category_values):
        num_squares = category_value  # Ya están en porcentaje/unidades
        for _ in range(num_squares):
            row = current_idx // cols
            col = current_idx % cols
            if row < rows: # Asegurarse de no exceder los límites de la cuadrícula
                waffle_chart[row, col] = i + 1  # Asignar un índice de categoría (+1 para evitar 0)
            current_idx += 1

    # Crear un mapa de colores para las categorías
    cmap = plt.cm.get_cmap('Paired', len(category_labels)) # Usar 'Paired' o cualquier otro cmap
    if colors: # Si se proporcionan colores personalizados
        cmap = plt.cm.colors.ListedColormap(colors)

    # Dibujar la cuadrícula
    plt.imshow(waffle_chart, cmap=cmap, aspect='auto')

    # Configurar los ticks para que no se muestren los números
    ax = plt.gca()
    ax.set_xticks(np.arange(-.5, cols, 1), minor=True)
    ax.set_yticks(np.arange(-.5, rows, 1), minor=True)
    ax.grid(which='minor', color='white', linestyle='-', linewidth=2)
    ax.set_xticks([])
    ax.set_yticks([])

    # Crear la leyenda
    legend_patches = []
    for i, category in enumerate(category_labels):
        color = colors[i] if colors else cmap(i)
        legend_patches.append(mpatches.Patch(color=color, label=f'{category}: {category_values[i]}%'))
    
    plt.legend(handles=legend_patches,
               loc='upper left', bbox_to_anchor=(1, 1),
               fontsize=12, frameon=False)

    plt.tight_layout()
    plt.show()

# Definir colores para las plataformas
platform_colors = ['#E50914', '#00A8E1', '#0064C7', '#6727B7', '#808080'] # Rojo Netflix, Azul Prime, etc.

# Llamar a la función para crear el gráfico
create_waffle_chart(
    df,
    categories=df['Plataforma'],
    values=df['Usuarios'],
    title='Distribución de Usuarios por Plataforma de Streaming',
    colors=platform_colors
)

Este código define una función create_waffle_chart que toma tus datos, categorías, valores y un título. Es flexible para que puedas especificar los colores y las dimensiones de la cuadrícula (por defecto 10x10).

Explicación del Código:

  1. fig = plt.figure(figsize=(10, 8)): Crea una figura de Matplotlib para nuestro gráfico.
  2. waffle_chart = np.zeros((rows, cols)): Inicializa una matriz NumPy de ceros que representará nuestra cuadrícula de waffle. Cada celda contendrá un número que indica a qué categoría pertenece.
  3. Bucle para rellenar la cuadrícula: Itera a través de cada categoría y sus valores. Para cada valor, calcula cuántos cuadrados debe ocupar y los asigna secuencialmente en la matriz waffle_chart.
  4. plt.imshow(waffle_chart, cmap=cmap, aspect='auto'): Esta es la clave para dibujar el waffle. imshow se usa comúnmente para mostrar imágenes, pero aquí lo usamos para mostrar nuestra matriz numérica, donde cada número se mapea a un color a través del cmap (mapa de colores).
  5. Configuración de Ticks y Cuadrícula: Se eliminan los ticks numéricos y se añade una cuadrícula blanca para separar visualmente los cuadrados, dando el efecto de waffle.
  6. Creación de Leyenda: Se utiliza matplotlib.patches.Patch para crear los elementos de la leyenda, asociando cada color con su categoría y su porcentaje.

🎨 Paso 4: Personalización y Mejora del Gráfico

Aunque el gráfico básico ya es funcional, podemos mejorarlo con algunas personalizaciones:

  • Ajustar Espaciado: Modificar el espaciado entre cuadrados.
  • Añadir Texto Directo: Colocar el porcentaje directamente en el gráfico.
  • Etiquetas de Ejes Personalizadas: Añadir etiquetas si los cuadrados tienen un significado por fila/columna.
  • Uso de Iconos: En lugar de cuadrados, usar iconos, aunque esto requeriría un enfoque más avanzado (por ejemplo, con font-awesome y anotaciones, o librerías como pywaffle).

Vamos a refinar la función para permitir un mayor control visual.

def create_waffle_chart_enhanced(data, categories, values, title, colors, rows=10, cols=10, spacing=0.5, font_size_legend=10, show_percentage=False):
    fig = plt.figure(figsize=(cols + 2, rows + 2)) # Ajustar tamaño de figura
    plt.title(title, fontsize=18, pad=20)

    waffle_chart = np.zeros((rows, cols))
    category_labels = categories.tolist()
    category_values = values.tolist()
    
    current_idx = 0
    for i, category_value in enumerate(category_values):
        num_squares = category_value
        for _ in range(num_squares):
            row = current_idx // cols
            col = current_idx % cols
            if row < rows:
                waffle_chart[row, col] = i + 1
            current_idx += 1

    # Crear un mapa de colores para las categorías
    cmap = plt.cm.colors.ListedColormap(colors) if colors else plt.cm.get_cmap('Paired', len(category_labels))

    # Dibujar los cuadrados individualmente para mayor control sobre el espaciado
    ax = fig.add_subplot(111)
    ax.set_xlim(-0.5 - spacing/2, cols - 0.5 + spacing/2)
    ax.set_ylim(-0.5 - spacing/2, rows - 0.5 + spacing/2)
    ax.set_aspect('equal')
    ax.axis('off') # Ocultar ejes

    for r in range(rows):
        for c in range(cols):
            category_index = int(waffle_chart[r, c]) - 1
            if category_index >= 0: # Si no es un cero (celda vacía si rows*cols > sum(values))
                color_to_use = colors[category_index] if colors else cmap(category_index)
                rect = mpatches.Rectangle((c - 0.5, r - 0.5), 1 - spacing, 1 - spacing,
                                        facecolor=color_to_use, edgecolor='white', linewidth=1)
                ax.add_patch(rect)

    # Invertir eje Y para que la primera categoría empiece arriba izquierda
    ax.invert_yaxis()

    # Crear la leyenda con porcentajes y un tamaño de fuente ajustable
    legend_patches = []
    for i, category in enumerate(category_labels):
        color = colors[i] if colors else cmap(i)
        label_text = f'{category}: {category_values[i]}%'
        legend_patches.append(mpatches.Patch(color=color, label=label_text))
    
    plt.legend(handles=legend_patches,
               loc='upper left', bbox_to_anchor=(1.05, 1),
               fontsize=font_size_legend, frameon=False)

    plt.tight_layout()
    plt.show()

# Llamar a la función mejorada
create_waffle_chart_enhanced(
    df,
    categories=df['Plataforma'],
    values=df['Usuarios'],
    title='Distribución de Usuarios por Plataforma (Mejorado)',
    colors=platform_colors,
    spacing=0.2, # Un poco más de espacio entre cuadrados
    font_size_legend=14
)
📌 Nota: En esta versión mejorada, dibujamos cada cuadrado como un `matplotlib.patches.Rectangle` individualmente. Esto nos da un control más preciso sobre el espaciado (`spacing`) y otros atributos visuales, como el borde blanco entre los cuadrados.

📈 Paso 5: Casos de Uso Avanzados y Consideraciones

Waffle Chart con un Total no-100

¿Qué pasa si tus datos no suman 100? Puedes ajustar el tamaño de la cuadrícula o normalizar los datos como hicimos al principio. Si el total es 200, podrías usar una cuadrícula de 10x20 o 14x14 (196 cuadrados) o simplemente cada cuadrado representa 2 unidades.

Por ejemplo, si tienes 200 items y quieres una cuadrícula de 10x10, cada cuadrado representaría 2 items.

# Ejemplo con datos que suman 200
data_large = {
    'Producto': ['A', 'B', 'C', 'D'],
    'Ventas': [80, 60, 40, 20] # Suma 200
}
df_large = pd.DataFrame(data_large)

# Cada cuadrado representará 2 unidades (200 / 100 = 2)
# Dividimos los valores por 2 para que se ajusten a una cuadrícula de 100 cuadrados
df_large['Cuadrados'] = (df_large['Ventas'] / 2).astype(int)

# Colores para los productos
product_colors = ['#FFC300', '#FF5733', '#C70039', '#900C3F']

create_waffle_chart_enhanced(
    df_large,
    categories=df_large['Producto'],
    values=df_large['Cuadrados'], # Usamos la columna 'Cuadrados' para el rellenado
    title='Distribución de Ventas por Producto (Total 200 unidades, 1 cuad=2 unid)',
    colors=product_colors,
    spacing=0.1
)

Gráficos de Waffle con Textos Directos o Etiquetas

Aunque el uso de plt.imshow simplifica mucho el dibujo, para añadir texto sobre cada 'waffle' cuadrado o para tener un control más granular sobre las formas, podrías usar bibliotecas especializadas o un enfoque completamente manual de matplotlib.patches para cada elemento. En nuestro create_waffle_chart_enhanced ya estamos dibujando rectángulos individuales, lo que abre la puerta a más personalización.

Por ejemplo, para añadir el porcentaje total de cada categoría justo al lado de su sección del waffle, puedes modificar el bucle de la leyenda o añadir anotaciones directamente en el gráfico (aunque esto puede ser complicado para un gráfico de waffle denso).

¿Cómo añadir anotaciones de texto en el gráfico? Para añadir texto directamente en el gráfico, necesitarías calcular la posición central de cada grupo de 'waffles' o la posición de un 'waffle' representativo para cada categoría. Esto puede volverse complejo rápidamente, especialmente si las categorías son pequeñas y dispersas. Una forma más sencilla sería usar la leyenda de forma más elaborada o una tabla complementaria.
# Ejemplo de cómo podrías intentar añadir texto (muy simplificado y puede requerir ajustes)
# Esto es más un concepto que una implementación robusta para todos los casos.
# Solo para fines ilustrativos y puede causar superposición en gráficos densos.

def add_text_to_waffle(ax, category_indices, category_labels, category_values, colors, rows, cols):
    # Calcular centroides de cada categoría (simplificado)
    current_idx = 0
    category_positions = {label: [] for label in category_labels}

    for i, label in enumerate(category_labels):
        num_squares = category_values[i]
        for _ in range(num_squares):
            row = current_idx // cols
            col = current_idx % cols
            if row < rows:
                category_positions[label].append((col, row))
            current_idx += 1
    
    for label, positions in category_positions.items():
        if positions:
            avg_x = sum([p[0] for p in positions]) / len(positions)
            avg_y = sum([p[1] for p in positions]) / len(positions)
            
            # Ajustar posición para que esté dentro del 'waffle'
            # Esto es un truco y necesita ser refinado para cada caso de uso
            ax.text(avg_x, avg_y, f'{category_values[category_labels.index(label)]}%',
                    color='white', ha='center', va='center', fontsize=8, fontweight='bold')

# Después de ax.add_patch(rect) en create_waffle_chart_enhanced:
# add_text_to_waffle(ax, category_indices, category_labels, category_values, colors, rows, cols)
# Para usar esto, necesitarías pasar los valores `category_values` como lista o Series.
# Ten en cuenta que esto puede saturar el gráfico si hay muchos cuadros pequeños.

Consideraciones de Accesibilidad

Al crear gráficos de waffle, considera:

  • Contraste de Colores: Asegúrate de que los colores elegidos tengan suficiente contraste para personas con daltonismo. Herramientas como ColorBrewer pueden ayudar.
  • Leyenda Clara: La leyenda debe ser siempre clara y fácil de leer, explicando qué representa cada color.
  • Texto Alternativo (en web): Si incrustas el gráfico en una página web, proporciona un texto alternativo (alt text) descriptivo para lectores de pantalla.

🌟 Conclusión

Los gráficos de waffle son una adición valiosa a tu arsenal de visualización de datos. Son excelentes para representar proporciones de una manera intuitiva y visualmente atractiva, superando a menudo las limitaciones de los gráficos de pastel cuando se trata de mostrar pequeñas diferencias o un gran número de categorías. Con Python y Matplotlib, tienes la flexibilidad de crearlos y personalizarlos para que se ajusten perfectamente a tu narrativa de datos.

Experimenta con diferentes tamaños de cuadrícula, esquemas de color y formas para encontrar la visualización más efectiva para tus datos. ¡La clave es la práctica y la creatividad!

💡 Próximos Pasos: Intenta aplicar los gráficos de waffle a tus propios conjuntos de datos. Experimenta con diferentes proporciones y números de categorías. ¡Verás cómo esta técnica puede darle vida a tus presentaciones de datos!

Tutoriales relacionados

Comentarios (0)

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