Skip to main content

Pocket — colormaps categóricos estables

Asegurar colores estables por categoría (y keys compuestas) en figuras reproducibles, evitando saltos al agregar/quitar grupos.

Fuente: cluster_0168 — Correcciones y mejoras para mapeos de color.


Contrato mínimo

Entrada: lista/serie de categorías (strings, ints o tuplas), nombre de colormap.
Salida: dict {categoria: "#RRGGBB"} y utilidades de mapeo + leyenda.


1) Paleta determinística (orden estable)

Por defecto, asignamos colores en orden alfabético de categorías para garantizar estabilidad entre runs.

from matplotlib import cm, colors

def stable_palette(categories, cmap_name="tab20", sort=True):
# cast seguro a str para claves hashables
cats = [str(c) for c in categories]
cats = sorted(set(cats)) if sort else list(dict.fromkeys(cats))
cmap = cm.get_cmap(cmap_name, len(cats))
return {c: colors.to_hex(cmap(i)) for i, c in enumerate(cats)}
  • sort=True → estable entre ejecuciones;
  • sort=False → respeta primer aparición (útil en tablas ordenadas por ranking).

2) Keys compuestas (tuplas) → representación estable

Normalizamos tuplas a un string único y legible.

def norm_key(k):
return " | ".join(map(str, k)) if isinstance(k, tuple) else str(k)

Uso típico:

# df["grp"] puede contener tuplas (prov, dpto) o strings
df["_grp_norm"] = df["grp"].map(norm_key)
pal = stable_palette(df["_grp_norm"].unique(), "tab20")
df["color"] = df["_grp_norm"].map(lambda k: pal.get(k, "#9e9e9e"))

Evita KeyError con .get(..., default) y mantené un color “neutro” para categorías no mapeadas.


3) Aplicación en gráficos (bar/scatter) y leyenda estable

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

# ejemplo bar
ax = df.sort_values("_grp_norm").plot.bar(
x="_grp_norm", y="valor", color=df["color"].values, legend=False
)

# leyenda: proxies en el orden estable de la paleta
handles = [mpatches.Patch(color=col, label=lab) for lab, col in pal.items()]
ax.legend(handles=handles, title="Grupo", ncol=2, frameon=False)
plt.tight_layout()

4) Trampas comunes (y fixes)

  • Reasignación implícita de colores al cambiar el subset → siempre derive colores desde la paleta global estable.
  • Keys no hashables (listas) → normalizá a string con norm_key.
  • RGBA a hex: usa matplotlib.colors.to_hex(rgba) para evitar formatos inconsistentes.
  • Colormap insuficiente para muchas categorías → elegir tab20, tab20b, o generar paletas discretas con get_cmap(..., N).

Ver también

  • metodos/charts_and_styles.md (política de escalas y estilos).
  • pocket/mapbox_overlay_patches.md (si la asignación termina en JSON de estilos).