Un heatmap es una representación gráfica de datos en la que los valores contenidos en una matriz se muestran mediante colores. Es como observar una tabla de datos “desde arriba”, donde cada celda refleja la magnitud de un valor en función de su tonalidad.
Este tipo de gráfico es especialmente útil para obtener una visión general de un conjunto numérico, más que para extraer valores específicos.
Heatmaps se utilizan con frecuencia para mostrar los resultados de un análisis de clustering jerárquico, acompañados de dendrogramas que agrupan filas y columnas según sus similitudes. Esto permite identificar patrones comunes, como países con características demográficas parecidas o variables fuertemente correlacionadas.
Variaciones
Mostrar el resultado de un clustering y comparar con expectativas (ejemplo: agrupaciones por continente).
Incluir los valores exactos en cada celda para facilitar la lectura numérica.
Usarlos en series temporales donde existen patrones regulares.
Aplicarlos a matrices de adyacencia para redes o grafos.
Errores habituales
No normalizar los datos antes de graficar.
No reordenar filas y columnas según los resultados de un clustering, lo que dificulta ver patrones.
Elegir una paleta de colores inadecuada, que confunda en lugar de resaltar diferencias.
Dataset: Precios Agroindustria de Cacao (2012 - 2025)
Archivo:MAG_PreciosAgroindustriaCacao_2025Junio.csv Fuente: Ministerio de Agricultura y Ganadería (MAG), Ecuador Última actualización: Junio 2025
import pandas as pddf = pd.read_csv("mag_preciosagroindustriacacao_2025junio.csv", sep=";")print(df.head())print(df.info())
PACC_ANIO PACC_MES DPA_PROVINCIA DPA_CANTON PACC_PRODUCTO \
0 2012 Enero El Oro Arenillas Cacao seco mezclado
1 2012 Enero El Oro Arenillas Cacao seco mezclado
2 2012 Enero El Oro El Guabo Cacao seco mezclado
3 2012 Enero El Oro El Guabo Cacao seco mezclado
4 2012 Enero El Oro Machala Cacao seco mezclado
PACC_PRESENTACION PACC_TIPO PACC_PRECIO_USD PACC_USD_KG
0 Quintal de 100,00 libras Compra 71.41 1.57
1 Quintal de 100,00 libras Venta 74.06 1.63
2 Quintal de 100,00 libras Compra 73.75 1.63
3 Quintal de 100,00 libras Venta 84.00 1.85
4 Quintal de 100,00 libras Compra 75.00 1.65
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 26246 entries, 0 to 26245
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 PACC_ANIO 26246 non-null int64
1 PACC_MES 26246 non-null object
2 DPA_PROVINCIA 26246 non-null object
3 DPA_CANTON 26246 non-null object
4 PACC_PRODUCTO 26246 non-null object
5 PACC_PRESENTACION 26246 non-null object
6 PACC_TIPO 26246 non-null object
7 PACC_PRECIO_USD 26246 non-null float64
8 PACC_USD_KG 26246 non-null float64
dtypes: float64(2), int64(1), object(6)
memory usage: 1.8+ MB
None
Iteración 1
import plotly.express as pximport plotly.io as piopio.renderers.default ="notebook"# Agrupar: precio promedio por año y cantóndf_pivot = ( df.groupby(["PACC_ANIO", "DPA_CANTON"])["PACC_PRECIO_USD"] .mean() .reset_index() .pivot(index="DPA_CANTON", columns="PACC_ANIO", values="PACC_PRECIO_USD"))# Convertir el pivot a formato largo (para Plotly)df_long = df_pivot.reset_index().melt(id_vars="DPA_CANTON", var_name="PACC_ANIO", value_name="PACC_PRECIO_USD")# Crear heatmapfig = px.imshow( df_pivot.values, labels=dict(x="Año", y="Cantón", color="Precio USD"), x=df_pivot.columns, y=df_pivot.index, color_continuous_scale="Viridis")# Ajustes de diseñofig.update_layout( title="Precio promedio en USD por año y cantón", xaxis=dict(side="top"), # años arriba font=dict(family="Arial", size=12), plot_bgcolor="white", margin=dict(l=80, r=40, t=80, b=40))fig.show()
Iteración 2
Cambio de nulos por 0
Presenta datos en cajas
# Reemplazar NaN por 0df_pivot = df_pivot.fillna(0)# Crear heatmapfig = px.imshow( df_pivot.values, labels=dict(x="Año", y="Cantón", color="Precio USD"), x=df_pivot.columns, y=df_pivot.index, color_continuous_scale="Viridis", text_auto=".2f"# mostrar valores dentro de cada celda con 2 decimales)# Ajustes de diseñofig.update_layout( title="Precio promedio en USD por año y cantón", xaxis=dict(side="top"), font=dict(family="Arial", size=12), plot_bgcolor="white", margin=dict(l=80, r=40, t=80, b=40))fig.show()
Iteración 3
Borde cajas Blanco
Eliminación de eje y eje x
import pandas as pdimport plotly.express as px# Agrupar: precio promedio por año y cantóndf_pivot = ( df.groupby(["PACC_ANIO", "DPA_CANTON"])["PACC_PRECIO_USD"] .mean() .reset_index() .pivot(index="DPA_CANTON", columns="PACC_ANIO", values="PACC_PRECIO_USD"))# Reemplazar NaN por 0df_pivot = df_pivot.fillna(0)# Crear heatmapfig = px.imshow( df_pivot.values, labels=dict(x="Año", y="Cantón", color="Precio USD"), x=df_pivot.columns, y=df_pivot.index, color_continuous_scale="Viridis")# Borde blanco entre celdasfig.update_traces( xgap=2, # separación entre columnas ygap=2# separación entre filas)# Ajustes de diseñofig.update_layout( title="Precio promedio en USD por año y cantón", xaxis=dict(side="top", title=""), # Quitar nombre eje X yaxis=dict(title=""), # Quitar nombre eje Y font=dict(family="Arial", size=12), plot_bgcolor="white", margin=dict(l=80, r=40, t=80, b=40), coloraxis_showscale=False# Quitar barra de color)fig.show()
Iteración 3
Ordenamiento
# Ordenar cantones por promedio total (de mayor a menor)df_pivot = df_pivot.loc[df_pivot.mean(axis=1).sort_values(ascending=False).index]# Crear heatmapfig = px.imshow( df_pivot.values, labels=dict(x="Año", y="Cantón", color="Precio USD"), x=df_pivot.columns, y=df_pivot.index, color_continuous_scale="Viridis")# Ajustes de diseñofig.update_layout( title="Precio promedio en USD por año y cantón", xaxis=dict(side="top", title=""), yaxis=dict(title=""), font=dict(family="Arial", size=12), plot_bgcolor="white", margin=dict(l=80, r=40, t=80, b=40), coloraxis_showscale=False)fig.show()