--- name: render_automatic_eda_pptx kind: function lang: py domain: datascience version: "1.0.0" purity: impure signature: "def render_automatic_eda_pptx(chapters_or_profile, out_path: str, meta: dict = None) -> dict" description: "Renderiza un documento AutomaticEDA por CAPÍTULOS (modelo de bloques independiente del formato) en una presentación PPTX 16:9 pensada para COMPARTIR. Acepta una lista de capítulos del modelo o directamente un TableProfile del grupo eda (construye los capítulos canónicos con build_document). Mismo principio anti-corte que el renderer PDF: cada bloque se mide y, si no cabe en la slide, continúa en una slide ' (cont.)'; las tablas largas se parten por filas REPITIENDO la cabecera; las figuras matplotlib se exportan a PNG e insertan escaladas para caber enteras. Cada slide lleva pie 'Capítulo · vX.Y.Z' y se escribe automatic_eda_manifest.json junto a la salida. dict-no-throw: nunca lanza, devuelve {path, n_slides, chapters, manifest_path, note}. Motor python-pptx (dependencia declarada en python/pyproject.toml)." tags: [eda, pptx, render, report, share, automatic-eda, chapters, versioned, no-cut, slides, python-pptx, datascience, python] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [os, "python-pptx", "datascience.automatic_eda"] params: - name: chapters_or_profile desc: "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. Lectura defensiva: lo no reconocido se degrada a Note, nunca lanza." - name: out_path desc: "ruta del archivo PPTX de salida. Los directorios padre se crean si faltan. Directorio no escribible → {path:None, note:} sin lanzar." - name: meta desc: "dict opcional. Claves: title (título), ctx (contexto de presentación para los builders de capítulo cuando se da un profile), manifest_path (override; por defecto automatic_eda_manifest.json junto a out_path), write_manifest (False para no escribirlo), generated_at." output: "dict (nunca lanza): {path: str|None, n_slides: int, chapters: list[{id,version,n_slides}], manifest_path: str|None, note: str}. En error fatal (incluida python-pptx no instalada) path es None y note explica la causa." tested: true tests: ["test_golden_profile_genera_pptx_portada_y_overview", "test_edge_tabla_larga_parte_repitiendo_cabecera_sin_cortar", "test_edge_profile_none_y_vacio_un_slide", "test_error_path_directorio_no_escribible_no_revienta"] test_file_path: "python/functions/datascience/render_automatic_eda_pptx_test.py" file_path: "python/functions/datascience/render_automatic_eda_pptx.py" --- ## Ejemplo ```python from datascience import render_automatic_eda_pptx # Desde un TableProfile del grupo eda (mismo modelo que el renderer PDF). 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_pptx( profile, "reports/ventas_aeda.pptx", {"title": "EDA — ventas", "ctx": {"dataset_name": "Ventas", "source_origin": "ERP export"}}) print(res["n_slides"], res["chapters"], res["manifest_path"]) # -> 3 [{'id':'portada','version':'1.0.0','n_slides':1}, # {'id':'overview','version':'1.0.0','n_slides':2}] reports/automatic_eda_manifest.json ``` ## Cuando usarla Cuando quieras **compartir el EDA como una presentación** (no para móvil sino para enseñar a alguien): mismo documento por capítulos que el PDF, emitido como PPTX 16:9. Úsala junto a `render_automatic_eda_pdf` para que cada EDA tenga sus dos salidas (PDF móvil + PPTX para compartir) desde el mismo modelo de capítulos. Garantiza no-corte: ningún texto, tabla ni imagen se recorta — lo que no cabe en una slide continúa en otra `(cont.)` con la cabecera repetida en las tablas. Para añadir capítulos nuevos al documento, ver `docs/capabilities/automatic_eda.md`. ## Gotchas - **Impura**: escribe el PPTX en `out_path` y, salvo `meta['write_manifest']=False`, el manifiesto `automatic_eda_manifest.json` junto a la salida. - **Dependencia python-pptx**: declarada en `python/pyproject.toml` (`python-pptx>=1.0.2`). Si no está instalada, devuelve `{path: None, note: 'python-pptx no disponible: ...'}` sin lanzar. Instalar: `uv pip install --python python/.venv/bin/python3 python-pptx`. - **Nunca lanza** (dict-no-throw): un bloque que falle se omite y se anota en `note`; el deck se genera igual. Un profile `None`/`{}` produce un deck de 1 slide válido. - **No corta nada**: cada bloque se mide; si no cabe en la slide actual, abre una slide `(cont.)`. Las tablas largas se parten por filas **repitiendo la cabecera** (las filas restantes pasan a la siguiente slide). Las figuras matplotlib se exportan a PNG en memoria y se insertan escaladas para caber enteras (nunca recortadas). - **Figuras**: un bloque `figure` puede traer una `matplotlib.figure.Figure` ya construida o un callable `make` (se construye perezosamente). Se cierra tras rasterizar. Las imágenes (`image`) por ruta se escalan manteniendo el aspecto. - **Tablas anchas**: con muchas columnas el ancho por columna se reduce y el texto se envuelve dentro de la celda (sigue sin perderse). El reparto por grupos de columnas para tablas muy anchas es mejora pendiente.