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.
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.
🛠️ 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:
- 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.
- 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.
- Rellenar la Cuadrícula: Los cuadrados de la cuadrícula se rellenan secuencialmente, coloreando los primeros
ncuadrados con el color de la primera categoría, los siguientesmcuadrados con el color de la segunda, y así sucesivamente.
Consideremos un ejemplo simple: distribución de un presupuesto de 100€.
| Categoría | Presupuesto (€) | Porcentaje (%) |
|---|---|---|
| --- | --- | --- |
| Alquiler | 40 | 40 |
| Comida | 25 | 25 |
| --- | --- | --- |
| Transporte | 15 | 15 |
| Ocio | 20 | 20 |
| --- | --- | --- |
| Total | 100 | 100 |
En un gráfico de waffle de 10x10, asignaríamos 40 cuadrados al alquiler, 25 a comida, etc., coloreándolos en orden.
✨ 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
⚙️ 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:
fig = plt.figure(figsize=(10, 8)): Crea una figura de Matplotlib para nuestro gráfico.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.- 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. plt.imshow(waffle_chart, cmap=cmap, aspect='auto'): Esta es la clave para dibujar el waffle.imshowse 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 delcmap(mapa de colores).- 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.
- Creación de Leyenda: Se utiliza
matplotlib.patches.Patchpara 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-awesomey anotaciones, o librerías comopywaffle).
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
)
📈 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!
Tutoriales relacionados
- Un Viaje de Mil Millas: Visualizando Rutas y Conexiones con Mapas de Flujo en Pythonintermediate20 min
- Domina los Treemaps con Python y Matplotlib: Explorando Datos Jerárquicos Visualmenteintermediate15 min
- Desentrañando Historias con Gráficos de Red: Un Enfoque Práctico en Pythonintermediate25 min
- Revelando Patrones Ocultos: Introducción a los Gráficos de Coordenadas Paralelas en Pythonbeginner15 min
- Visualización Interactiva de Datos con Plotly Express en Python: ¡Crea Dashboards Asombrosos!intermediate18 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!