import marimo __generated_with = "0.15.2" app = marimo.App(width="columns") @app.cell(column=0) def _(): import marimo as mo return (mo,) @app.cell def _(mo): mo.md(r"""# Altair: graficos interactivos""") return @app.cell def _(): from vega_datasets import data import altair as alt import pandas as pd import pyarrow return alt, data, 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()