Files
fn_registry/python/functions/datascience/render_automatic_eda_markdown.md
T
egutierrez 48de3ce3da feat(eda): salida Markdown del AutomaticEDA para pegar a un LLM
Añade un tercer formato de salida al AutomaticEDA, junto al PDF y el PPTX:
un Markdown autocontenido del MISMO documento por capítulos
(chapters_registry.build_document), optimizado para incorporar a un LLM
(texto plano + tablas markdown reales, sin binarios incrustados).

- render_md_impl.render_md(chapters, out_path, meta): serializa los bloques
  del modelo (Heading/Markdown/KVTable/DataTable/Figure/Image/Caption/Note/
  Group/GlossaryEntry) a Markdown. Cabecera con metadatos + índice navegable
  con anclas GitHub; tablas volcadas enteras (el MD no pagina); marcadores de
  glosario eliminados conservando la negrita; glosario al final.
- Figuras: un LLM no ve la imagen, así que se prioriza texto + datos. Se emite
  el caption y, cuando la figura tiene barras (histograma), se extrae la tabla
  de bins (Desde/Hasta/Frecuencia) de los artistas matplotlib. La banda ±1σ
  (axvspan) se descarta por ancho para que no aparezca como un falso bin.
  PNG opcional vía meta['embed_figures'] (off por defecto → sin binarios).
- render_automatic_eda_markdown: función pública del registry (tag eda),
  espejo de render_automatic_eda_pdf/pptx, acepta lista de capítulos o un
  TableProfile (build_document). dict-no-throw.
- render_automatic_eda (pipeline): emite también el .md (emit_md=True por
  defecto, clave de retorno aeda_md_path). Cambio aditivo: PDF/PPTX/manifest
  siguen saliendo igual.

Tests: golden de todos los kinds + regresión del filtro de la banda ±1σ +
edge documento vacío + profile path. Suite del paquete y del pipeline verde
(122 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 18:52:08 +02:00

6.5 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, params, output, tested, tests, test_file_path, file_path
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports params output tested tests test_file_path file_path
render_automatic_eda_markdown function py datascience 1.0.0 impure def render_automatic_eda_markdown(chapters_or_profile, out_path: str, meta: dict = None) -> dict Renderiza un documento AutomaticEDA por CAPÍTULOS (modelo de bloques independiente del formato) en un único MARKDOWN autocontenido pensado para PEGAR A UN LLM. Acepta una lista de capítulos del modelo o directamente un TableProfile del grupo eda (construye los capítulos canónicos con build_document). Prioriza TEXTO + DATOS sobre lo visual: las tablas se vuelcan como tablas markdown con TODAS las filas (sin paginar — no hay páginas que cortar), una figura matplotlib se reduce a su caption más la tabla de datos subyacente (Desde/Hasta/Frecuencia de las barras del histograma) porque un LLM no ve la imagen, y los marcadores de glosario se eliminan conservando el **negrita**. Lleva cabecera (# título), bloque de metadatos en blockquote e índice numerado con anclas GitHub. Espejo de render_automatic_eda_pdf/render_automatic_eda_pptx pero SIN manifest (KISS, el markdown es un único artefacto de texto). dict-no-throw: nunca lanza, devuelve {path, n_chars, chapters, note}; en error fatal path es None y note explica la causa. Flag opcional meta['embed_figures'] exporta PNGs junto al .md (off por defecto).
eda
markdown
render
report
llm
automatic-eda
chapters
versioned
no-cut
text
datascience
python
false error_go_core
os
re
matplotlib
datascience.automatic_eda
name desc
chapters_or_profile una lista de capítulos del modelo AutomaticEDA (dataclasses Chapter o dicts {id,title,version,blocks}) O un TableProfile dict del grupo eda. Si es un TableProfile, los capítulos canónicos se construyen con build_document(profile, meta['ctx']). Bloques soportados: heading, markdown, kv_table, data_table, figure, image, caption, note, group, glossary_entry. Lectura defensiva: lo no reconocido se degrada a Note, nunca lanza.
name desc
out_path ruta del archivo .md de salida. Los directorios padre se crean si faltan. Directorio no escribible → {path:None, note:<causa>} sin lanzar.
name desc
meta dict opcional. Claves: title (título del documento), ctx (dict con dataset_name→Dataset, source_origin→Fuente, storage→Almacenamiento, n_rows/n_cols→Dimensiones; también lo consumen los builders de capítulo cuando se da un profile), generated_at (timestamp; si falta se genera ISO UTC), embed_figures (True para exportar PNGs <basename>_figN.png junto al .md; por defecto False y el markdown queda autocontenido).
dict (nunca lanza): {path: str|None, n_chars: int, chapters: list[{id,version}], note: str}. En error fatal (p.ej. directorio no escribible) path es None y note explica la causa. Un documento sin capítulos aplicables produce un markdown mínimo válido con 'documento vacío' y chapters=[]. true
test_golden_bloques_sinteticos_serializa_todo_a_markdown
test_edge_documento_vacio_no_revienta
test_profile_path_construye_capitulos_y_escribe
python/functions/datascience/render_automatic_eda_markdown_test.py python/functions/datascience/render_automatic_eda_markdown.py

Ejemplo

from datascience import render_automatic_eda_markdown

# Desde un TableProfile del grupo eda (mismo modelo que los renderers PDF/PPTX).
profile = {
    "table": "ventas", "source": "/data/ventas.csv",
    "n_rows": 1000, "n_cols": 2, "quality_score": 92.5,
    "columns": [
        {"name": "precio", "inferred_type": "numeric", "null_pct": 0.01,
         "numeric": {"mean": 42.5, "median": 40.0, "min": 1.0, "max": 100.0,
                     "std": 12.3}},
        {"name": "categoria", "inferred_type": "categorical", "null_pct": 0.0,
         "categorical": {"top": [{"value": "neumaticos", "count": 500}]}},
    ],
}
res = render_automatic_eda_markdown(
    profile, "reports/ventas_aeda.md",
    {"title": "EDA — ventas",
     "ctx": {"dataset_name": "Ventas", "source_origin": "ERP export",
             "n_rows": 1000, "n_cols": 2}})
print(res["path"], res["n_chars"], res["chapters"])
# -> reports/ventas_aeda.md 4123 [{'id':'portada','version':'1.0.0'}, ...]

Cuando usarla

Cuando quieras pegar el EDA a un LLM (ChatGPT, Claude, ...) o tenerlo en texto plano versionable: mismo documento por capítulos que el PDF/PPTX, pero serializado a Markdown sin binarios. Úsala como tercera salida junto a render_automatic_eda_pdf (móvil) y render_automatic_eda_pptx (compartir) desde el MISMO modelo de capítulos. A diferencia de esas dos, no hay páginas ni slides: todas las filas de cada tabla se vuelcan (nada se corta) y cada figura se reduce a su caption + la tabla de datos subyacente, que es lo que un LLM puede leer. Para añadir capítulos al documento, ver docs/capabilities/automatic_eda.md.

Gotchas

  • Impura: escribe el .md en out_path (crea los directorios padre). Con meta['embed_figures']=True además exporta un PNG <basename>_figN.png por figura junto al .md; por defecto NO exporta nada y el markdown queda autocontenido.
  • Nunca lanza (dict-no-throw): un bloque que falle se degrada a una nota y se anota en note; el documento se escribe igual. Un profile/lista vacíos producen un markdown mínimo válido con *(documento vacío …)* y chapters=[].
  • Figuras = datos, no imagen: un bloque figure se serializa como *Figura: caption* más, si la figura matplotlib trae barras (histograma / barras), una tabla | Desde | Hasta | Frecuencia | extraída de los Rectangle patches (máx 100 filas; el resto se trunca con *… (N filas más)*). Si no hay barras o algo falla, solo sale el caption. La figura se cierra (plt.close) tras leerla.
  • Glosario vs negrita: se eliminan SOLO los marcadores de glosario [[term:key]]visible[[/term]] (queda visible); el **negrita** markdown SE CONSERVA (es válido). No se usa strip_inline_md aquí porque ese también quita el bold.
  • Anclas del índice: el ## Índice enlaza cada capítulo con un ancla estilo GitHub del encabezado ## N. Título (minúsculas, espacios→-, sin signos). Si dos capítulos comparten título exacto sus anclas colisionan (caso raro; los capítulos canónicos tienen títulos únicos).
  • Tablas: las celdas escapan | (→ \|) y pliegan saltos de línea a <br> para no romper la columna. No hay reparto por ancho — un LLM no lo necesita.