feat(eda): poblar head_rows real en el capitulo OVERVIEW (df.head)
El capitulo OVERVIEW del motor AutomaticEDA mostraba "df.head no disponible"
porque ninguna fase de calculo poblaba las primeras filas crudas de la tabla.
- build_eda_render_ctx: nuevo bloque que muestrea SELECT * LIMIT head_n
(param nuevo head_n=10) y lo expone en ctx["head_rows"] como lista de
dicts fila. Estilo dict-no-throw: si la query falla, se omite la clave.
- profile_table: puebla prof["head_rows"] reusando _sample_rows (SELECT de
las columnas LIMIT 10) tras recalcular el type_breakdown. Asi el report
JSON sidecar tambien lo lleva y el capitulo lo recoge via profile aunque
no se construya el ctx.
- overview.py: la nota del DataTable de df.head ahora indica el total de
filas del dataset cuando se conoce ("primeras 10 filas de 891"). Bump
CHAPTER_VERSION 1.0.0 -> 1.1.0.
- overview_test.py (nuevo): golden (head via profile y via ctx, render PDF
+ PPTX muestran las filas reales, placeholder ausente), edge (sin
head_rows degrada a nota honesta sin romper, None/vacio devuelven None).
Verificado end-to-end con titanic: render_automatic_eda emite PDF + PPTX con
df.head visible (Braund/Cumings/Heikkinen + columnas) y sin el placeholder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,10 @@ vacia y el resto del ctx se construye igual. Ante un fallo global devuelve al
|
||||
menos ``{**base_ctx, "db_path": db_path, "table": table}``.
|
||||
|
||||
Claves de DATOS que produce (las consumen los capitulos):
|
||||
- ``head_rows`` : [ {col: valor, ...}, ... ] primeras filas CRUDAS de la
|
||||
tabla (``SELECT * LIMIT head_n``), una entrada por fila.
|
||||
La lee el capitulo OVERVIEW para mostrar df.head real en
|
||||
lugar del placeholder "df.head no disponible".
|
||||
- ``raw_numeric`` : {col: [float|None, ...]} muestra cruda de las columnas
|
||||
numericas, ALINEADA POR FILA (una entrada por fila aunque
|
||||
sea None). La leen modelos (clustering 2D en vivo) y
|
||||
@@ -56,7 +60,7 @@ def _to_float(value):
|
||||
return None
|
||||
|
||||
|
||||
def build_eda_render_ctx(db_path, table, profile, backend="duckdb", sample=5000, base_ctx=None):
|
||||
def build_eda_render_ctx(db_path, table, profile, backend="duckdb", sample=5000, base_ctx=None, head_n=10):
|
||||
"""Construye el ctx de datos crudos para los renderers de AutomaticEDA.
|
||||
|
||||
Args:
|
||||
@@ -77,13 +81,15 @@ def build_eda_render_ctx(db_path, table, profile, backend="duckdb", sample=5000,
|
||||
base_ctx: dict opcional con claves de presentacion ya preparadas
|
||||
(dataset_name, source_origin, ...). Se parte de una copia y NO se
|
||||
pisan sus claves; solo se añaden las de datos. Default None -> {}.
|
||||
head_n: numero de filas crudas a muestrear para ``ctx["head_rows"]``
|
||||
(df.head del capitulo OVERVIEW). Default 10. <=0 omite la clave.
|
||||
|
||||
Returns:
|
||||
El dict ``ctx`` directamente (NO un wrapper {status,...}): se pasa tal
|
||||
cual como ``meta={"ctx": <ese dict>}`` a render_automatic_eda_pdf/pptx.
|
||||
Nunca lanza. Claves que puede contener: raw_numeric, timeseries_raw,
|
||||
geo_points (omitidas si no aplican o fallan), y siempre db_path + table
|
||||
para backends validos.
|
||||
Nunca lanza. Claves que puede contener: head_rows, raw_numeric,
|
||||
timeseries_raw, geo_points (omitidas si no aplican o fallan), y siempre
|
||||
db_path + table para backends validos.
|
||||
"""
|
||||
# Copia de base_ctx: nunca mutamos el dict del caller. Las claves de
|
||||
# presentacion que ya traiga se conservan; las de datos se añaden encima.
|
||||
@@ -117,6 +123,24 @@ def build_eda_render_ctx(db_path, table, profile, backend="duckdb", sample=5000,
|
||||
ctx["db_path"] = db_path
|
||||
ctx["table"] = table
|
||||
|
||||
# 1.5) head_rows: primeras filas CRUDAS de la tabla (SELECT * LIMIT n)
|
||||
# para que el capitulo OVERVIEW muestre df.head real en vez del
|
||||
# placeholder. Una sola query, dict-no-throw: si falla, se omite la
|
||||
# clave (el capitulo degrada a su nota honesta). No se pisa una clave
|
||||
# head_rows que ya viniera en base_ctx (presentacion).
|
||||
if head_n and int(head_n) > 0 and "head_rows" not in ctx:
|
||||
try:
|
||||
hq = query_fn(f'SELECT * FROM "{table}" LIMIT {int(head_n)}')
|
||||
if isinstance(hq, dict) and hq.get("status") == "ok":
|
||||
hrows = [
|
||||
dict(r) for r in (hq.get("rows") or [])
|
||||
if isinstance(r, dict)
|
||||
]
|
||||
if hrows:
|
||||
ctx["head_rows"] = hrows
|
||||
except Exception: # noqa: BLE001 - dict-no-throw: omitir la clave
|
||||
pass
|
||||
|
||||
# 2) Columnas del perfil agregado (lectura defensiva).
|
||||
cols = profile.get("columns") if isinstance(profile, dict) else None
|
||||
cols = cols or []
|
||||
|
||||
Reference in New Issue
Block a user