Callbacks: on_change y on_click
Los callbacks son funciones que se ejecutan antes de que el script se re-ejecute cuando un widget cambia de valor. Este orden de ejecución es fundamental: primero se ejecuta el callback, después se re-ejecuta el script de arriba a abajo. Esto permite preparar el estado, validar datos o derivar valores calculados que estarán disponibles cuando el resto del script se ejecute.
Los callbacks se vinculan a los widgets mediante los parámetros on_change (para widgets que almacenan un valor) y on_click (para botones):
import streamlit as st
# Callback sin argumentos
def calcular_total():
precio = st.session_state.get("precio", 0)
cantidad = st.session_state.get("cantidad", 1)
st.session_state.total = precio * cantidad
precio = st.number_input("Precio unitario (€)", value=10.0, key="precio", on_change=calcular_total)
cantidad = st.number_input("Cantidad", value=1, min_value=1, key="cantidad", on_change=calcular_total)
total = st.session_state.get("total", precio * cantidad)
st.metric("Total", f"€ {total:.2f}")
Un aspecto importante de los callbacks es que se ejecutan antes del rerun, no durante. Esto significa que los valores actualizados en
session_statedentro del callback ya están disponibles cuando el script empieza a ejecutarse de nuevo, lo que permite inicializar la interfaz con datos derivados o calculados.
sequenceDiagram
participant User as Usuario
participant Widget as Widget Streamlit
participant CB as Callback on_change
participant Script as Script principal
participant State as session_state
User->>Widget: Cambia valor
Widget->>CB: Ejecuta antes del rerun
CB->>State: Actualiza cálculos derivados
CB->>State: Valida o transforma
Widget->>Script: Dispara rerun completo
Script->>State: Lee estado calculado
Script->>User: Renderiza UI nueva
Note over CB,State: args y kwargs personalizan callback
Callbacks con argumentos: args y kwargs
Cuando el callback necesita saber qué widget lo invocó o recibir datos contextuales, se pueden pasar argumentos posicionales con args (tupla) y argumentos con nombre con kwargs (diccionario):
import streamlit as st
def actualizar_historial(nombre_widget, valor_nuevo=None):
if "historial_cambios" not in st.session_state:
st.session_state.historial_cambios = []
valor = valor_nuevo or st.session_state.get(nombre_widget, "N/A")
st.session_state.historial_cambios.append(f"{nombre_widget} → {valor}")
# args: tupla posicional
region = st.selectbox(
"Región",
["Norte", "Sur", "Este", "Oeste"],
key="region",
on_change=actualizar_historial,
args=("region",)
)
# kwargs: diccionario
año = st.slider(
"Año",
2020, 2026, 2025,
key="año",
on_change=actualizar_historial,
kwargs={"nombre_widget": "año"}
)
with st.expander("Historial de cambios"):
for cambio in st.session_state.get("historial_cambios", []):
st.write(f"• {cambio}")
on_click en st.button
import streamlit as st
import pandas as pd
import numpy as np
def cargar_datos(fuente):
st.session_state.df = pd.DataFrame(
np.random.randn(100, 3),
columns=[f"Col_{i}" for i in range(1, 4)]
)
st.session_state.fuente_datos = fuente
st.session_state.datos_cargados = True
# El callback se ejecuta cuando se hace clic, ANTES del rerun
st.button("Cargar datos de producción", on_click=cargar_datos, args=("produccion",))
st.button("Cargar datos de prueba", on_click=cargar_datos, args=("prueba",))
if st.session_state.get("datos_cargados"):
st.success(f"Datos cargados desde: **{st.session_state.fuente_datos}**")
st.dataframe(st.session_state.df.head())
st.query_params: parámetros de URL
st.query_params permite leer y modificar los parámetros de la query string de la URL, haciendo posible crear URLs compartibles que preservan el estado de los filtros de la aplicación. Cuando un usuario comparte la URL con los parámetros, el destinatario ve la misma vista filtrada al abrir el enlace:
import streamlit as st
# URL: http://localhost:8501/?region=Norte&año=2026
# Leer parámetros de la URL (con valores por defecto)
region = st.query_params.get("region", "Norte")
año = int(st.query_params.get("año", 2026))
st.title("Dashboard de ventas")
# Los widgets se inicializan con los valores de la URL
region_sel = st.selectbox("Región", ["Norte", "Sur", "Este", "Oeste"],
index=["Norte", "Sur", "Este", "Oeste"].index(region))
año_sel = st.slider("Año", 2020, 2026, año)
# Actualizar la URL cuando cambien los widgets
st.query_params["region"] = region_sel
st.query_params["año"] = str(año_sel)
st.write(f"Mostrando datos de **{region_sel}** en **{año_sel}**")
st.caption(f"URL compartible: ?region={region_sel}&año={año_sel}")
# Limpiar todos los parámetros
if st.button("Restablecer URL"):
st.query_params.clear()
st.rerun()
st.context: información del entorno del usuario
st.context proporciona acceso a información sobre el entorno del usuario que ejecuta la aplicación, como el tema visual activo y el idioma del navegador. Esta información permite adaptar dinámicamente la interfaz al contexto del usuario:
import streamlit as st
st.title("Información del contexto")
# Tema activo del usuario
tema = st.context.theme
st.write(f"Tema activo: **{tema}** (light/dark/auto)")
# Locale del usuario (idioma del navegador)
locale = st.context.locale
st.write(f"Locale del navegador: **{locale}**")
# Adaptar la app según el tema
if tema == "dark":
color_grafico = "#FFFFFF"
else:
color_grafico = "#000000"
st.write(f"Color del gráfico adaptado al tema: {color_grafico}")
Patrón completo: dashboard con estado en URL
import streamlit as st
import pandas as pd
import numpy as np
# Leer estado de URL
defaults = {
"año": "2026",
"region": "Norte",
"metrica": "ventas"
}
params = {k: st.query_params.get(k, v) for k, v in defaults.items()}
st.title("Dashboard compartible")
st.caption("Los filtros se guardan en la URL para compartir con el equipo.")
with st.sidebar:
año = st.select_slider("Año", [2020, 2021, 2022, 2023, 2024, 2025, 2026],
value=int(params["año"]))
region = st.selectbox("Región", ["Norte", "Sur", "Este", "Oeste"],
index=["Norte", "Sur", "Este", "Oeste"].index(params["region"]))
metrica = st.radio("Métrica", ["ventas", "costes", "beneficio"],
index=["ventas", "costes", "beneficio"].index(params["metrica"]))
# Actualizar URL
st.query_params["año"] = str(año)
st.query_params["region"] = region
st.query_params["metrica"] = metrica
# Mostrar datos con los filtros aplicados
np.random.seed(int(año))
df = pd.DataFrame({"mes": range(1, 13), metrica: np.random.randint(5000, 15000, 12)})
st.subheader(f"{metrica.capitalize()} — {region} ({año})")
st.line_chart(df, x="mes", y=metrica)
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Streamlit es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Streamlit
Explora más contenido relacionado con Streamlit y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Usar on_change para ejecutar funciones cuando cambia el valor de un widget. Implementar on_click en st.button para ejecutar acciones en el momento del clic. Pasar argumentos a los callbacks con los parámetros args y kwargs. Leer y modificar parámetros de la URL con st.query_params para URLs compartibles. Acceder al contexto del usuario (tema, dispositivo) con st.context.