Charts & estilos — tablas, escalas y diagramas
y decisiones Guía unificada para (a) tablas estilizadas en notebooks/reportes, (b) escalas de color e interpolación para Mapbox (fill-color), y (c) convenciones de diagramación para procesos y flujos de datos.
Decisiones (consolidadas)
- Un solo contrato de escalas por métrica (rangos lineales predefinidos +
linspace
) y parcheo determinista deinterpolate_list
. Deprecamos “listas ad-hoc” de stops sin doc. - Presentación acoplada tabla+gráfico (cuando corresponda), y overlays en mapas con transparencia controlada.
- Diagramas con símbolos/colores consistentes y uso preferente de graphviz para reproducibilidad.
1) DataFrames estilizados (barras, notación)
Objetivo: mejorar lectura rápida de tablas en notebooks y reportes impresos.
Patrones recomendados
- Barras horizontales sobre columnas cuantitativas (percentiles o magnitudes).
- Formato: si la magnitud lo requiere, notación ingenieril o científica con sufijos (
K
,M
). - Ordenación y subtotales por
grouper
antes del estilo (evita que el formateo oculte outliers).
Snippet (pandas Styler)
def style_table(df, cols_pct=None, cols_num=None):
s = df.copy()
if cols_pct:
s[cols_pct] = s[cols_pct].astype(float)
if cols_num:
s[cols_num] = s[cols_num].astype(float)
sty = s.style
if cols_pct:
sty = sty.bar(subset=cols_pct, color='#DDEBF7', align='zero')
sty = sty.format({c: '{:.1%}' for c in cols_pct})
if cols_num:
sty = sty.bar(subset=cols_num, color='#FCE4D6')
sty = sty.format({c: '{:,.0f}' for c in cols_num})
return sty.set_table_styles([{'selector': 'th', 'props': 'text-align:center;'}])
Tabla y gráfico “pegados” en el output: mostrar la tabla justo debajo del plot para cada distrito/sección
mejora el contexto y reduce scroll.
2) Mapas (Matplotlib) — overlay con transparencia
Para inspecciones rápidas sin stack web: dibujar geometrías y superponer un mosaico base con imshow
usando los bounds del Axes
, y aplicar alpha en la capa vectorial.
fig, ax = plt.subplots(figsize=(10,6))
circuitos_gdf.dropna().plot(ax=ax, alpha=0.5) # capa vectorial
minx, maxx = ax.get_xlim(); miny, maxy = ax.get_ylim()
image = get_maps_image(minx, miny, maxx, maxy) # recupera raster de fondo
ax.imshow(image, extent=[minx, maxx, miny, maxy], aspect='equal')
Regla: el mapa base no debe tapar la simbología; controlarlo con alpha
en la capa vectorial.
3) Mapbox — políticas de escalas y “interpolate”
Estandarizamos rangos lineales por métrica y la inserción de stops en interpolate_list
:
Rangos sugeridos
- Pobreza: 0 → 0.60
- Indigencia: 0 → 0.25
- Canasta alimentaria (CBA): 0 → 300 000
- Canasta total (CBT): 0 → 600 000
- Ingreso mediano: 0 → 300 000
- Ingreso total familiar: 0 → 600 000
Estos rangos vienen de la práctica en tus cuadernos y se implementan con
np.linspace
paran_stops
uniforme.
Generación de stops
# ejemplo reducida
if 'Pobreza' in title:
linspace_values = np.linspace(0, 0.6, n_stops)
elif 'Indigencia' in title:
linspace_values = np.linspace(0, 0.25, n_stops)
elif 'Canasta Alimentaria' in title:
linspace_values = np.linspace(0, 300000, n_stops)
# ... (resto de métricas)
Inserción/actualización en interpolate_list
La estructura típica de fill-color
es:
['interpolate', ['linear'], ['get', VAR],
v1, '#hex1', v2, '#hex2', ...]
El reemplazo correcto es antes de cada color hex o sobrescribiendo cada valor numérico tras el ['get', VAR]
. Evitar reemplazar colores o el get
.
def update_values(interpolate_list, linspace_values):
is_next_val_scale, color_idx, i = False, 0, 0
while i < len(interpolate_list):
val = interpolate_list[i]
if isinstance(val, list) and val[0] == 'get':
is_next_val_scale = True
elif is_next_val_scale and isinstance(val, (int, float)):
interpolate_list[i] = linspace_values[color_idx]; color_idx += 1
elif is_next_val_scale and isinstance(val, str) and val.startswith("#"):
is_next_val_scale = False
i += 1
return interpolate_list
Este patrón refleja la detección del get
y el recorrido seguro de stops, con variantes donde se inserta el valor numérico inmediatamente antes del color si la lista carece de stops explícitos.
Depuración: trazar con print
las decisiones (Found 'get'
, Replacing value…
) facilita validar que solo tocás los stops y no los colores.
4) Convenciones de diagramación (swimlanes, graphviz)
Objetivo: comunicar pipelines y responsabilidades con claridad y consistencia.
Símbolos
- Rectángulos = procesos/operaciones; paralelogramo = entrada/salida; diamante = decisión; óvalo = inicio/fin; flechas = flujo.
Capas y swimlanes
- Swimlanes (por equipo o etapa) y layers (por fase) mejoran la lectura en flujos complejos.
Herramientas
- Graphviz (recomendado para versionar), o Visio/Lucid/draw.io para diagramas manuales; Airflow/Prefect si se genera desde orquestadores.
Snippet (DOT mínimo)
digraph atlas_pipeline {
rankdir=LR; node [shape=rectangle, style=rounded];
subgraph cluster_ingesta { label="Ingesta"; n1[label="EPH"]; n2[label="Censo"]; }
subgraph cluster_etl { label="ETL"; e1[label="Preprocesar"]; e2[label="Merges"]; }
subgraph cluster_modelo { label="Modelo"; m1[label="Entrenar"]; m2[label="Publicar métricas"]; }
n1 -> e1 -> e2 -> m1 -> m2;
}
5) Accesibilidad, leyendas y estilos
- Accesibilidad: evitar pares rojo/verde sin textura; asegurar contraste AA.
- Leyenda: orden de bins consistente (menor→mayor), y texto corto con umbrales explícitos.
- Texturas/Hatches: usar “///”, “//”, “/” para densidad cualitativa en mapas monócromos (fallback impresión).
6) QA de visualizaciones (checklist)
- Escala correcta: rangos y
n_stops
acordes a la métrica; validarfill-color
después del parcheo. - Overlay: el mapa base no tapa la simbología (ver
alpha
). - Tabla/plot acoplados: tabla debajo del gráfico cuando se itera por
distrito/sección
. - Convenciones: símbolos y colores respetan la guía (rectángulo/proceso, diamante/decisión).
- Determinismo: el mismo dataset produce los mismos stops (linspace) y la misma leyenda.
7) Deprecaciones
- Dejado de usar paletas manuales dispersas y stops no documentados.
- Evitar scripts que mutan
interpolate_list
sin detectar['get', VAR]
primero.