Add drawing and visualization applications with Marimo framework
- Implement dibujar.py for drawing functionality with base64 and PIL image rendering. - Create dibujar_retropaint.py for retro painting features using the Paint widget. - Develop draw_data.py to visualize data with Scatter and Bar widgets, including lazy installation of dependencies. - Add layout configuration for graphical representations in layouts/Graficos_plotly.grid.json. - Enhance shell interaction with mejora_shell_mowidget.py, allowing local library imports and script execution. - Introduce primera_prueba_shell_mowidget.py for testing shell commands and user input handling. - Create prueba_de_embeddings.py for embedding visualizations using Sentence Transformers and dimensionality reduction techniques. - Implement pygwalker_visualizaciones.py for interactive data exploration and visualization using Pygwalker. - Add a sample bash script for user input and ping functionality in scripts/mi_script.sh.
This commit is contained in:
@@ -0,0 +1,132 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
|
||||||
|
import os, sys, importlib, subprocess, shutil
|
||||||
|
|
||||||
|
def _have(mod: str) -> bool:
|
||||||
|
try:
|
||||||
|
importlib.import_module(mod)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _install_with_uv(spec: str) -> bool:
|
||||||
|
uv = shutil.which("uv")
|
||||||
|
if uv:
|
||||||
|
subprocess.check_call([uv, "pip", "install", spec])
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _install_with_pip(spec: str) -> bool:
|
||||||
|
# intenta habilitar pip si no existe
|
||||||
|
try:
|
||||||
|
import ensurepip # noqa: F401
|
||||||
|
ensurepip.bootstrap()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
pip_exe = shutil.which("pip") or shutil.which("pip3")
|
||||||
|
if pip_exe:
|
||||||
|
subprocess.check_call([pip_exe, "install", spec])
|
||||||
|
return True
|
||||||
|
|
||||||
|
# último recurso: python -m pip
|
||||||
|
try:
|
||||||
|
subprocess.check_call([sys.executable, "-m", "pip", "install", spec])
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def ensure_pkg(spec: str, module: str | None = None):
|
||||||
|
module = module or spec
|
||||||
|
if _have(module):
|
||||||
|
return
|
||||||
|
if _install_with_uv(spec):
|
||||||
|
return
|
||||||
|
if _install_with_pip(spec):
|
||||||
|
return
|
||||||
|
raise RuntimeError(
|
||||||
|
f"No pude instalar {spec}. Instálalo manualmente con `uv pip install {spec}`."
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- instala dependencias ---
|
||||||
|
# bavisitter desde PyPI; si falla, cae al repo de GitHub
|
||||||
|
try:
|
||||||
|
ensure_pkg("bavisitter", "bavisitter")
|
||||||
|
except Exception:
|
||||||
|
ensure_pkg("git+https://github.com/jiwnchoi/Bavisitter.git", "bavisitter")
|
||||||
|
|
||||||
|
for spec in [("pandas","pandas"), ("altair","altair"), ("vega_datasets","vega_datasets")]:
|
||||||
|
ensure_pkg(spec[0], spec[1])
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
import altair as alt
|
||||||
|
from vega_datasets import data
|
||||||
|
return data, mo, os
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
# Cell 2
|
||||||
|
api_key_input = mo.ui.text(value="", label="OPENAI_API_KEY (opcional aquí; si ya está en el entorno, deja vacío)", full_width=True)
|
||||||
|
model_dd = mo.ui.dropdown(
|
||||||
|
options=["gpt-4o", "gpt-4o-mini", "gpt-4.1", "gpt-4o-reasoning"],
|
||||||
|
value="gpt-4o",
|
||||||
|
label="Modelo"
|
||||||
|
)
|
||||||
|
theme_dd = mo.ui.radio(options=["light", "dark"], value="light", label="Tema de Bavisitter")
|
||||||
|
launch_btn = mo.ui.run_button(label="Lanzar Bavisitter")
|
||||||
|
|
||||||
|
mo.vstack([api_key_input, mo.hstack([model_dd, theme_dd]), launch_btn])
|
||||||
|
|
||||||
|
return api_key_input, launch_btn, model_dd, theme_dd
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(data, mo):
|
||||||
|
movies_df = data.movies()
|
||||||
|
# Se muestra automáticamente como tabla si es la última expresión:
|
||||||
|
mo.ui.dataframe(movies_df)
|
||||||
|
return (movies_df,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(api_key_input, launch_btn, mo, model_dd, movies_df, os, theme_dd):
|
||||||
|
# Cell 4
|
||||||
|
from bavisitter import Bavisitter
|
||||||
|
|
||||||
|
# Si se pulsa el botón, configuramos la API key (si el usuario la introdujo)
|
||||||
|
if api_key_input.value:
|
||||||
|
os.environ["OPENAI_API_KEY"] = api_key_input.value
|
||||||
|
|
||||||
|
# Validaciones mínimas
|
||||||
|
has_key = bool(os.environ.get("OPENAI_API_KEY", "").strip())
|
||||||
|
mo.stop(not launch_btn.value, mo.md("Pulsa **Lanzar Bavisitter** para iniciar."))
|
||||||
|
mo.stop(not has_key, mo.md("Falta **OPENAI_API_KEY**. Escríbela en la celda de arriba o expórtala en el entorno."))
|
||||||
|
|
||||||
|
# Instanciar Bavisitter con el dataset de ejemplo y los parámetros elegidos
|
||||||
|
app = Bavisitter(
|
||||||
|
movies_df,
|
||||||
|
model=model_dd.value,
|
||||||
|
color_mode=theme_dd.value
|
||||||
|
)
|
||||||
|
app # Bavisitter renderiza su interfaz; úsala para pedir gráficos, detectar y resolver problemas de diseño
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(os):
|
||||||
|
os.environ["OPENAI_API_KEY"]
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.1"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
from d2_widget import Widget
|
||||||
|
import pathlib
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
|
return Widget, mo, pathlib
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell(hide_code=True)
|
||||||
|
def _(mo):
|
||||||
|
# Definición por defecto (puedes editarla en el textarea)
|
||||||
|
d2_source_default = """
|
||||||
|
# Ajustes de layout
|
||||||
|
direction: right
|
||||||
|
|
||||||
|
# Nodos
|
||||||
|
app: {
|
||||||
|
label: "Ingesta"
|
||||||
|
shape: rectangle
|
||||||
|
}
|
||||||
|
db: {
|
||||||
|
label: "PostgreSQL"
|
||||||
|
shape: cylinder
|
||||||
|
}
|
||||||
|
dashboard: {
|
||||||
|
label: "Metabase"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enlaces
|
||||||
|
app -> db: "escribe"
|
||||||
|
db -> dashboard: "lee"
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Widgets de UI
|
||||||
|
editor = mo.ui.text_area(value=d2_source_default, label="Definición D2", full_width=True)
|
||||||
|
theme_id = mo.ui.number(value=200, label="themeID (D2)")
|
||||||
|
pad_px = mo.ui.number(value=8, label="Padding")
|
||||||
|
sketch_mode = mo.ui.checkbox(label="Sketch (boceto)", value=False)
|
||||||
|
animate_edges = mo.ui.checkbox(label="Animar aristas", value=True)
|
||||||
|
|
||||||
|
export_name = mo.ui.text(value="diagrama.svg", label="Archivo SVG")
|
||||||
|
export_button = mo.ui.run_button(label="Exportar SVG")
|
||||||
|
|
||||||
|
# Layout
|
||||||
|
mo.ui.tabs({
|
||||||
|
"Editor": mo.vstack([
|
||||||
|
mo.md("## Diagrama D2"),
|
||||||
|
editor,
|
||||||
|
]),
|
||||||
|
"Opciones": mo.vstack([
|
||||||
|
mo.hstack([theme_id, pad_px, sketch_mode, animate_edges], justify="start", gap="1rem"),
|
||||||
|
mo.md("Configura opciones del compilador D2."),
|
||||||
|
]),
|
||||||
|
"Exportar": mo.vstack([
|
||||||
|
mo.hstack([export_name, export_button], gap="1rem"),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
|
||||||
|
return editor, export_button, export_name, pad_px, sketch_mode, theme_id
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(pad_px, sketch_mode, theme_id):
|
||||||
|
compile_options = {
|
||||||
|
"themeID": int(theme_id.value),
|
||||||
|
"pad": int(pad_px.value),
|
||||||
|
"sketch": bool(sketch_mode.value),
|
||||||
|
}
|
||||||
|
|
||||||
|
return (compile_options,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(Widget, compile_options, editor):
|
||||||
|
diagram_widget = Widget(editor.value, compile_options)
|
||||||
|
diagram_widget
|
||||||
|
return (diagram_widget,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(diagram_widget, export_button, export_name, mo, pathlib):
|
||||||
|
if export_button.value:
|
||||||
|
svg_text = diagram_widget.svg
|
||||||
|
out_path = pathlib.Path(export_name.value)
|
||||||
|
out_path.write_text(svg_text, encoding="utf-8")
|
||||||
|
mo.md(f"### SVG exportado\n[Descargar SVG]({out_path})")
|
||||||
|
else:
|
||||||
|
mo.md("Pulsa **Exportar SVG** para guardar el archivo.")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.1"
|
||||||
|
app = marimo.App(width="columns")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell(column=0)
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
from vega_datasets import data
|
||||||
|
import altair as alt
|
||||||
|
import pandas as pd
|
||||||
|
import pyarrow
|
||||||
|
return alt, data, mo, pd
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
mo.md(r"""Visualizacion de barras categóricas Pudiendo seleccionar una""")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, mo, pd):
|
||||||
|
|
||||||
|
dataset = pd.DataFrame([
|
||||||
|
{"a": "A", "b": 28},
|
||||||
|
{"a": "B", "b": 55},
|
||||||
|
{"a": "C", "b": 43},
|
||||||
|
{"a": "D", "b": 91},
|
||||||
|
{"a": "E", "b": 81},
|
||||||
|
{"a": "F", "b": 53},
|
||||||
|
{"a": "G", "b": 19},
|
||||||
|
{"a": "H", "b": 87},
|
||||||
|
{"a": "I", "b": 52},
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
_x = "a:O" # categórica
|
||||||
|
_y = "b:Q" # numérica
|
||||||
|
|
||||||
|
# Selección solo por clic
|
||||||
|
select1 = alt.selection_point(name="select", on="click")
|
||||||
|
|
||||||
|
stroke_width1 = (
|
||||||
|
alt.when(select1).then(alt.value(2, empty=False)).otherwise(alt.value(0))
|
||||||
|
)
|
||||||
|
|
||||||
|
_bar_chart1 = (
|
||||||
|
alt.Chart(
|
||||||
|
dataset,
|
||||||
|
height=200,
|
||||||
|
config=alt.Config(scale=alt.ScaleConfig(bandPaddingInner=0.2)),
|
||||||
|
)
|
||||||
|
.mark_bar(fill="#4C78A8", stroke="black", cursor="pointer")
|
||||||
|
.encode(
|
||||||
|
x= _x,
|
||||||
|
y= _y,
|
||||||
|
fillOpacity=alt.when(select1).then(alt.value(1)).otherwise(alt.value(0.3)),
|
||||||
|
strokeWidth=stroke_width1,
|
||||||
|
)
|
||||||
|
.add_params(select1)
|
||||||
|
)
|
||||||
|
|
||||||
|
bar_chart1 = mo.ui.altair_chart(_bar_chart1)
|
||||||
|
bar_chart1
|
||||||
|
|
||||||
|
return bar_chart1, dataset
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(bar_chart1, dataset, mo):
|
||||||
|
filtered_data1 = mo.ui.table(bar_chart1.value if len(bar_chart1.value) else dataset)
|
||||||
|
filtered_data1
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
mo.md(r"""Visualización de barras categóricas con media pudiéndose seleccionar varias""")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, data, mo):
|
||||||
|
|
||||||
|
dataset_weather = data.seattle_weather()
|
||||||
|
|
||||||
|
# Crear columnas explícitas de mes para evitar errores en marimo
|
||||||
|
dataset_weather2 = dataset_weather.copy()
|
||||||
|
dataset_weather2["month_date"] = dataset_weather2["date"].dt.month
|
||||||
|
dataset_weather2["month_name"] = dataset_weather2["date"].dt.strftime("%b") # Ej: Jan, Feb...
|
||||||
|
|
||||||
|
# Variables X y Y
|
||||||
|
_x = "month_name:O" # categórica
|
||||||
|
_y = "mean(precipitation):Q" # numérica
|
||||||
|
|
||||||
|
# Selección por intervalo (brush) en el eje X
|
||||||
|
brush2 = alt.selection_interval(encodings=["x"])
|
||||||
|
|
||||||
|
bars2 = (
|
||||||
|
alt.Chart(dataset_weather2)
|
||||||
|
.mark_bar()
|
||||||
|
.encode(
|
||||||
|
x=_x,
|
||||||
|
y=_y,
|
||||||
|
opacity=alt.when(brush2).then(alt.value(1)).otherwise(alt.value(0.7)),
|
||||||
|
)
|
||||||
|
.add_params(brush2)
|
||||||
|
)
|
||||||
|
|
||||||
|
line2 = (
|
||||||
|
alt.Chart(dataset_weather2)
|
||||||
|
.mark_rule(color="firebrick")
|
||||||
|
.encode(
|
||||||
|
y=_y,
|
||||||
|
size=alt.SizeValue(3),
|
||||||
|
)
|
||||||
|
.transform_filter(brush2)
|
||||||
|
)
|
||||||
|
|
||||||
|
layered_chart2 = alt.layer(bars2, line2)
|
||||||
|
|
||||||
|
weather_chart2 = mo.ui.altair_chart(layered_chart2)
|
||||||
|
weather_chart2
|
||||||
|
|
||||||
|
return dataset_weather2, weather_chart2
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(dataset_weather2, mo, weather_chart2):
|
||||||
|
filtered_weather2 = mo.ui.table(weather_chart2.value if len(weather_chart2.value) else dataset_weather2)
|
||||||
|
filtered_weather2
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell(column=1)
|
||||||
|
def _(mo):
|
||||||
|
mo.md(r"""Gráfico con agrupación en Slider""")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, data, mo):
|
||||||
|
# from vega_datasets import data
|
||||||
|
|
||||||
|
# Cargar dataset
|
||||||
|
dataset_movies3 = data.movies()
|
||||||
|
|
||||||
|
# Variables X e Y
|
||||||
|
_x = "IMDB_Rating:Q" # numérica
|
||||||
|
_y = "Rotten_Tomatoes_Rating:Q" # numérica
|
||||||
|
|
||||||
|
# Slider de Altair (param embebido en el gráfico)
|
||||||
|
slider_binding3 = alt.binding_range(min=0, max=10, step=0.1)
|
||||||
|
threshold3 = alt.param(name="threshold3", value=5, bind=slider_binding3)
|
||||||
|
|
||||||
|
# Capa 1: puntos con IMDB >= threshold
|
||||||
|
points3 = (
|
||||||
|
alt.Chart(dataset_movies3)
|
||||||
|
.mark_circle()
|
||||||
|
.encode(
|
||||||
|
x=alt.X(_x, title="IMDB Rating"),
|
||||||
|
y=alt.Y(_y, title="Rotten Tomatoes Rating")
|
||||||
|
)
|
||||||
|
.transform_filter(
|
||||||
|
alt.datum.IMDB_Rating >= threshold3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Capa 2: puntos agregados con IMDB < threshold
|
||||||
|
binned3 = (
|
||||||
|
alt.Chart(dataset_movies3)
|
||||||
|
.mark_circle()
|
||||||
|
.encode(
|
||||||
|
x=alt.X(_x, bin=alt.Bin(maxbins=10)),
|
||||||
|
y=alt.Y(_y, bin=alt.Bin(maxbins=10)),
|
||||||
|
size=alt.Size("count():Q", scale=alt.Scale(domain=[0,160]))
|
||||||
|
)
|
||||||
|
.transform_filter(
|
||||||
|
alt.datum.IMDB_Rating < threshold3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Capa 3: regla vertical del threshold
|
||||||
|
rule3 = (
|
||||||
|
alt.Chart()
|
||||||
|
.mark_rule(color="gray")
|
||||||
|
.encode(
|
||||||
|
strokeWidth=alt.StrokeWidth(value=6),
|
||||||
|
x=alt.X(datum=alt.expr(threshold3.name), type="quantitative")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Combinar capas
|
||||||
|
layered_movies3 = alt.layer(points3, binned3, rule3).add_params(threshold3)
|
||||||
|
|
||||||
|
movies_chart3 = mo.ui.altair_chart(layered_movies3)
|
||||||
|
movies_chart3
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
mo.md(r"""Altair está trabajando bien en marimor pero aún tiene algunas partes por pulir como por ejemplo la capacidad de tener dos gráficos En una misma celda También tiene problemas a la hora de tener Y filtrar En diferentes celdas además de pasar datos como por ejemplo el Slider""")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, data, mo):
|
||||||
|
# Dataset
|
||||||
|
dataset_movies4 = data.movies()
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
x1 = "IMDB_Rating:Q" # numérica
|
||||||
|
y1 = "Rotten_Tomatoes_Rating:Q" # numérica
|
||||||
|
|
||||||
|
# Selección
|
||||||
|
pts4 = alt.selection_point(encodings=['x'], name="pts4")
|
||||||
|
|
||||||
|
# Heatmap base
|
||||||
|
rect4 = (
|
||||||
|
alt.Chart(dataset_movies4)
|
||||||
|
.mark_rect()
|
||||||
|
.encode(
|
||||||
|
x=alt.X(x1, bin=True),
|
||||||
|
y=alt.Y(y1, bin=True),
|
||||||
|
color=alt.Color(
|
||||||
|
"count()",
|
||||||
|
scale=alt.Scale(scheme="greenblue"),
|
||||||
|
legend=alt.Legend(title="Total Records")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.properties(width=550, height=300)
|
||||||
|
)
|
||||||
|
|
||||||
|
movies_rect4 = mo.ui.altair_chart(rect4.add_params(pts4))
|
||||||
|
movies_rect4
|
||||||
|
|
||||||
|
return dataset_movies4, pts4, x1, y1
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, dataset_movies4, mo, pts4, x1, y1):
|
||||||
|
circ4 = (
|
||||||
|
alt.Chart(dataset_movies4)
|
||||||
|
.mark_point(color="grey")
|
||||||
|
.encode(
|
||||||
|
x=alt.X(x1, bin=True),
|
||||||
|
y=alt.Y(y1, bin=True),
|
||||||
|
size=alt.Size("count()", legend=alt.Legend(title="Records in Selection"))
|
||||||
|
)
|
||||||
|
.transform_filter(pts4)
|
||||||
|
.properties(width=550, height=300)
|
||||||
|
)
|
||||||
|
|
||||||
|
movies_circ4 = mo.ui.altair_chart(circ4)
|
||||||
|
movies_circ4
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(
|
||||||
|
width="medium",
|
||||||
|
layout_file="layouts/Graficos_plotly.grid.json",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
# Cell 1: gráfico Plotly (reactivo)
|
||||||
|
import marimo as mo
|
||||||
|
import pandas as pd
|
||||||
|
import plotly.express as px
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
df = pd.read_json("https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json")
|
||||||
|
|
||||||
|
fig = px.scatter(
|
||||||
|
df,
|
||||||
|
x="Horsepower",
|
||||||
|
y="Miles_per_Gallon",
|
||||||
|
color="Origin",
|
||||||
|
hover_data=["Name"],
|
||||||
|
)
|
||||||
|
|
||||||
|
plot = mo.ui.plotly(fig) # Solo scatter/treemap/sunburst soportan selección reactiva
|
||||||
|
plot
|
||||||
|
return df, mo, np, pd, plot, px
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(df, plot):
|
||||||
|
# Cell 2: dataset filtrado (reactivo e interactivo)
|
||||||
|
# marimo vuelve a ejecutar esta celda cuando cambia la selección del gráfico
|
||||||
|
indices = plot.indices # lista de int con las filas seleccionadas
|
||||||
|
selected_df = df.iloc[indices] if indices else df
|
||||||
|
|
||||||
|
# Visor interactivo con búsqueda/ordenación/filtros integrados
|
||||||
|
selected_df
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(pd):
|
||||||
|
# Cell 2 • datos base (Vega cars)
|
||||||
|
cars_df = pd.read_json("https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json")
|
||||||
|
cars_df["Year"] = pd.to_datetime(cars_df["Year"])
|
||||||
|
cars_df["Horsepower_num"] = pd.to_numeric(cars_df["Horsepower"], errors="coerce")
|
||||||
|
numeric_cols = ["Miles_per_Gallon","Horsepower_num","Weight_in_lbs","Acceleration","Displacement"]
|
||||||
|
cars_df
|
||||||
|
return cars_df, numeric_cols
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(cars_df, mo, np):
|
||||||
|
# Cell 3 • controles UI (reactivos)
|
||||||
|
origin_dd = mo.ui.dropdown(options=["All"] + sorted(cars_df["Origin"].dropna().unique().tolist()),
|
||||||
|
value="All", label="Origin")
|
||||||
|
year_min = int(cars_df["Year"].dt.year.min())
|
||||||
|
year_max = int(cars_df["Year"].dt.year.max())
|
||||||
|
year_rg = mo.ui.range_slider(year_min, year_max, value=(year_min, year_max), step=1, label="Year range")
|
||||||
|
hp_min = int(np.nanmin(cars_df["Horsepower_num"]))
|
||||||
|
hp_max = int(np.nanmax(cars_df["Horsepower_num"]))
|
||||||
|
hp_rg = mo.ui.range_slider(hp_min, hp_max, value=(hp_min, hp_max), step=5, label="Horsepower range")
|
||||||
|
bins_sl = mo.ui.slider(5, 60, value=20, step=1, label="Bins (hist)")
|
||||||
|
y_metric = mo.ui.radio(options=["Miles_per_Gallon","Horsepower_num","Weight_in_lbs","Acceleration","Displacement"],
|
||||||
|
value="Miles_per_Gallon", label="Y metric (box)")
|
||||||
|
mo.hstack([origin_dd, year_rg, hp_rg, bins_sl, y_metric])
|
||||||
|
return bins_sl, hp_rg, origin_dd, y_metric, year_rg
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(cars_df, hp_rg, origin_dd, year_rg):
|
||||||
|
# Cell 4 • dataframe filtrado (base para los 5 gráficos)
|
||||||
|
df_filtrado = cars_df.copy()
|
||||||
|
if origin_dd.value != "All":
|
||||||
|
df_filtrado = df_filtrado[df_filtrado["Origin"] == origin_dd.value]
|
||||||
|
df_filtrado = df_filtrado[
|
||||||
|
(df_filtrado["Year"].dt.year >= year_rg.value[0]) &
|
||||||
|
(df_filtrado["Year"].dt.year <= year_rg.value[1]) &
|
||||||
|
(df_filtrado["Horsepower_num"].between(hp_rg.value[0], hp_rg.value[1]))
|
||||||
|
].dropna(subset=["Miles_per_Gallon","Horsepower_num"])
|
||||||
|
df_filtrado
|
||||||
|
return (df_filtrado,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(df_filtrado, mo, px):
|
||||||
|
# Cell 5 • (1) Line chart: media de MPG por año y origen
|
||||||
|
line_df = (df_filtrado
|
||||||
|
.assign(YearNum=df_filtrado["Year"].dt.year)
|
||||||
|
.groupby(["YearNum","Origin"], as_index=False)["Miles_per_Gallon"].mean())
|
||||||
|
line_fig1 = px.line(line_df, x="YearNum", y="Miles_per_Gallon", color="Origin",
|
||||||
|
markers=True, title="MPG medio por año")
|
||||||
|
line_plot1 = mo.ui.plotly(line_fig1)
|
||||||
|
line_plot1
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(bins_sl, df_filtrado, mo, px):
|
||||||
|
# Cell 6 • (2) Histogram: distribución de Horsepower (nbins reactivo)
|
||||||
|
hist_fig1 = px.histogram(df_filtrado, x="Horsepower_num", nbins=bins_sl.value,
|
||||||
|
color="Origin", title="Distribución de Horsepower")
|
||||||
|
hist_plot1 = mo.ui.plotly(hist_fig1)
|
||||||
|
hist_plot1
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(df_filtrado, mo, px, y_metric):
|
||||||
|
# Cell 7 • (3) Box plot: métrica Y por Origin (métrica reactiva)
|
||||||
|
box_fig1 = px.box(df_filtrado, x="Origin", y=y_metric.value, points="outliers",
|
||||||
|
title=f"Distribución de {y_metric.value} por Origin")
|
||||||
|
box_plot1 = mo.ui.plotly(box_fig1)
|
||||||
|
box_plot1
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(df_filtrado, mo, px):
|
||||||
|
# Cell 8 • (4) Density heatmap: Horsepower vs MPG
|
||||||
|
heat_fig1 = px.density_heatmap(df_filtrado, x="Horsepower_num", y="Miles_per_Gallon",
|
||||||
|
nbinsx=40, nbinsy=30, title="Densidad HP vs MPG")
|
||||||
|
heat_plot1 = mo.ui.plotly(heat_fig1)
|
||||||
|
heat_plot1
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(df_filtrado, mo, numeric_cols, px):
|
||||||
|
# Cell 9 • (5) Scatter matrix: relación entre variables numéricas
|
||||||
|
splom_fig1 = px.scatter_matrix(df_filtrado[numeric_cols], dimensions=numeric_cols,
|
||||||
|
title="Scatter Matrix de variables numéricas")
|
||||||
|
splom_plot1 = mo.ui.plotly(splom_fig1)
|
||||||
|
splom_plot1
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
import polars as pl
|
||||||
|
import quak
|
||||||
|
return mo, pl, quak
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo, pl, quak):
|
||||||
|
src = "https://github.com/uwdata/mosaic/raw/main/data/athletes.parquet"
|
||||||
|
df = pl.read_parquet(src) # Cambialo por tu dataframe
|
||||||
|
q = quak.Widget(df)
|
||||||
|
mo.ui.anywidget(q)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, df, df_base, mo, slider_2d):
|
||||||
|
chart = (
|
||||||
|
alt.Chart(df_base).mark_point(color="gray").encode(x="x", y="y") +
|
||||||
|
alt.Chart(df).mark_point().encode(x="x", y="y")
|
||||||
|
).properties(width=300, height=300)
|
||||||
|
|
||||||
|
mo.vstack([
|
||||||
|
mo.md("""
|
||||||
|
## `Slider2D` demo
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import Slider2D
|
||||||
|
|
||||||
|
slider_2d = Slider2D(width=300, height=300)
|
||||||
|
```
|
||||||
|
|
||||||
|
This demo contains a two dimensional slider. The thinking is that sometimes you want to be able to make changes to two variables at the same time. The output is always standardized to the range of -1 to 1, but you can always use custom code to adapt this."""),
|
||||||
|
mo.hstack([slider_2d, chart])
|
||||||
|
])
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, arr, df_orig, mat, mo, np, pd):
|
||||||
|
x_sim = np.random.multivariate_normal(
|
||||||
|
np.array(arr.matrix).reshape(-1),
|
||||||
|
np.array(mat.matrix),
|
||||||
|
2500
|
||||||
|
)
|
||||||
|
df_sim = pd.DataFrame({"x": x_sim[:, 0], "y": x_sim[:, 1]})
|
||||||
|
|
||||||
|
chart_sim = (
|
||||||
|
alt.Chart(df_sim).mark_point().encode(x="x", y="y") +
|
||||||
|
alt.Chart(df_orig).mark_point(color="gray").encode(x="x", y="y")
|
||||||
|
)
|
||||||
|
|
||||||
|
mo.vstack([
|
||||||
|
mo.md("""
|
||||||
|
## `Matrix` demo
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import Matrix
|
||||||
|
|
||||||
|
arr = Matrix(rows=1, cols=2, step=0.1)
|
||||||
|
mat = Matrix(matrix=np.eye(2), mirror=True, step=0.1)
|
||||||
|
```
|
||||||
|
|
||||||
|
This demo contains a representation of a two dimensional gaussian distribution. You can adapt the center by changing the first array that represents the mean and the variance can be updated by alterering the second one that represents the covariance matrix. Notice how the latter matrix has a triangular constraint."""),
|
||||||
|
mo.hstack([arr, mat, chart_sim])
|
||||||
|
])
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(Matrix, mo, np, pd):
|
||||||
|
pca_mat = mo.ui.anywidget(Matrix(np.random.normal(0, 1, size=(3, 2)), step=0.1))
|
||||||
|
rgb_mat = np.random.randint(0, 255, size=(1000, 3))
|
||||||
|
color = ["#{0:02x}{1:02x}{2:02x}".format(r, g, b) for r,g,b in rgb_mat]
|
||||||
|
|
||||||
|
rgb_df = pd.DataFrame({
|
||||||
|
"r": rgb_mat[:, 0], "g": rgb_mat[:, 1], "b": rgb_mat[:, 2], 'color': color
|
||||||
|
})
|
||||||
|
return color, pca_mat, rgb_mat
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, color, mo, pca_mat, pd, rgb_mat):
|
||||||
|
X_tfm = rgb_mat @ pca_mat.matrix
|
||||||
|
df_pca = pd.DataFrame({"x": X_tfm[:, 0], "y": X_tfm[:, 1], "c": color})
|
||||||
|
pca_chart = alt.Chart(df_pca).mark_point().encode(x="x", y="y", color=alt.Color('c:N', scale = None))
|
||||||
|
|
||||||
|
mo.vstack([
|
||||||
|
mo.md("""
|
||||||
|
### PCA demo with `Matrix`
|
||||||
|
|
||||||
|
Ever want to do your own PCA? Try to figure out a mapping from a 3d color map to a 2d representation with the transformation matrix below."""),
|
||||||
|
mo.hstack([pca_mat, pca_chart])
|
||||||
|
])
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(c, coffees, mo, price, prob1, prob2, saying, shouting, times, total):
|
||||||
|
mo.vstack([
|
||||||
|
mo.md(f"""
|
||||||
|
## Tangle objects
|
||||||
|
|
||||||
|
Very much inspired by [tangle.js](), this library also offers some sliders/choice elements that can natively be combined in markdown.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import TangleSlider
|
||||||
|
```
|
||||||
|
|
||||||
|
There are some examples below.
|
||||||
|
### Apples example
|
||||||
|
|
||||||
|
Suppose that you have {coffees} and they each cost {price} then in total you would need to spend ${total:.2f}.
|
||||||
|
|
||||||
|
### Amdhals law
|
||||||
|
|
||||||
|
You cannot always get a speedup by throwing more compute at a problem. Let's compare two scenarios.
|
||||||
|
|
||||||
|
- You might have a parallel program that needs to sync up {prob1}.
|
||||||
|
- Another parallel program needs to sync up {prob2}.
|
||||||
|
|
||||||
|
The consequences of these choices are shown below. You might be suprised at the result, but you need to remember that if you throw more cores at the problem then you will also have more cores that will idle when the program needs to sync.
|
||||||
|
|
||||||
|
"""),
|
||||||
|
c,
|
||||||
|
mo.md(f"""
|
||||||
|
### Also a choice widget
|
||||||
|
|
||||||
|
The slider widget can do numeric values for you, but sometimes you also want to make a choice between discrete choices. For that, you can use the `TangleChoice` widget.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import TangleChoice
|
||||||
|
```
|
||||||
|
|
||||||
|
As a quick demo, let's repeat {saying} {times}.
|
||||||
|
|
||||||
|
{" ".join([saying.choice] * int(times.amount))}
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
mo.md(f"""
|
||||||
|
### Also a select widget
|
||||||
|
|
||||||
|
Like `TangleChoice` but as a drop-down
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import TangleSelect
|
||||||
|
```
|
||||||
|
|
||||||
|
As a quick demo, let's repeat {shouting} {times}.
|
||||||
|
|
||||||
|
{" ".join([shouting.choice] * int(times.amount))}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
])
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(color_picker, mo):
|
||||||
|
mo.vstack(
|
||||||
|
[
|
||||||
|
mo.md(f"""
|
||||||
|
## Pick colors
|
||||||
|
|
||||||
|
Pick colors using a standard browser color input.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import ColorPicker
|
||||||
|
ColorPicker(color="#444444")
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use a color picker with marimo's `Html` to affect how things are rendered.
|
||||||
|
"""),
|
||||||
|
mo.Html(f'<p style="color: {color_picker.color}">Change my color!</p>'),
|
||||||
|
mo.hstack([
|
||||||
|
color_picker,
|
||||||
|
mo.md(f"You selected {color_picker.value['color']} which is {color_picker.rgb} in RGB values.")
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(edge_widget, mo):
|
||||||
|
mo.vstack([
|
||||||
|
mo.md(f"""
|
||||||
|
## Drawing Edges
|
||||||
|
|
||||||
|
We even have a tool that allows you to connect nodes by drawing edges!
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import EdgeDraw
|
||||||
|
EdgeDraw(["a", "b", "c", "d"])
|
||||||
|
```
|
||||||
|
|
||||||
|
Try it yourself by drawing below.
|
||||||
|
"""),
|
||||||
|
edge_widget,
|
||||||
|
mo.md(f"""
|
||||||
|
As you draw more nodes, you will also update the `widget.links` property.
|
||||||
|
"""),
|
||||||
|
edge_widget.links
|
||||||
|
|
||||||
|
])
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo, sortable_list):
|
||||||
|
mo.vstack([
|
||||||
|
mo.md("""
|
||||||
|
## Sortable Lists
|
||||||
|
|
||||||
|
```python
|
||||||
|
from wigglystuff import SortableList
|
||||||
|
SortableList(["Action", "Comedy", "Drama"], addable=True, removable=True, editable=True)
|
||||||
|
```
|
||||||
|
|
||||||
|
Try dragging items to reorder, adding new items, clicking to edit, or removing with the [x] buttons.
|
||||||
|
"""),
|
||||||
|
sortable_list,
|
||||||
|
mo.md(f"Current value: `{sortable_list.value}`")
|
||||||
|
])
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
from wigglystuff import EdgeDraw
|
||||||
|
|
||||||
|
edge_widget = mo.ui.anywidget(EdgeDraw(["a", "b", "c", "d"]))
|
||||||
|
return (edge_widget,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(coffees, price):
|
||||||
|
# You need to define derivates in other cells.
|
||||||
|
total = coffees.amount * price.amount
|
||||||
|
return (total,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, np, pd, prob1, prob2):
|
||||||
|
cores = np.arange(1, 64 + 1)
|
||||||
|
p1, p2 = prob1.amount/100, prob2.amount/100
|
||||||
|
eff1 = 1/(p1 + (1-p1)/cores)
|
||||||
|
eff2 = 1/(p2 + (1-p2)/cores)
|
||||||
|
|
||||||
|
df_amdahl = pd.DataFrame({
|
||||||
|
'cores': cores,
|
||||||
|
f'{prob1.amount:.2f}% sync rate': eff1,
|
||||||
|
f'{prob2.amount:.2f}% sync rate': eff2
|
||||||
|
}).melt("cores")
|
||||||
|
|
||||||
|
c = (
|
||||||
|
alt.Chart(df_amdahl)
|
||||||
|
.mark_line()
|
||||||
|
.encode(
|
||||||
|
x='cores',
|
||||||
|
y=alt.Y('value').title("effective cores"),
|
||||||
|
color="variable"
|
||||||
|
)
|
||||||
|
.properties(width=500, title="Comparison between cores and actual speedup.")
|
||||||
|
)
|
||||||
|
return (c,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
from wigglystuff import TangleSlider, TangleChoice, TangleSelect
|
||||||
|
|
||||||
|
coffees = mo.ui.anywidget(TangleSlider(amount=10, min_value=0, step=1, suffix=" coffees", digits=0))
|
||||||
|
price = mo.ui.anywidget(TangleSlider(amount=3.50, min_value=0.01, max_value=10, step=0.01, prefix="$", digits=2))
|
||||||
|
prob1 = mo.ui.anywidget(TangleSlider(min_value=0, max_value=20, step=0.1, suffix="% of the time", amount=5))
|
||||||
|
prob2 = mo.ui.anywidget(TangleSlider(min_value=0, max_value=20, step=0.1, suffix="% of the time", amount=0))
|
||||||
|
saying = mo.ui.anywidget(TangleChoice(["🙂", "🎉", "💥"]))
|
||||||
|
shouting = mo.ui.anywidget(TangleSelect(["🥔", "🥕", "🍎"]))
|
||||||
|
times = mo.ui.anywidget(TangleSlider(min_value=1, max_value=20, step=1, suffix=" times", amount=3))
|
||||||
|
return coffees, price, prob1, prob2, saying, shouting, times
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import altair as alt
|
||||||
|
import marimo as mo
|
||||||
|
import micropip
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# await micropip.install("wigglystuff==0.1.1")
|
||||||
|
return alt, mo, np, pd
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo, np):
|
||||||
|
from wigglystuff import Matrix
|
||||||
|
|
||||||
|
mat = mo.ui.anywidget(Matrix(matrix=np.eye(2), mirror=True, step=0.1))
|
||||||
|
arr = mo.ui.anywidget(Matrix(rows=1, cols=2, step=0.1))
|
||||||
|
return Matrix, arr, mat
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(Matrix, mo, np):
|
||||||
|
x1 = mo.ui.anywidget(Matrix(matrix=np.eye(2), step=0.1))
|
||||||
|
x2 = mo.ui.anywidget(Matrix(matrix=np.random.random((2, 2)), step=0.1))
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
from wigglystuff import Slider2D
|
||||||
|
|
||||||
|
slider_2d = mo.ui.anywidget(Slider2D(width=300, height=300))
|
||||||
|
return (slider_2d,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(np, pd, slider_2d):
|
||||||
|
df = pd.DataFrame({
|
||||||
|
"x": np.random.normal(slider_2d.x * 10, 1, 2000),
|
||||||
|
"y": np.random.normal(slider_2d.y * 10, 1, 2000)
|
||||||
|
})
|
||||||
|
return (df,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(np, pd):
|
||||||
|
df_base = pd.DataFrame({
|
||||||
|
"x": np.random.normal(0, 1, 2000),
|
||||||
|
"y": np.random.normal(0, 1, 2000)
|
||||||
|
})
|
||||||
|
return (df_base,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(np, pd):
|
||||||
|
x_orig = np.random.multivariate_normal(np.array([0, 0]), np.array([[1, 0], [0, 1]]), 2500)
|
||||||
|
df_orig = pd.DataFrame({"x": x_orig[:, 0], "y": x_orig[:, 1]})
|
||||||
|
return (df_orig,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
from wigglystuff import ColorPicker
|
||||||
|
color_picker = mo.ui.anywidget(ColorPicker(color="#444444"))
|
||||||
|
return (color_picker,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
from wigglystuff import SortableList
|
||||||
|
|
||||||
|
sortable_list = mo.ui.anywidget(
|
||||||
|
SortableList(
|
||||||
|
["Action", "Comedy", "Drama", "Thriller", "Sci-Fi"],
|
||||||
|
addable=True,
|
||||||
|
removable=True,
|
||||||
|
editable=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return (sortable_list,)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"metadata": {
|
||||||
|
"marimo_version": "0.15.2"
|
||||||
|
},
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"id": "aoMP",
|
||||||
|
"code_hash": "cc4a4b61a8ee606a4542fe01ac4a07df",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": [
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "Resolved 175 packages in 1.52s\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "Downloading hf-xet (3.0MiB)\nDownloading google-api-python-client (13.3MiB)\nDownloading semgrep (47.1MiB)\nDownloading fonttools (4.6MiB)\nDownloading tokenizers (3.2MiB)\nDownloading litellm (8.5MiB)\nDownloading selenium (9.2MiB)\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Building html2text==2024.2.26\n Building pyperclip==1.9.0\n Building wget==3.2\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "Downloading debugpy (3.4MiB)\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "Downloading tiktoken (1.0MiB)\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Built wget==3.2\n Built pyperclip==1.9.0\n Built html2text==2024.2.26\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "Downloading bavisitter (5.5MiB)\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading tiktoken\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading hf-xet\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading tokenizers\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading debugpy\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading fonttools\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading litellm\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading bavisitter\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading selenium\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading google-api-python-client\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": " Downloading semgrep\nPrepared 74 packages in 3.15s\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "Uninstalled 7 packages in 17ms\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "Installed 124 packages in 92ms\n + aiohappyeyeballs==2.6.1\n + aiohttp==3.12.15\n + aiosignal==1.4.0\n + anthropic==0.37.1\n + async-timeout==5.0.1\n + bavisitter==0.0.4\n + blessed==1.21.0\n + boltons==21.0.0\n + bracex==2.6\n - cachetools==6.2.0\n + cachetools==5.5.2\n - click==8.2.1\n + click==8.1.8\n + click-option-group==0.5.7\n + colorama==0.4.6\n + contourpy==1.3.2\n + cycler==0.12.1\n + debugpy==1.8.16\n + defusedxml==0.7.1\n + deprecated==1.2.18\n + distro==1.9.0\n + editor==1.6.6\n - exceptiongroup==1.3.0\n + exceptiongroup==1.2.2\n + face==24.0.0\n + filelock==3.19.1\n + fonttools==4.59.2\n + frozenlist==1.7.0\n + fsspec==2025.7.0\n + git-python==1.0.3\n + gitdb==4.0.12\n + gitpython==3.1.45\n + glom==22.1.0\n + google-ai-generativelanguage==0.6.6\n + google-api-core==2.25.1\n + google-api-python-client==2.179.0\n + google-auth==2.40.3\n + google-auth-httplib2==0.2.0\n + google-generativeai==0.7.2\n + googleapis-common-protos==1.70.0\n + grpcio==1.74.0\n + grpcio-status==1.62.3\n + hf-xet==1.1.9\n + html2image==2.0.7\n + html2text==2024.2.26\n + httpcore==1.0.9\n + httplib2==0.30.0\n + httpx==0.28.1\n + huggingface-hub==0.34.4\n + importlib-metadata==7.1.0\n + inquirer==3.4.1\n + ipykernel==6.30.1\n + jiter==0.10.0\n + joblib==1.5.2\n + jupyter-client==8.6.3\n + jupyter-core==5.8.1\n + kiwisolver==1.4.9\n + litellm==1.76.0\n + markdown-it-py==4.0.0\n + matplotlib==3.10.5\n + mdurl==0.1.2\n + multidict==6.6.4\n + nest-asyncio==1.6.0\n + nltk==3.9.1\n + open-interpreter==0.4.3\n + openai==1.102.0\n + opentelemetry-api==1.25.0\n + opentelemetry-exporter-otlp-proto-common==1.25.0\n + opentelemetry-exporter-otlp-proto-http==1.25.0\n + opentelemetry-instrumentation==0.46b0\n + opentelemetry-instrumentation-requests==0.46b0\n + opentelemetry-proto==1.25.0\n + opentelemetry-sdk==1.25.0\n + opentelemetry-semantic-conventions==0.46b0\n + opentelemetry-util-http==0.46b0\n + outcome==1.3.0.post0\n + pillow==11.3.0\n + propcache==0.3.2\n + proto-plus==1.26.1\n - protobuf==6.32.0\n + protobuf==4.25.8\n - psutil==7.0.0\n + psutil==5.9.8\n + pyasn1==0.6.1\n + pyasn1-modules==0.4.2\n + pyparsing==3.2.3\n + pyperclip==1.9.0\n + pysocks==1.7.1\n + python-dotenv==1.1.1\n + pyzmq==27.0.2\n + readchar==4.2.1\n + regex==2025.8.29\n + rich==13.5.3\n + rsa==4.9.1\n + ruamel-yaml==0.18.15\n + ruamel-yaml-clib==0.2.12\n + runs==1.2.2\n + selenium==4.35.0\n + semgrep==1.134.0\n + send2trash==1.8.3\n + setuptools==80.9.0\n + shellingham==1.5.4\n + shortuuid==1.0.13\n + smmap==5.0.2\n + sortedcontainers==2.4.0\n - starlette==0.47.3\n + starlette==0.37.2\n + termcolor==2.3.0\n + tiktoken==0.7.0\n + tokenizers==0.22.0\n + tokentrim==0.1.13\n + toml==0.10.2\n + tomli==2.0.2\n + tornado==6.5.2\n + tqdm==4.67.1\n + trio==0.30.0\n + trio-websocket==0.12.2\n + typer==0.12.5\n - typing-extensions==4.15.0\n + typing-extensions==4.14.1\n + uritemplate==4.2.0\n + wcmatch==8.5.2\n + webdriver-manager==4.0.2\n + websocket-client==1.8.0\n + wget==3.2\n + wrapt==1.17.3\n + wsproto==1.2.0\n + xmod==1.8.1\n + yarl==1.20.1\n + yaspin==3.1.0\n + zipp==3.23.0\n"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "aCWo",
|
||||||
|
"code_hash": "3ae165e9e1c0e9cb05ace86a6dc3f262",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/html": "<div style='display: flex;flex: 1;flex-direction: column;justify-content: flex-start;align-items: normal;flex-wrap: nowrap;gap: 0.5rem'><marimo-ui-element object-id='aCWo-0' random-id='973dcdc4-688b-bb8b-2945-e809bf38c4e9'><marimo-text data-initial-value='""' data-label='"<span class=\"markdown prose dark:prose-invert\"><span class=\"paragraph\">OPENAI_API_KEY (opcional aqu\u00ed; si ya est\u00e1 en el entorno, deja vac\u00edo)</span></span>"' data-placeholder='""' data-kind='"text"' data-full-width='true' data-disabled='false' data-debounce='true'></marimo-text></marimo-ui-element><div style='display: flex;flex: 1;flex-direction: row;justify-content: space-between;align-items: normal;flex-wrap: nowrap;gap: 0.5rem'><marimo-ui-element object-id='aCWo-1' random-id='3cb2f00b-da11-1c60-511a-0fb0f40f62bb'><marimo-dropdown data-initial-value='["gpt-4o"]' data-label='"<span class=\"markdown prose dark:prose-invert\"><span class=\"paragraph\">Modelo</span></span>"' data-options='["gpt-4o", "gpt-4o-mini", "gpt-4.1", "gpt-4o-reasoning"]' data-allow-select-none='false' data-searchable='false' data-full-width='false'></marimo-dropdown></marimo-ui-element><marimo-ui-element object-id='aCWo-2' random-id='1f4a9be7-b346-f30e-90db-bba56e3a0e5d'><marimo-radio data-initial-value='"light"' data-label='"<span class=\"markdown prose dark:prose-invert\"><span class=\"paragraph\">Tema de Bavisitter</span></span>"' data-options='["light", "dark"]' data-inline='false' data-disabled='false'></marimo-radio></marimo-ui-element></div><marimo-ui-element object-id='aCWo-3' random-id='70c7c342-fe90-38ba-ef7e-40ac99eade64'><marimo-button data-initial-value='0' data-label='"<span class=\"markdown prose dark:prose-invert\"><span class=\"paragraph\">Lanzar Bavisitter</span></span>"' data-kind='"neutral"' data-disabled='false' data-full-width='false'></marimo-button></marimo-ui-element></div>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ajNN",
|
||||||
|
"code_hash": "8d688461aee68cf5f12da3ab4e8f4d82",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/html": "<marimo-ui-element object-id='ajNN-0' random-id='a2cef7d0-091c-2095-7646-1e56d231f627'><marimo-dataframe data-initial-value='{"transforms": []}' data-label='null' data-columns='[["Title", "string", "object"], ["US_Gross", "number", "float64"], ["Worldwide_Gross", "number", "float64"], ["US_DVD_Sales", "number", "float64"], ["Production_Budget", "number", "float64"], ["Release_Date", "string", "object"], ["MPAA_Rating", "string", "object"], ["Running_Time_min", "number", "float64"], ["Distributor", "string", "object"], ["Source", "string", "object"], ["Major_Genre", "string", "object"], ["Creative_Type", "string", "object"], ["Director", "string", "object"], ["Rotten_Tomatoes_Rating", "number", "float64"], ["IMDB_Rating", "number", "float64"], ["IMDB_Votes", "number", "float64"]]' data-dataframe-name='"movies_df"' data-total='3201' data-page-size='5'></marimo-dataframe></marimo-ui-element>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pYQS",
|
||||||
|
"code_hash": "22608c40d28d2013c08e9b6eaf612cd2",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/html": "<marimo-ui-element object-id='pYQS-0' random-id='57ca6e34-3f48-9604-fe44-fe037431fd55'><marimo-anywidget data-initial-value='{"color_mode": "light", "ipc_queue": [], "messages": [], "streaming": false}' data-label='null' data-js-url='"./@file/20082536-42199-jhi6K66B.js"' data-js-hash='"43fe0f7d5f2958f5c0b3f1f8d8c49a4f"' data-css='""' data-buffer-paths='[]'></marimo-anywidget></marimo-ui-element>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gTaR",
|
||||||
|
"code_hash": "f452725116c9b87037dbbb8dfc325ec1",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/html": "<pre style='font-size: 12px'>'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'</pre>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -6,7 +6,73 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"id": "Hbol",
|
"id": "Hbol",
|
||||||
"code_hash": null,
|
"code_hash": "0914bd1bbeb9727790bfe2b5da7b0eb3",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "MJUe",
|
||||||
|
"code_hash": "d779223af5e58013abde68cbe3a3e517",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vblA",
|
||||||
|
"code_hash": "16b2686f0a3092171143731bc921c8b9",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bkHC",
|
||||||
|
"code_hash": "49cb0878d7ec60b899cafc532ba7b203",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEQa",
|
||||||
|
"code_hash": "1310ca8f87851c6abfc360ed4ad866c5",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "PKri",
|
||||||
|
"code_hash": "d1adb234ad2ebdd558a8b780168b7504",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Xref",
|
||||||
|
"code_hash": "501562d98a40f8ec082094108c01df7e",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "SFPL",
|
||||||
|
"code_hash": "c4a8490190c6289529269e729e711bfc",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BYtC",
|
||||||
|
"code_hash": "fff70582cf75e221534d3bbc4f12a577",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "RGSE",
|
||||||
|
"code_hash": "dd8013e55251f1fccf2dc6b6c0015880",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Kclp",
|
||||||
|
"code_hash": "05b631c7433a4800962bd9d1451e83c9",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "emfo",
|
||||||
|
"code_hash": "b70e25a38be12dcf8bbcb99cdcecf9d8",
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
"console": []
|
"console": []
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"metadata": {
|
||||||
|
"marimo_version": "0.15.2"
|
||||||
|
},
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"id": "Hbol",
|
||||||
|
"code_hash": "4fa9f530528a67e370348eb38c6b7024",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "edAi",
|
||||||
|
"code_hash": "be5e1e397391c61c55f27bf5f6881fd2",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/html": "<marimo-ui-element object-id='edAi-0' random-id='973dcdc4-688b-bb8b-2945-e809bf38c4e9'><marimo-anywidget data-initial-value='{"_columns": ["id", "name", "nationality", "sex", "date_of_birth", "height", "weight", "sport", "gold", "silver", "bronze", "info"], "_table_name": "df", "sql": "SELECT * FROM \"df\""}' data-label='null' data-js-url='"./@file/524489-31880-J4IXjEA0.js"' data-js-hash='"5ec7fd2207d37973a2148c7000e010a6"' data-css='""' data-buffer-paths='[]'></marimo-anywidget></marimo-ui-element>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"metadata": {
|
||||||
|
"marimo_version": "0.15.2"
|
||||||
|
},
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"id": "Hbol",
|
||||||
|
"code_hash": "893c2cde3ff7b0b85a1848b84dc639b1",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mNiZ",
|
||||||
|
"code_hash": "fd76317e77b2cdb53ad7dec19180a46d",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/html": "<marimo-ui-element object-id='mNiZ-0' random-id='e3a96b2b-fc0f-4574-72e3-dfe94f6627c6'><marimo-text data-initial-value='"echo Hola desde KMD"' data-label='"<span class=\"markdown prose dark:prose-invert\"><span class=\"paragraph\">Comando</span></span>"' data-placeholder='""' data-kind='"text"' data-full-width='false' data-disabled='false' data-debounce='true'></marimo-text></marimo-ui-element>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "XVTp",
|
||||||
|
"code_hash": "3df5f5a32e040d8a340e350779b41c10",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "error",
|
||||||
|
"ename": "interruption",
|
||||||
|
"evalue": "This cell was interrupted and needs to be re-run",
|
||||||
|
"traceback": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": [
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stderr",
|
||||||
|
"text": "<span class=\"codehilite\"><div class=\"highlight\"><pre><span></span><span class=\"gt\">Traceback (most recent call last):</span>\n File <span class=\"nb\">"/home/lucas/DataProyects/visualizaciones/.venv/lib/python3.10/site-packages/marimo/_runtime/executor.py"</span>, line <span class=\"m\">138</span>, in <span class=\"n\">execute_cell</span>\n<span class=\"w\"> </span><span class=\"n\">exec</span><span class=\"p\">(</span><span class=\"n\">cell</span><span class=\"o\">.</span><span class=\"n\">body</span><span class=\"p\">,</span> <span class=\"n\">glbls</span><span class=\"p\">)</span>\n File <span class=\"nb\">"/tmp/marimo_75418/__marimo__cell_XVTp_.py"</span>, line <span class=\"m\">3</span>, in <span class=\"n\"><module></span>\n<span class=\"w\"> </span><span class=\"n\">output</span> <span class=\"o\">=</span> <span class=\"n\">shell</span><span class=\"o\">.</span><span class=\"n\">do_run</span><span class=\"p\">(</span><span class=\"n\">command_input</span><span class=\"o\">.</span><span class=\"n\">value</span><span class=\"p\">)</span>\n File <span class=\"nb\">"/tmp/marimo_75418/__marimo__cell_Hbol_.py"</span>, line <span class=\"m\">13</span>, in <span class=\"n\">do_run</span>\n<span class=\"w\"> </span><span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">subprocess</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">(</span>\n File <span class=\"nb\">"/usr/lib/python3.10/subprocess.py"</span>, line <span class=\"m\">505</span>, in <span class=\"n\">run</span>\n<span class=\"w\"> </span><span class=\"n\">stdout</span><span class=\"p\">,</span> <span class=\"n\">stderr</span> <span class=\"o\">=</span> <span class=\"n\">process</span><span class=\"o\">.</span><span class=\"n\">communicate</span><span class=\"p\">(</span><span class=\"nb\">input</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"o\">=</span><span class=\"n\">timeout</span><span class=\"p\">)</span>\n File <span class=\"nb\">"/usr/lib/python3.10/subprocess.py"</span>, line <span class=\"m\">1154</span>, in <span class=\"n\">communicate</span>\n<span class=\"w\"> </span><span class=\"n\">stdout</span><span class=\"p\">,</span> <span class=\"n\">stderr</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_communicate</span><span class=\"p\">(</span><span class=\"nb\">input</span><span class=\"p\">,</span> <span class=\"n\">endtime</span><span class=\"p\">,</span> <span class=\"n\">timeout</span><span class=\"p\">)</span>\n File <span class=\"nb\">"/usr/lib/python3.10/subprocess.py"</span>, line <span class=\"m\">2021</span>, in <span class=\"n\">_communicate</span>\n<span class=\"w\"> </span><span class=\"n\">ready</span> <span class=\"o\">=</span> <span class=\"n\">selector</span><span class=\"o\">.</span><span class=\"n\">select</span><span class=\"p\">(</span><span class=\"n\">timeout</span><span class=\"p\">)</span>\n File <span class=\"nb\">"/usr/lib/python3.10/selectors.py"</span>, line <span class=\"m\">416</span>, in <span class=\"n\">select</span>\n<span class=\"w\"> </span><span class=\"n\">fd_event_list</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">_selector</span><span class=\"o\">.</span><span class=\"n\">poll</span><span class=\"p\">(</span><span class=\"n\">timeout</span><span class=\"p\">)</span>\n File <span class=\"nb\">"/home/lucas/DataProyects/visualizaciones/.venv/lib/python3.10/site-packages/marimo/_runtime/handlers.py"</span>, line <span class=\"m\">32</span>, in <span class=\"n\">interrupt_handler</span>\n<span class=\"w\"> </span><span class=\"k\">raise</span> <span class=\"n\">MarimoInterrupt</span>\n<span class=\"gr\">KeyboardInterrupt</span>\n</pre></div>\n</span>"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,137 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"metadata": {
|
||||||
|
"marimo_version": "0.15.2"
|
||||||
|
},
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"id": "Hbol",
|
||||||
|
"code_hash": "1d0db38904205bec4d6f6f6a1f6cec3e",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "MJUe",
|
||||||
|
"code_hash": "161ebcb820075ae0ed102ae0a00f47c2",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vblA",
|
||||||
|
"code_hash": "f7f5821d3695ae3da07f153aa5a1a7a6",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bkHC",
|
||||||
|
"code_hash": "dad9563ab733290d13df7d9f3c1f904b",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "XQvs",
|
||||||
|
"code_hash": null,
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": [
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stdout",
|
||||||
|
"text": "Script guardado en scripts/mi_script.sh y listo para ejecutarse.\n"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEQa",
|
||||||
|
"code_hash": "eea45b0636482cfa9d88aa3c65db2599",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": [
|
||||||
|
{
|
||||||
|
"type": "stream",
|
||||||
|
"name": "stdout",
|
||||||
|
"text": "Script guardado en scripts/mi_script.sh y listo para ejecutarse.\n"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "PKri",
|
||||||
|
"code_hash": "de1dd307acb19774134d7d0913854010",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/html": "<marimo-ui-element object-id='PKri-0' random-id='eb28ac23-1aa8-4a65-56fa-f187b12e4ce8'><marimo-anywidget data-initial-value='{"command": "bash -x ./scripts/mi_script.sh", "working_directory": "."}' data-label='null' data-js-url='"./@file/10677-12323-PKp7Iw7j.js"' data-js-hash='"a1582408702671c0b1563e88a1e2c259"' data-css='""' data-buffer-paths='[]'></marimo-anywidget></marimo-ui-element>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Xref",
|
||||||
|
"code_hash": "9a13086a1230097669e15deae4b7eb72",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "SFPL",
|
||||||
|
"code_hash": null,
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"type": "data",
|
||||||
|
"data": {
|
||||||
|
"text/plain": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"console": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"metadata": {
|
||||||
|
"marimo_version": "0.15.2"
|
||||||
|
},
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"id": "Hbol",
|
||||||
|
"code_hash": "9b50c9b671e7c769d569eb6803bfa319",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "MJUe",
|
||||||
|
"code_hash": "b69c9e22f0e38d50fa6dd4fd0b32197d",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vblA",
|
||||||
|
"code_hash": "aaa515da69322158d5f7ffc3309edb0b",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bkHC",
|
||||||
|
"code_hash": "c4c089a66f59ff92da5acf684f4ff257",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEQa",
|
||||||
|
"code_hash": "0cecc7bcd800abfcada2f4d2b7494b10",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "PKri",
|
||||||
|
"code_hash": "2e869e6640acd43bb304ec05e69db2b8",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Xref",
|
||||||
|
"code_hash": "14a4998b87bc95159a178f162e080a72",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "SFPL",
|
||||||
|
"code_hash": "3d94c0bbe21b88e5ce038a4529fd7d43",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BYtC",
|
||||||
|
"code_hash": "5529c61207cdf6a5357bab61fb2aea56",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "RGSE",
|
||||||
|
"code_hash": "90cae7bc1234a321f4e97934254c0dcb",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Kclp",
|
||||||
|
"code_hash": "c7351b53182b8fb61ffb6886d05807a6",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "emfo",
|
||||||
|
"code_hash": "1c680ba70a7a65bb39086d250190ed84",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Hstk",
|
||||||
|
"code_hash": null,
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"metadata": {
|
||||||
|
"marimo_version": "0.15.2"
|
||||||
|
},
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"id": "Hbol",
|
||||||
|
"code_hash": "9b50c9b671e7c769d569eb6803bfa319",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "MJUe",
|
||||||
|
"code_hash": "b69c9e22f0e38d50fa6dd4fd0b32197d",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vblA",
|
||||||
|
"code_hash": "aaa515da69322158d5f7ffc3309edb0b",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bkHC",
|
||||||
|
"code_hash": "c4c089a66f59ff92da5acf684f4ff257",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lEQa",
|
||||||
|
"code_hash": "0cecc7bcd800abfcada2f4d2b7494b10",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "PKri",
|
||||||
|
"code_hash": "2e869e6640acd43bb304ec05e69db2b8",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Xref",
|
||||||
|
"code_hash": "14a4998b87bc95159a178f162e080a72",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "SFPL",
|
||||||
|
"code_hash": "3d94c0bbe21b88e5ce038a4529fd7d43",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BYtC",
|
||||||
|
"code_hash": "5529c61207cdf6a5357bab61fb2aea56",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "RGSE",
|
||||||
|
"code_hash": "90cae7bc1234a321f4e97934254c0dcb",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Kclp",
|
||||||
|
"code_hash": "c7351b53182b8fb61ffb6886d05807a6",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "emfo",
|
||||||
|
"code_hash": "1c680ba70a7a65bb39086d250190ed84",
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Hstk",
|
||||||
|
"code_hash": null,
|
||||||
|
"outputs": [],
|
||||||
|
"console": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
|
|||||||
|
Parte,Porcentaje
|
||||||
|
P(A),25
|
||||||
|
P(B),25
|
||||||
|
P(A|B),25
|
||||||
|
P(B|A),25
|
||||||
|
+3202
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+11539
File diff suppressed because it is too large
Load Diff
+82
@@ -0,0 +1,82 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
return (mo,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
from modraw import Draw
|
||||||
|
from mohtml import img
|
||||||
|
return Draw, img
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(Draw, mo):
|
||||||
|
widget = mo.ui.anywidget(Draw(width=1000, height=450))
|
||||||
|
|
||||||
|
widget
|
||||||
|
return (widget,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(img, mo, widget):
|
||||||
|
def safe_draw_preview(widget, mode="auto"):
|
||||||
|
"""
|
||||||
|
Render the Draw content without raising.
|
||||||
|
mode:
|
||||||
|
- "auto": prefer base64; fallback to PIL
|
||||||
|
- "base64": only base64
|
||||||
|
- "pil": only PIL
|
||||||
|
- "both": show both (for debugging)
|
||||||
|
"""
|
||||||
|
# Read base64 safely
|
||||||
|
b64 = None
|
||||||
|
try:
|
||||||
|
v = getattr(widget, "value", None)
|
||||||
|
if isinstance(v, dict):
|
||||||
|
b64 = v.get("base64")
|
||||||
|
except Exception:
|
||||||
|
b64 = None
|
||||||
|
|
||||||
|
# Get PIL safely
|
||||||
|
pil_img = None
|
||||||
|
if hasattr(widget, "get_pil"):
|
||||||
|
try:
|
||||||
|
pil_img = widget.get_pil()
|
||||||
|
except Exception:
|
||||||
|
pil_img = None
|
||||||
|
|
||||||
|
# Decide what to render to avoid duplication
|
||||||
|
children = []
|
||||||
|
if mode == "auto":
|
||||||
|
if b64:
|
||||||
|
children = [img(src=b64)]
|
||||||
|
elif pil_img is not None:
|
||||||
|
children = [pil_img]
|
||||||
|
elif mode == "base64":
|
||||||
|
if b64:
|
||||||
|
children = [img(src=b64)]
|
||||||
|
elif mode == "pil":
|
||||||
|
if pil_img is not None:
|
||||||
|
children = [pil_img]
|
||||||
|
elif mode == "both":
|
||||||
|
if b64:
|
||||||
|
children.append(img(src=b64))
|
||||||
|
if pil_img is not None:
|
||||||
|
children.append(pil_img)
|
||||||
|
|
||||||
|
return mo.vstack(children) if children else mo.md("Dibuja algo para previsualizar.")
|
||||||
|
|
||||||
|
safe_draw_preview(widget, "base64")# fuerza solo base64
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
return (mo,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
from mopaint import Paint
|
||||||
|
from mohtml import img, div, tailwind_css
|
||||||
|
return Paint, div, img
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(Paint, mo):
|
||||||
|
widget = mo.ui.anywidget(Paint(height=550))
|
||||||
|
widget
|
||||||
|
return (widget,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(widget):
|
||||||
|
widget.value
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(div, img, widget):
|
||||||
|
div(
|
||||||
|
img(src=widget.get_base64()), klass="bg-gray-200 p-4"
|
||||||
|
) # Use base64 representation directly with mohtml
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(widget):
|
||||||
|
widget.get_pil()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
+214
@@ -0,0 +1,214 @@
|
|||||||
|
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()
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"type": "grid",
|
||||||
|
"data": {
|
||||||
|
"columns": 24,
|
||||||
|
"rowHeight": 20,
|
||||||
|
"maxWidth": 1400,
|
||||||
|
"bordered": true,
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"position": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
24,
|
||||||
|
9
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": [
|
||||||
|
0,
|
||||||
|
9,
|
||||||
|
12,
|
||||||
|
28
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": [
|
||||||
|
12,
|
||||||
|
9,
|
||||||
|
12,
|
||||||
|
28
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": [
|
||||||
|
0,
|
||||||
|
37,
|
||||||
|
12,
|
||||||
|
28
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"position": [
|
||||||
|
12,
|
||||||
|
37,
|
||||||
|
12,
|
||||||
|
28
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
from importlib import import_module
|
||||||
|
from typing import Dict, Any, Iterable, Tuple, Optional
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def _prefer_local_path(pkg_name: str, repo_path: Path) -> Optional[str]:
|
||||||
|
"""Insert repo/src or repo into sys.path (front) if it contains the package folder."""
|
||||||
|
for cand in (repo_path / "src", repo_path):
|
||||||
|
if (cand / pkg_name).exists():
|
||||||
|
sys.path.insert(0, str(cand))
|
||||||
|
return str(cand)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _purge_loaded(pkg_name: str) -> None:
|
||||||
|
"""Remove any already-loaded modules for this package."""
|
||||||
|
for k in list(sys.modules):
|
||||||
|
if k == pkg_name or k.startswith(pkg_name + "."):
|
||||||
|
del sys.modules[k]
|
||||||
|
|
||||||
|
def import_local_libs(
|
||||||
|
libs: Dict[str, str],
|
||||||
|
install_with_uv: bool = False,
|
||||||
|
uv_extra_args: Iterable[str] = (),
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Force-import local libraries from given repos.
|
||||||
|
- libs: dict { 'package_name': '/abs/path/to/repo' }
|
||||||
|
- install_with_uv: if True, runs `uv pip install -e <repo>`
|
||||||
|
(not required for local dev if sys.path injection is enough)
|
||||||
|
- uv_extra_args: extra args for uv, e.g. ['--constraint', 'constraints.txt']
|
||||||
|
Returns: dict { 'package_name': imported_module }
|
||||||
|
"""
|
||||||
|
imported: Dict[str, Any] = {}
|
||||||
|
uv_bin = shutil.which("uv")
|
||||||
|
|
||||||
|
for name, repo in libs.items():
|
||||||
|
repo_path = Path(repo).resolve()
|
||||||
|
if not repo_path.exists():
|
||||||
|
raise FileNotFoundError(f"[import_local] Repo not found: {repo_path}")
|
||||||
|
|
||||||
|
_purge_loaded(name)
|
||||||
|
added = _prefer_local_path(name, repo_path)
|
||||||
|
if not added:
|
||||||
|
raise ModuleNotFoundError(
|
||||||
|
f"[import_local] Could not find package folder '{name}' in "
|
||||||
|
f"'{repo_path}/src' or '{repo_path}'. Check your repo layout."
|
||||||
|
)
|
||||||
|
|
||||||
|
if install_with_uv:
|
||||||
|
if not uv_bin:
|
||||||
|
raise RuntimeError("uv not found in PATH, but install_with_uv=True.")
|
||||||
|
# Install editable using uv (no pip required).
|
||||||
|
# This installs into uv's target environment. For pure local dev,
|
||||||
|
# you can keep install_with_uv=False and rely on sys.path injection.
|
||||||
|
subprocess.run(
|
||||||
|
[uv_bin, "pip", "install", "-e", str(repo_path), *uv_extra_args],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Import the top-level package to ensure it resolves from the local path
|
||||||
|
imported[name] = import_module(name)
|
||||||
|
|
||||||
|
return imported
|
||||||
|
return (import_local_libs,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(import_local_libs):
|
||||||
|
LIBS = {
|
||||||
|
"moutils": "/home/lucas/DataProyects/git_proyects/moutils"
|
||||||
|
}
|
||||||
|
|
||||||
|
import_local_libs(LIBS)
|
||||||
|
|
||||||
|
# Ahora ya puedes importar normal
|
||||||
|
from moutils import shell, ShellWidget
|
||||||
|
return (ShellWidget,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
bash_code = """#!/bin/bash
|
||||||
|
|
||||||
|
# Espera input del usuario
|
||||||
|
read -p "Write the host to ping" destino
|
||||||
|
|
||||||
|
# Ejecuta ping indefinidamente
|
||||||
|
ping "$destino"
|
||||||
|
|
||||||
|
"""
|
||||||
|
return (bash_code,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(bash_code):
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Crear la carpeta scripts si no existe
|
||||||
|
os.makedirs("scripts", exist_ok=True)
|
||||||
|
|
||||||
|
# Ruta del archivo .sh dentro de scripts
|
||||||
|
script_path = os.path.join("scripts", "mi_script.sh")
|
||||||
|
|
||||||
|
# Guardar el contenido en el archivo
|
||||||
|
with open(script_path, "w") as f:
|
||||||
|
f.write(bash_code)
|
||||||
|
|
||||||
|
# Dar permisos de ejecución
|
||||||
|
os.chmod(script_path, 0o755)
|
||||||
|
|
||||||
|
print(f"Script guardado en {script_path} y listo para ejecutarse.")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(ShellWidget):
|
||||||
|
console = ShellWidget(command="bash -x ./scripts/mi_script.sh", run=True)
|
||||||
|
console
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
# console.kill()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import marimo as mo
|
||||||
|
from moutils import shell
|
||||||
|
return mo, shell
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(shell):
|
||||||
|
shell(command="ls")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(shell):
|
||||||
|
shell_widget = shell("""
|
||||||
|
sleep 5 && read -p "Ingresa algo: " variable
|
||||||
|
|
||||||
|
""")
|
||||||
|
shell_widget
|
||||||
|
return (shell_widget,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(shell_widget):
|
||||||
|
shell_widget.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
print("hola")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
cmd_input = mo.ui.text(value="echo 'Hola desde ShellWidget!'", label="Comando")
|
||||||
|
workdir_input = mo.ui.text(value=".", label="Directorio de trabajo (opcional)")
|
||||||
|
run_btn = mo.ui.run_button(label="Ejecutar comando")
|
||||||
|
|
||||||
|
mo.vstack([cmd_input, workdir_input, run_btn])
|
||||||
|
return cmd_input, run_btn, workdir_input
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(cmd_input, mo, run_btn, shell, workdir_input):
|
||||||
|
# Importante: accede a .value en otra celda
|
||||||
|
if not run_btn.value:
|
||||||
|
mo.md("Pulsa **Ejecutar comando**")
|
||||||
|
else:
|
||||||
|
# Instanciar el widget Shell cuando se pulse el botón
|
||||||
|
# Shell ejecuta y streamea la salida en la celda
|
||||||
|
shell(cmd_input.value, working_directory=workdir_input.value)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
# import marimo as mo
|
||||||
|
# from moutils import shell
|
||||||
|
|
||||||
|
cmd = mo.ui.text("date", label="Comando (auto)")
|
||||||
|
cmd
|
||||||
|
return (cmd,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(cmd, shell):
|
||||||
|
# Cada cambio en cmd.value re-ejecuta esta celda
|
||||||
|
shell(cmd.value)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
import asyncio
|
||||||
|
from moutils import ShellWidget
|
||||||
|
return ShellWidget, asyncio
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(ShellWidget, asyncio):
|
||||||
|
def autorun_shell(command: str, working_directory: str = ".") -> ShellWidget:
|
||||||
|
w = ShellWidget(command, working_directory)
|
||||||
|
|
||||||
|
# Programar la ejecución inmediatamente, respetando el event loop actual
|
||||||
|
try:
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
if loop.is_running():
|
||||||
|
loop.create_task(w._execute_command_async())
|
||||||
|
else:
|
||||||
|
loop.run_until_complete(w._execute_command_async())
|
||||||
|
except RuntimeError:
|
||||||
|
asyncio.run(w._execute_command_async())
|
||||||
|
|
||||||
|
return w
|
||||||
|
return (autorun_shell,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(autorun_shell):
|
||||||
|
autorun_shell("date", working_directory=".")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,479 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.2"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
# marimo
|
||||||
|
import marimo as mo
|
||||||
|
|
||||||
|
# Data & math
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# Embeddings
|
||||||
|
from sentence_transformers import SentenceTransformer
|
||||||
|
|
||||||
|
# Dimensionality reduction & metrics
|
||||||
|
from sklearn.decomposition import PCA
|
||||||
|
from sklearn.manifold import TSNE
|
||||||
|
from sklearn.metrics import pairwise_distances
|
||||||
|
from sklearn.neighbors import NearestNeighbors
|
||||||
|
|
||||||
|
# Viz
|
||||||
|
import altair as alt
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
from functools import lru_cache
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
|
||||||
|
# --- Notes (English): ---
|
||||||
|
# - All comments are in English as requested.
|
||||||
|
# - We avoid variable re-declarations across cells (Marimo DAG rule).
|
||||||
|
# - The last expression in each cell is displayed automatically.
|
||||||
|
|
||||||
|
return (
|
||||||
|
NearestNeighbors,
|
||||||
|
PCA,
|
||||||
|
SentenceTransformer,
|
||||||
|
TSNE,
|
||||||
|
alt,
|
||||||
|
io,
|
||||||
|
lru_cache,
|
||||||
|
mo,
|
||||||
|
np,
|
||||||
|
pairwise_distances,
|
||||||
|
pd,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
# UI elements (defined here; values used in later cells)
|
||||||
|
sample_toggle = mo.ui.checkbox(label="Use sample dataset (tiny demo)", value=True)
|
||||||
|
text_area = mo.ui.text_area(
|
||||||
|
value="Label,Text\ntech,Transformers accelerate NLP research.\ntech,Embeddings capture semantic meaning.\n"
|
||||||
|
"finance,Markets react to macroeconomic signals.\nfinance,Portfolio optimization reduces risk.\n"
|
||||||
|
"sports,The team improved defense and strategy.\nsports,Training intensity boosts performance.\n",
|
||||||
|
label="CSV data (columns: Label,Text)", full_width=True
|
||||||
|
)
|
||||||
|
|
||||||
|
model_a_dropdown = mo.ui.dropdown(
|
||||||
|
options=[
|
||||||
|
"sentence-transformers/all-MiniLM-L6-v2",
|
||||||
|
"thenlper/gte-small",
|
||||||
|
"BAAI/bge-small-en-v1.5",
|
||||||
|
"sentence-transformers/paraphrase-MiniLM-L6-v2",
|
||||||
|
],
|
||||||
|
value="sentence-transformers/all-MiniLM-L6-v2",
|
||||||
|
label="Model A"
|
||||||
|
)
|
||||||
|
model_b_dropdown = mo.ui.dropdown(
|
||||||
|
options=[
|
||||||
|
"sentence-transformers/all-MiniLM-L6-v2",
|
||||||
|
"thenlper/gte-small",
|
||||||
|
"BAAI/bge-small-en-v1.5",
|
||||||
|
"sentence-transformers/paraphrase-MiniLM-L6-v2",
|
||||||
|
],
|
||||||
|
value="BAAI/bge-small-en-v1.5",
|
||||||
|
label="Model B"
|
||||||
|
)
|
||||||
|
|
||||||
|
reducer_dropdown = mo.ui.radio(
|
||||||
|
options=["PCA", "TSNE"],
|
||||||
|
value="PCA",
|
||||||
|
label="Dimensionality reduction"
|
||||||
|
)
|
||||||
|
k_slider = mo.ui.slider(3, 20, value=10, label="k for neighborhood agreement")
|
||||||
|
|
||||||
|
mo.vstack([
|
||||||
|
mo.md("### Data & Models"),
|
||||||
|
sample_toggle,
|
||||||
|
text_area,
|
||||||
|
mo.hstack([model_a_dropdown, model_b_dropdown]),
|
||||||
|
mo.hstack([reducer_dropdown, k_slider]),
|
||||||
|
])
|
||||||
|
|
||||||
|
return (
|
||||||
|
k_slider,
|
||||||
|
model_a_dropdown,
|
||||||
|
model_b_dropdown,
|
||||||
|
reducer_dropdown,
|
||||||
|
text_area,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(io, pd, text_area):
|
||||||
|
# Build dataframe from UI state.
|
||||||
|
# If sample_toggle is True, parse the sample CSV from text_area; otherwise expect user-provided CSV.
|
||||||
|
def _parse_csv_to_df(csv_text: str) -> pd.DataFrame:
|
||||||
|
# Parse CSV robustly
|
||||||
|
df = pd.read_csv(io.StringIO(csv_text))
|
||||||
|
# Basic schema validation
|
||||||
|
expected_cols = {"Label", "Text"}
|
||||||
|
if not expected_cols.issubset(set(df.columns)):
|
||||||
|
raise ValueError("CSV must contain columns: Label, Text")
|
||||||
|
# Ensure string types
|
||||||
|
df["Label"] = df["Label"].astype(str)
|
||||||
|
df["Text"] = df["Text"].astype(str)
|
||||||
|
return df
|
||||||
|
|
||||||
|
dataframe_input = _parse_csv_to_df(text_area.value)
|
||||||
|
dataframe_input
|
||||||
|
|
||||||
|
return (dataframe_input,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(SentenceTransformer, lru_cache, mo, model_a_dropdown, model_b_dropdown):
|
||||||
|
# Cache model loading to avoid repeated downloads.
|
||||||
|
@lru_cache(maxsize=4)
|
||||||
|
def load_model_cached(model_name: str) -> SentenceTransformer:
|
||||||
|
# English: caches SentenceTransformer for responsiveness
|
||||||
|
return SentenceTransformer(model_name)
|
||||||
|
|
||||||
|
selected_model_a = model_a_dropdown.value
|
||||||
|
selected_model_b = model_b_dropdown.value
|
||||||
|
|
||||||
|
mo.hstack([
|
||||||
|
mo.md(f"**Model A:** `{selected_model_a}`"),
|
||||||
|
mo.md(f"**Model B:** `{selected_model_b}`"),
|
||||||
|
])
|
||||||
|
|
||||||
|
return load_model_cached, selected_model_a, selected_model_b
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(
|
||||||
|
dataframe_input,
|
||||||
|
load_model_cached,
|
||||||
|
np,
|
||||||
|
selected_model_a,
|
||||||
|
selected_model_b,
|
||||||
|
):
|
||||||
|
# Generate embeddings for both models on the same text order.
|
||||||
|
texts_for_embedding = dataframe_input["Text"].tolist()
|
||||||
|
|
||||||
|
def _embed_texts(model_name: str, texts: list[str]) -> np.ndarray:
|
||||||
|
model = load_model_cached(model_name)
|
||||||
|
return model.encode(texts, show_progress_bar=False, normalize_embeddings=True)
|
||||||
|
|
||||||
|
embeddings_a = _embed_texts(selected_model_a, texts_for_embedding)
|
||||||
|
embeddings_b = _embed_texts(selected_model_b, texts_for_embedding)
|
||||||
|
|
||||||
|
# Show shapes as a quick check
|
||||||
|
{"A_shape": embeddings_a.shape, "B_shape": embeddings_b.shape}
|
||||||
|
|
||||||
|
return embeddings_a, embeddings_b
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(
|
||||||
|
PCA,
|
||||||
|
TSNE,
|
||||||
|
dataframe_input,
|
||||||
|
embeddings_a,
|
||||||
|
embeddings_b,
|
||||||
|
np,
|
||||||
|
pd,
|
||||||
|
reducer_dropdown,
|
||||||
|
):
|
||||||
|
# Reduce to 2D using PCA or TSNE.
|
||||||
|
reducer_choice = reducer_dropdown.value
|
||||||
|
|
||||||
|
def _reduce_2d(X: np.ndarray, method: str) -> np.ndarray:
|
||||||
|
if method == "PCA":
|
||||||
|
reducer = PCA(n_components=2, random_state=42)
|
||||||
|
return reducer.fit_transform(X)
|
||||||
|
elif method == "TSNE":
|
||||||
|
# TSNE default perplexity 30 works fine for small demos; set random_state for reproducibility.
|
||||||
|
reducer = TSNE(n_components=2, random_state=42, init="pca", learning_rate="auto")
|
||||||
|
return reducer.fit_transform(X)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown reducer")
|
||||||
|
|
||||||
|
coords_a_2d = _reduce_2d(embeddings_a, reducer_choice)
|
||||||
|
coords_b_2d = _reduce_2d(embeddings_b, reducer_choice)
|
||||||
|
|
||||||
|
# Pack into tidy DataFrames for plotting
|
||||||
|
plot_df_a = pd.DataFrame({
|
||||||
|
"x": coords_a_2d[:, 0],
|
||||||
|
"y": coords_a_2d[:, 1],
|
||||||
|
"Label": dataframe_input["Label"],
|
||||||
|
"Text": dataframe_input["Text"],
|
||||||
|
"Model": "A"
|
||||||
|
})
|
||||||
|
plot_df_b = pd.DataFrame({
|
||||||
|
"x": coords_b_2d[:, 0],
|
||||||
|
"y": coords_b_2d[:, 1],
|
||||||
|
"Label": dataframe_input["Label"],
|
||||||
|
"Text": dataframe_input["Text"],
|
||||||
|
"Model": "B"
|
||||||
|
})
|
||||||
|
|
||||||
|
plot_df_combined = pd.concat([plot_df_a, plot_df_b], ignore_index=True)
|
||||||
|
plot_df_combined
|
||||||
|
|
||||||
|
return (
|
||||||
|
coords_a_2d,
|
||||||
|
coords_b_2d,
|
||||||
|
plot_df_a,
|
||||||
|
plot_df_b,
|
||||||
|
plot_df_combined,
|
||||||
|
reducer_choice,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(alt, plot_df_combined, reducer_choice):
|
||||||
|
# Build linked charts: one for Model A and one for Model B.
|
||||||
|
# English: We use consistent color mapping by Label across both charts.
|
||||||
|
|
||||||
|
# Calculate consistent color domain
|
||||||
|
label_domain = sorted(plot_df_combined["Label"].unique().tolist())
|
||||||
|
|
||||||
|
base = alt.Chart(plot_df_combined).mark_circle(size=80).encode(
|
||||||
|
x=alt.X("x:Q", title=f"{reducer_choice} 1"),
|
||||||
|
y=alt.Y("y:Q", title=f"{reducer_choice} 2"),
|
||||||
|
color=alt.Color("Label:N", legend=alt.Legend(title="Label"), scale=alt.Scale(scheme="category10", domain=label_domain)),
|
||||||
|
tooltip=["Model:N", "Label:N", "Text:N"]
|
||||||
|
).properties(width=350, height=300)
|
||||||
|
|
||||||
|
chart_a = base.transform_filter(alt.datum.Model == "A").properties(title="Model A")
|
||||||
|
chart_b = base.transform_filter(alt.datum.Model == "B").properties(title="Model B")
|
||||||
|
|
||||||
|
alt.hconcat(chart_a, chart_b).resolve_scale(color="shared")
|
||||||
|
|
||||||
|
return (label_domain,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(NearestNeighbors, coords_a_2d, coords_b_2d, k_slider, mo, np, pd):
|
||||||
|
# Compute neighborhood agreement: for each point, overlap between k-NN in A vs B (after 2D reduction).
|
||||||
|
# English: Robust version that clips k to the valid range based on dataset size.
|
||||||
|
|
||||||
|
# from sklearn.neighbors import NearestNeighbors
|
||||||
|
|
||||||
|
# Dataset size
|
||||||
|
n_points = int(coords_a_2d.shape[0])
|
||||||
|
|
||||||
|
# Guard: need at least 3 points to compute non-trivial neighbors (exclude self)
|
||||||
|
mo.stop(n_points < 3, mo.md("Need at least **3** rows to compute neighborhood overlap."))
|
||||||
|
|
||||||
|
# Clip k so that kneighbors sees n_neighbors <= n_samples - 1 (exclude self)
|
||||||
|
requested_k = int(k_slider.value)
|
||||||
|
max_valid_k = max(1, n_points - 2) # ensures (k+1) <= (n_points - 1)
|
||||||
|
effective_k = min(requested_k, max_valid_k)
|
||||||
|
|
||||||
|
# Informative message if clipping happened
|
||||||
|
k_info = mo.md(
|
||||||
|
f"Using **k = {effective_k}** (requested {requested_k}, max valid {max_valid_k} for n={n_points})."
|
||||||
|
) if effective_k != requested_k else mo.md(f"Using **k = {effective_k}** for n={n_points}.")
|
||||||
|
|
||||||
|
def _knn_indices(X2d: np.ndarray, k: int) -> np.ndarray:
|
||||||
|
# English: use k+1 to include self in the neighbor list, then drop self (index 0)
|
||||||
|
# n_neighbors must be strictly less than n_samples, so pass (k+1) <= (n_points - 1)
|
||||||
|
nbrs = NearestNeighbors(n_neighbors=k + 1, metric="euclidean")
|
||||||
|
nbrs.fit(X2d)
|
||||||
|
indices = nbrs.kneighbors(return_distance=False)
|
||||||
|
return indices[:, 1:] # drop self
|
||||||
|
|
||||||
|
knn_a = _knn_indices(coords_a_2d, k=effective_k)
|
||||||
|
knn_b = _knn_indices(coords_b_2d, k=effective_k)
|
||||||
|
|
||||||
|
def _rowwise_overlap(idx_a: np.ndarray, idx_b: np.ndarray) -> np.ndarray:
|
||||||
|
# English: compute per-point overlap fraction between two k-NN index sets
|
||||||
|
overlaps = []
|
||||||
|
for a, b in zip(idx_a, idx_b):
|
||||||
|
inter = len(set(a.tolist()).intersection(set(b.tolist())))
|
||||||
|
overlaps.append(inter / len(a))
|
||||||
|
return np.array(overlaps, dtype=float)
|
||||||
|
|
||||||
|
overlap_scores = _rowwise_overlap(knn_a, knn_b)
|
||||||
|
neighborhood_agreement_mean = float(np.mean(overlap_scores))
|
||||||
|
|
||||||
|
# Display small summary table (head) + info about effective k
|
||||||
|
mo.vstack([
|
||||||
|
k_info,
|
||||||
|
mo.ui.dataframe(
|
||||||
|
pd.DataFrame({"Point": np.arange(len(overlap_scores)),
|
||||||
|
f"Overlap@{effective_k}": overlap_scores})
|
||||||
|
),
|
||||||
|
mo.md(f"**Mean Overlap@{effective_k}:** {neighborhood_agreement_mean:.3f}")
|
||||||
|
])
|
||||||
|
|
||||||
|
return neighborhood_agreement_mean, overlap_scores
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(coords_a_2d, coords_b_2d, dataframe_input, np, pd):
|
||||||
|
# For each label, compute 2D centroids in A and B, then report distance between centroids.
|
||||||
|
labels_series = dataframe_input["Label"]
|
||||||
|
unique_labels = sorted(labels_series.unique().tolist())
|
||||||
|
|
||||||
|
def _centroids(coords: np.ndarray, labels: pd.Series) -> dict[str, np.ndarray]:
|
||||||
|
out = {}
|
||||||
|
for lab in unique_labels:
|
||||||
|
pts = coords[labels.values == lab]
|
||||||
|
out[lab] = np.mean(pts, axis=0)
|
||||||
|
return out
|
||||||
|
|
||||||
|
centroids_a = _centroids(coords_a_2d, labels_series)
|
||||||
|
centroids_b = _centroids(coords_b_2d, labels_series)
|
||||||
|
|
||||||
|
centroid_rows = []
|
||||||
|
for lab in unique_labels:
|
||||||
|
ca = centroids_a[lab]
|
||||||
|
cb = centroids_b[lab]
|
||||||
|
dist = float(np.linalg.norm(ca - cb))
|
||||||
|
centroid_rows.append({"Label": lab, "CentroidShift(A_vs_B)": dist})
|
||||||
|
|
||||||
|
centroid_shift_df = pd.DataFrame(centroid_rows).sort_values("CentroidShift(A_vs_B)", ascending=False)
|
||||||
|
centroid_shift_df
|
||||||
|
|
||||||
|
return centroid_shift_df, labels_series
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(embeddings_a, embeddings_b, np, pairwise_distances, pd):
|
||||||
|
# Compute pairwise distance matrices in the original embedding spaces (A vs B), compare rank correlation (Spearman).
|
||||||
|
# English: measures whether global structure is preserved similarly by the two models.
|
||||||
|
from scipy.stats import spearmanr
|
||||||
|
|
||||||
|
# Use cosine distances on normalized embeddings (already normalized earlier).
|
||||||
|
dist_a = pairwise_distances(embeddings_a, metric="cosine")
|
||||||
|
dist_b = pairwise_distances(embeddings_b, metric="cosine")
|
||||||
|
|
||||||
|
# Vectorize upper triangles (avoid diagonal)
|
||||||
|
triu_idx = np.triu_indices(dist_a.shape[0], k=1)
|
||||||
|
vec_a = dist_a[triu_idx]
|
||||||
|
vec_b = dist_b[triu_idx]
|
||||||
|
|
||||||
|
rho, p_val = spearmanr(vec_a, vec_b)
|
||||||
|
|
||||||
|
pd.DataFrame({"Spearman_rho":[float(rho)], "p_value":[float(p_val)]})
|
||||||
|
|
||||||
|
return p_val, rho
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(
|
||||||
|
NearestNeighbors,
|
||||||
|
coords_a_2d,
|
||||||
|
coords_b_2d,
|
||||||
|
dataframe_input,
|
||||||
|
labels_series,
|
||||||
|
np,
|
||||||
|
pd,
|
||||||
|
):
|
||||||
|
def _label_density(coords: np.ndarray, labels: pd.Series, k: int = 5) -> pd.DataFrame:
|
||||||
|
# English: need at least 3 points; with n=2, dropping self leaves 0 neighbors
|
||||||
|
n_points = int(coords.shape[0])
|
||||||
|
if n_points < 3:
|
||||||
|
# Return minimal summary with NaNs to signal insufficient neighbors
|
||||||
|
return pd.DataFrame({"Label": labels.values, "LocalDensity": np.nan}) \
|
||||||
|
.groupby("Label", as_index=False) \
|
||||||
|
.agg(Size=("Label","count"), MeanLocalDensity=("LocalDensity","mean"))
|
||||||
|
|
||||||
|
# English: choose a valid n_neighbors for sklearn kneighbors
|
||||||
|
# We query (k_eff + 1) neighbors to include self, then drop self.
|
||||||
|
# Constraint: n_neighbors <= n_points - 1 to satisfy sklearn's strict inequality.
|
||||||
|
n_neighbors = min(k + 1, n_points - 1)
|
||||||
|
k_eff = max(1, n_neighbors - 1) # English: effective neighbors after dropping self, at least 1
|
||||||
|
|
||||||
|
nbrs = NearestNeighbors(n_neighbors=n_neighbors, metric="euclidean").fit(coords)
|
||||||
|
dists, _ = nbrs.kneighbors(return_distance=True)
|
||||||
|
|
||||||
|
# English: drop self at index 0 and average first k_eff distances
|
||||||
|
# If n_neighbors might be > k_eff+1 due to clipping, we still take only k_eff after removing self.
|
||||||
|
local_density = dists[:, 1:1 + k_eff].mean(axis=1)
|
||||||
|
|
||||||
|
df = pd.DataFrame({"Label": labels.values, "LocalDensity": local_density})
|
||||||
|
out = df.groupby("Label", as_index=False).agg(
|
||||||
|
Size=("Label","count"),
|
||||||
|
MeanLocalDensity=("LocalDensity","mean")
|
||||||
|
)
|
||||||
|
return out
|
||||||
|
|
||||||
|
# English: choose k safely based on dataset size (consistent with above guard)
|
||||||
|
k_density = min(5, max(1, len(dataframe_input) - 2))
|
||||||
|
|
||||||
|
density_a = _label_density(coords_a_2d, labels_series, k=k_density)
|
||||||
|
density_b = _label_density(coords_b_2d, labels_series, k=k_density)
|
||||||
|
|
||||||
|
summary_labels = density_a.merge(density_b, on="Label", suffixes=("_A", "_B"))
|
||||||
|
summary_labels
|
||||||
|
return (summary_labels,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(
|
||||||
|
alt,
|
||||||
|
centroid_shift_df,
|
||||||
|
k_slider,
|
||||||
|
label_domain,
|
||||||
|
mo,
|
||||||
|
neighborhood_agreement_mean,
|
||||||
|
np,
|
||||||
|
overlap_scores,
|
||||||
|
p_val,
|
||||||
|
pd,
|
||||||
|
plot_df_a,
|
||||||
|
plot_df_b,
|
||||||
|
plot_df_combined,
|
||||||
|
rho,
|
||||||
|
summary_labels,
|
||||||
|
):
|
||||||
|
# UI panel summarizing metrics and allowing CSV export of 2D coords.
|
||||||
|
export_button = mo.ui.button("Export 2D coordinates (CSV)")
|
||||||
|
|
||||||
|
summary_md = mo.md(
|
||||||
|
f"""
|
||||||
|
### Summary
|
||||||
|
- Neighborhood agreement (mean Overlap@{k_slider.value}): **{neighborhood_agreement_mean:.3f}**
|
||||||
|
- Centroid shift (A vs B): min={centroid_shift_df['CentroidShift(A_vs_B)'].min():.3f}, max={centroid_shift_df['CentroidShift(A_vs_B)'].max():.3f}
|
||||||
|
- Global structure similarity (Spearman on pairwise distances): **rho={float(rho):.3f}** (p={float(p_val):.2e})
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prepare exported CSV
|
||||||
|
export_df = plot_df_combined.copy()
|
||||||
|
export_payload = export_df.to_csv(index=False)
|
||||||
|
|
||||||
|
mo.vstack([
|
||||||
|
summary_md,
|
||||||
|
mo.ui.tabs({
|
||||||
|
"Scatter A/B": mo.ui.altair_chart(alt.hconcat(
|
||||||
|
alt.Chart(plot_df_a).mark_circle(size=80).encode(
|
||||||
|
x="x:Q", y="y:Q", color=alt.Color("Label:N", scale=alt.Scale(domain=label_domain)),
|
||||||
|
tooltip=["Label:N","Text:N"]
|
||||||
|
).properties(title="A", width=360, height=320),
|
||||||
|
alt.Chart(plot_df_b).mark_circle(size=80).encode(
|
||||||
|
x="x:Q", y="y:Q", color=alt.Color("Label:N", scale=alt.Scale(domain=label_domain)),
|
||||||
|
tooltip=["Label:N","Text:N"]
|
||||||
|
).properties(title="B", width=360, height=320)
|
||||||
|
)),
|
||||||
|
"Overlap@k (head)": mo.ui.table(
|
||||||
|
pd.DataFrame({"Point": np.arange(len(overlap_scores)),
|
||||||
|
f"Overlap@{k_slider.value}": overlap_scores})
|
||||||
|
),
|
||||||
|
"Centroid shift": mo.ui.table(centroid_shift_df),
|
||||||
|
"Label summary": mo.ui.table(summary_labels),
|
||||||
|
}),
|
||||||
|
export_button
|
||||||
|
])
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import marimo
|
||||||
|
|
||||||
|
__generated_with = "0.15.1"
|
||||||
|
app = marimo.App(width="medium")
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _():
|
||||||
|
# Cell 1 — Imports y utilidades
|
||||||
|
import marimo as mo
|
||||||
|
import os
|
||||||
|
import pandas as pd
|
||||||
|
import numpy as np
|
||||||
|
import altair as alt
|
||||||
|
import pygwalker as pyg
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from vega_datasets import data as vega_data
|
||||||
|
except Exception:
|
||||||
|
vega_data = None
|
||||||
|
|
||||||
|
|
||||||
|
DATASET_URLS: Dict[str, str] = {
|
||||||
|
"Bike Sharing (DC)": "https://kanaries-app.s3.ap-northeast-1.amazonaws.com/public-datasets/bike_sharing_dc.csv",
|
||||||
|
}
|
||||||
|
return DATASET_URLS, mo, pd, pyg, vega_data
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(mo):
|
||||||
|
options = [
|
||||||
|
"cars",
|
||||||
|
"iris",
|
||||||
|
"seattle-weather",
|
||||||
|
"stocks",
|
||||||
|
"Bike Sharing (DC)",
|
||||||
|
]
|
||||||
|
|
||||||
|
dataset_selector = mo.ui.dropdown(options=options, value="cars", label="Dataset")
|
||||||
|
sample_toggle = mo.ui.checkbox(label="Muestrear filas", value=False)
|
||||||
|
sample_size = mo.ui.number(value=1000, label="Filas a tomar")
|
||||||
|
dark_mode = mo.ui.radio(options=["media", "light", "dark"], value="media", label="Tema")
|
||||||
|
spec_path_input = mo.ui.text(value="", label="Ruta de spec (opcional)", full_width=True)
|
||||||
|
|
||||||
|
mo.vstack([
|
||||||
|
mo.md("## 1) Selecciona un dataset y preferencias"),
|
||||||
|
mo.hstack([dataset_selector, sample_toggle, sample_size]),
|
||||||
|
mo.hstack([dark_mode]),
|
||||||
|
spec_path_input,
|
||||||
|
])
|
||||||
|
return (
|
||||||
|
dark_mode,
|
||||||
|
dataset_selector,
|
||||||
|
sample_size,
|
||||||
|
sample_toggle,
|
||||||
|
spec_path_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(
|
||||||
|
dark_mode,
|
||||||
|
dataset_selector,
|
||||||
|
sample_size,
|
||||||
|
sample_toggle,
|
||||||
|
spec_path_input,
|
||||||
|
):
|
||||||
|
selected_name = dataset_selector.value
|
||||||
|
use_sample = sample_toggle.value
|
||||||
|
sample_n = sample_size.value
|
||||||
|
selected_theme = dark_mode.value
|
||||||
|
spec_path_val = spec_path_input.value.strip()
|
||||||
|
return sample_n, selected_name, selected_theme, spec_path_val, use_sample
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(
|
||||||
|
DATASET_URLS: "Dict[str, str]",
|
||||||
|
pd,
|
||||||
|
sample_n,
|
||||||
|
selected_name,
|
||||||
|
use_sample,
|
||||||
|
vega_data,
|
||||||
|
):
|
||||||
|
def _load_dataset(name: str) -> pd.DataFrame:
|
||||||
|
if name == "Bike Sharing (DC)":
|
||||||
|
return pd.read_csv(DATASET_URLS["Bike Sharing (DC)"], parse_dates=["date"])
|
||||||
|
if name == "cars":
|
||||||
|
if vega_data is not None:
|
||||||
|
return vega_data.cars()
|
||||||
|
return pd.read_json("https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json")
|
||||||
|
if name == "iris":
|
||||||
|
if vega_data is not None:
|
||||||
|
return vega_data.iris()
|
||||||
|
return pd.read_csv("https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv")
|
||||||
|
if name == "seattle-weather":
|
||||||
|
if vega_data is not None:
|
||||||
|
return vega_data.seattle_weather()
|
||||||
|
return pd.read_csv(
|
||||||
|
"https://raw.githubusercontent.com/vega/vega-datasets/master/data/seattle-weather.csv",
|
||||||
|
parse_dates=["date"],
|
||||||
|
)
|
||||||
|
if name == "stocks":
|
||||||
|
if vega_data is not None:
|
||||||
|
return vega_data.stocks()
|
||||||
|
return pd.read_csv(
|
||||||
|
"https://raw.githubusercontent.com/vega/vega-datasets/master/data/stocks.csv",
|
||||||
|
parse_dates=["date"],
|
||||||
|
)
|
||||||
|
return pd.DataFrame()
|
||||||
|
|
||||||
|
_df_raw = _load_dataset(selected_name)
|
||||||
|
|
||||||
|
if use_sample and isinstance(sample_n, (int, float)) and sample_n > 0:
|
||||||
|
_n = int(sample_n)
|
||||||
|
df = _df_raw.sample(n=min(_n, len(_df_raw)), random_state=42).reset_index(drop=True)
|
||||||
|
else:
|
||||||
|
df = _df_raw
|
||||||
|
|
||||||
|
df
|
||||||
|
return (df,)
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(df, mo):
|
||||||
|
explorer = mo.ui.data_explorer(df)
|
||||||
|
explorer
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@app.cell
|
||||||
|
def _(df, mo, pyg, selected_theme, spec_path_val):
|
||||||
|
_gw_gid = "gwalker-main"
|
||||||
|
_html = pyg.to_html(
|
||||||
|
df,
|
||||||
|
gid=_gw_gid,
|
||||||
|
dark=selected_theme,
|
||||||
|
spec=spec_path_val if spec_path_val != "" else "",
|
||||||
|
)
|
||||||
|
|
||||||
|
mo.Html(_html)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run()
|
||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Espera input del usuario
|
||||||
|
read -p "Write the host to ping" destino
|
||||||
|
|
||||||
|
# Ejecuta ping indefinidamente
|
||||||
|
ping "$destino"
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "marimo"
|
name = "marimo"
|
||||||
version = "0.15.1"
|
version = "0.15.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "click" },
|
{ name = "click" },
|
||||||
@@ -223,9 +223,9 @@ dependencies = [
|
|||||||
{ name = "uvicorn" },
|
{ name = "uvicorn" },
|
||||||
{ name = "websockets" },
|
{ name = "websockets" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/7a/aa/6f9ddd2b12220e442e9aa34ab370e449ee4c56f610e6cad6c648075bc59b/marimo-0.15.1.tar.gz", hash = "sha256:ff46f0d61fb2132afee9f1195b81cadbfddc64707451549179c3ae52cdbf17c2", size = 31191348, upload-time = "2025-08-28T18:53:59.222Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/6f/b8/fb55e2943bf2ac958b3c2975ed3d8022edc7763b674f65af75ded2859bd2/marimo-0.15.2.tar.gz", hash = "sha256:726933fd9c9561fa73e323b1821b173c5e0f85196ec2a497a3509cc2fc245c58", size = 31191439, upload-time = "2025-08-29T16:56:46.748Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/b6/df/2fb4a9db612bbf70a3ae6a2b223ac1421de2778d4ced3edb388e39287b39/marimo-0.15.1-py3-none-any.whl", hash = "sha256:5bb75bead625c2c5153d1be70748042707469f6f8564e126d4ad4d05856529e0", size = 31427631, upload-time = "2025-08-28T18:54:03.001Z" },
|
{ url = "https://files.pythonhosted.org/packages/6e/e6/eb732caaea80ca1d0b3a66c862a062dcd031ed1348291b78362aec9dd1c2/marimo-0.15.2-py3-none-any.whl", hash = "sha256:630cbad0217fb6cd8f78e6775b955242c1528a673233095dec5901781588bee9", size = 31427634, upload-time = "2025-08-29T16:56:52.564Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Reference in New Issue
Block a user