import marimo __generated_with = "0.15.2" app = marimo.App(width="medium") @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(): # import marimo as mo import sys import subprocess import importlib import pandas as pd import altair as alt # Instalación perezosa de drawdata si no está disponible def _ensure(pkg: str): try: importlib.import_module(pkg) except ImportError: subprocess.check_call([sys.executable, "-m", "pip", "install", pkg, "--quiet"]) _ensure("drawdata") from drawdata import ScatterWidget, BarWidget # API principal return BarWidget, ScatterWidget @app.cell def _(mo): mode_selector = mo.ui.radio( options=["Scatter", "Barras"], value="Scatter", label="Modo de dibujo" ) mode_selector return (mode_selector,) @app.cell def _(BarWidget, ScatterWidget, mo): # Creamos ambos widgets una sola vez y los reusamos reactivamente scatter_widget = ScatterWidget() bar_widget = BarWidget( collection_names=["Serie A", "Serie B"], # nombres de colecciones (series) n_bins=20 # nº de bins para eje X ) mo.md("Widgets inicializados. Usa el selector para mostrar uno u otro.") return bar_widget, scatter_widget @app.cell def _(bar_widget, mode_selector, scatter_widget): # Importante en marimo: leer .value en celda separada current_widget = scatter_widget if mode_selector.value == "Scatter" else bar_widget current_widget return @app.cell def _(bar_widget, mo, mode_selector, scatter_widget): # Para ScatterWidget y BarWidget existe .data_as_pandas # En scatter: columnas típicas x, y, color # En barras: columnas por bin/serie/valor (según widget) df_drawn = (scatter_widget.data_as_pandas if mode_selector.value == "Scatter" else bar_widget.data_as_pandas) # Validación básica is_empty = (df_drawn is None) or (len(df_drawn) == 0) mo.stop(is_empty, mo.md("Dibuja puntos (Scatter) o columnas (Barras) para ver datos.")) # Vista tabular interactiva mo.ui.dataframe(df_drawn) return (df_drawn,) @app.cell def _(df_drawn, mode_selector): # Nota: todo está encapsulado en funciones locales para evitar redefinir variables globales. def _build_chart_c6(df, mode): import altair as alt import marimo as mo # Si no hay datos, mostramos aviso if df is None or len(df) == 0: return mo.md("Dibuja datos para visualizar el gráfico.") # Mapeo robusto (lower -> original) DENTRO de la función orig_cols = list(df.columns) lower_map = {str(c).lower(): c for c in orig_cols} if mode == "Scatter": x_col = lower_map.get("x", orig_cols[0]) y_col = lower_map.get("y", orig_cols[1 if len(orig_cols) > 1 else 0]) color_col = lower_map.get("color", None) chart_scatter = ( alt.Chart(df) .mark_point(filled=True, opacity=0.8, size=80) .encode( x=alt.X(x_col, title=str(x_col)), y=alt.Y(y_col, title=str(y_col)), color=alt.Color(color_col, title=str(color_col)) if color_col else alt.value("steelblue"), tooltip=orig_cols ) .properties(title="Dispersión dibujada (reactivo)") .interactive() ) return chart_scatter else: # Barras: detectar bin/x, value/y y collection/serie si existe bin_col = lower_map.get("bin") or lower_map.get("x") or orig_cols[0] val_col = lower_map.get("value") or lower_map.get("y") or (orig_cols[1] if len(orig_cols) > 1 else orig_cols[0]) serie_col = ( lower_map.get("collection") or lower_map.get("serie") or lower_map.get("series") or lower_map.get("group") or None ) base = alt.Chart(df).encode( x=alt.X(bin_col, title=str(bin_col)), y=alt.Y(val_col, title=str(val_col)), tooltip=orig_cols ) chart_bars = ( base.mark_bar() .encode(color=alt.Color(serie_col, title=str(serie_col)) if serie_col else alt.value("steelblue")) .properties(title="Barras dibujadas (reactivo)") .interactive() ) return chart_bars # Construimos el gráfico en una variable y la devolvemos como última expresión _chart_c6_output = _build_chart_c6(df_drawn, mode_selector.value) _chart_c6_output return @app.cell def _(df_drawn, mode_selector, scatter_widget): # También encapsulado para no chocar con nombres de otras celdas. def _prepare_ml_or_matrix_c7(df, mode): import pandas as pd import marimo as mo if df is None or len(df) == 0: return mo.md("No hay datos para preparar. Dibuja primero en el lienzo.") if mode == "Scatter": xy = getattr(scatter_widget, "data_as_X_y", None) if (xy is None) or (xy[0] is None) or (xy[1] is None): return mo.md("Añade puntos en el scatter para obtener X, y.") X, y = xy n_feats = X.shape[1] if hasattr(X, "shape") and len(X.shape) > 1 else 1 if n_feats == 1: x_cols = ["x"] elif n_feats == 2: x_cols = ["x", "y"] else: x_cols = [f"x{i+1}" for i in range(n_feats)] preview = pd.DataFrame(X, columns=x_cols) preview["target"] = y return mo.vstack([ mo.md(f"Listo para ML — **X**: {getattr(X, 'shape', '')}, **y**: {getattr(y, 'shape', '')}"), mo.ui.dataframe(preview.head(20)) ]) else: # Barras → matriz (filas=bins, columnas=series) o columna única si no hay series orig_cols = list(df.columns) lower_map = {str(c).lower(): c for c in orig_cols} bin_col = lower_map.get("bin") or lower_map.get("x") or orig_cols[0] val_col = lower_map.get("value") or lower_map.get("y") or (orig_cols[-1] if len(orig_cols) > 1 else orig_cols[0]) serie_col = ( lower_map.get("collection") or lower_map.get("serie") or lower_map.get("series") or lower_map.get("group") or None ) if serie_col: mat_df = df.pivot_table(index=bin_col, columns=serie_col, values=val_col, fill_value=0, aggfunc="sum").sort_index() else: mat_df = df[[bin_col, val_col]].set_index(bin_col).sort_index() return mo.vstack([ mo.md(f"Matriz lista para modelar/featurear — forma: **{mat_df.shape}**"), mo.ui.dataframe(mat_df.reset_index().head(50)) ]) _ml_matrix_c7_output = _prepare_ml_or_matrix_c7(df_drawn, mode_selector.value) _ml_matrix_c7_output return @app.cell def _(): return if __name__ == "__main__": app.run()