Streamlit

Streamlit

Tutorial Streamlit: Widgets de UI dinámicos e interactivos

Descubre cómo usar `st.button` y `st.checkbox` en Streamlit para crear aplicaciones interactivas y mejorar la experiencia del usuario en Python Streamlit.

Aprende Streamlit GRATIS y certifícate

Uso de botones y checkboxes: st.button, st.checkbox

Los botones y las casillas de verificación son elementos fundamentales para crear interactividad en una aplicación Streamlit. Con st.button y st.checkbox, es posible capturar acciones del usuario y responder en consecuencia.

El método st.button genera un botón en la interfaz. Cuando el usuario hace clic en él, se puede desencadenar una acción específica. Por ejemplo:

if st.button('Enviar'):
    st.write('¡Formulario enviado con éxito!')

En este caso, al pulsar el botón con la etiqueta 'Enviar', se mostrará el mensaje '¡Formulario enviado con éxito!' en la aplicación. El uso de condiciones if junto con st.button permite controlar el flujo según la interacción del usuario.

Por otro lado, st.checkbox crea una casilla de verificación que puede estar marcada o desmarcada. Este widget es útil para togglear opciones o configuraciones. A continuación, un ejemplo práctico:

mostrar_grafico = st.checkbox('Mostrar gráfico de datos')

if mostrar_grafico:
    st.line_chart(datos)

Si el usuario marca la casilla 'Mostrar gráfico de datos', se visualizará el gráfico lineal basado en el conjunto de datos proporcionado. La variable mostrar_grafico almacena un valor booleano que refleja el estado actual de la casilla de verificación.

Es posible personalizar ambos widgets con parámetros adicionales. Por ejemplo, se puede establecer un estado inicial predeterminado para st.checkbox utilizando el parámetro value:

notificaciones = st.checkbox('Recibir notificaciones', value=True)

Aquí, la casilla 'Recibir notificaciones' aparecerá marcada por defecto. Para deshabilitar un botón o casilla de verificación, evitando que el usuario interactúe con ellos, se utiliza el parámetro disabled:

st.button('Procesar', disabled=True)
st.checkbox('Acepto los términos', disabled=True)

Mediante el uso de st.button y st.checkbox, se logra una interacción dinámica que enriquece la funcionalidad de la aplicación. Es esencial utilizarlos de forma coherente para ofrecer una experiencia de usuario intuitiva y eficiente.

Controles de selección: st.selectbox, st.multiselect, st.radio

Los controles de selección son componentes esenciales en Streamlit para permitir que el usuario interactúe con la aplicación eligiendo entre múltiples opciones. Los widgets st.selectbox, st.multiselect y st.radio ofrecen diferentes formas de presentar estas opciones en la interfaz.

El método st.selectbox muestra un cuadro desplegable que permite seleccionar una única opción de una lista. Es útil cuando se dispone de un gran número de opciones y se desea ahorrar espacio en la pantalla. A continuación, un ejemplo de uso:

opcion_seleccionada = st.selectbox(
    'Selecciona tu fruta favorita:',
    ['Manzana', 'Banana', 'Naranja', 'Fresa', 'Mango']
)

st.write(f'Has seleccionado: **{opcion_seleccionada}**')

En este ejemplo, el usuario puede elegir su fruta favorita de una lista. La variable opcion_seleccionada almacenará la opción seleccionada, que luego se muestra en pantalla.

El widget st.multiselect permite al usuario seleccionar múltiples opciones de una lista. Es ideal cuando se requiere elegir más de un elemento. Por ejemplo:

opciones_seleccionadas = st.multiselect(
    'Selecciona tus lenguajes de programación preferidos:',
    ['Python', 'JavaScript', 'C++', 'Java', 'Go', 'Rust']
)

st.write('Has seleccionado:', ', '.join(opciones_seleccionadas))

Aquí, el usuario puede seleccionar varios lenguajes de programación. La variable opciones_seleccionadas es una lista que contiene todas las opciones elegidas.

El control st.radio presenta las opciones como botones de radio, permitiendo que el usuario seleccione solo una opción de un conjunto pequeño. Es útil cuando hay pocas opciones y se quiere mostrarlas todas visiblemente. Por ejemplo:

genero = st.radio(
    'Selecciona tu género:',
    ['Masculino', 'Femenino']
)

st.write(f'Has seleccionado: **{genero}**')

En este caso, las opciones se muestran como botones de radio, y el usuario puede seleccionar una de ellas.

Todos estos widgets aceptan parámetros adicionales para mejorar la experiencia del usuario:

  • options: Una lista de elementos que se muestran como opciones.
  • index: Determina la opción que aparece seleccionada por defecto.
  • key: Una clave única para mantener el estado del widget.

Por ejemplo, para establecer una opción predeterminada en st.selectbox:

pais = st.selectbox(
    'Selecciona tu país:',
    ['España', 'México', 'Argentina', 'Colombia', 'Chile'],
    index=0
)

Aquí, 'España' aparecerá seleccionada por defecto.

Además, los controles de selección pueden trabajar con estructuras de datos más complejas, como diccionarios o listas de tuplas. Por ejemplo, si se desea mostrar opciones con etiquetas y valores distintos:

opciones = [('Manzana', 1), ('Banana', 2), ('Naranja', 3)]
opcion = st.selectbox('Selecciona una fruta:', opciones, format_func=lambda x: x[0])

st.write(f'ID de la fruta seleccionada: {opcion[1]}')

Utilizando el parámetro format_func, se puede personalizar cómo se muestran las opciones en la interfaz, mientras se trabaja con datos subyacentes más complejos.

Entradas de datos: st.text_input, st.number_input, st.text_area

Los widgets st.text_input, st.number_input y st.text_area permiten al usuario proporcionar información que puede ser procesada en tiempo real.

El método st.text_input crea un campo de texto de una sola línea, ideal para capturar información breve como nombres, correos electrónicos o contraseñas. Por ejemplo:

nombre = st.text_input('Introduce tu nombre')
st.write(f'Hola, **{nombre}**')

En este ejemplo, el valor introducido por el usuario en st.text_input se almacena en la variable nombre, que luego se muestra en la aplicación. Es posible establecer un valor por defecto utilizando el parámetro value:

ciudad = st.text_input('Ciudad de residencia', value='Madrid')

Además, para ocultar la entrada del usuario, como en el caso de contraseñas, se utiliza el parámetro type con el valor 'password':

contraseña = st.text_input('Contraseña', type='password')

El widget st.number_input permite al usuario introducir valores numéricos, ya sean enteros o decimales. Este widget es útil cuando se requiere un control más preciso sobre los datos numéricos, incluyendo límites y pasos específicos:

edad = st.number_input('Introduce tu edad', min_value=0, max_value=120, value=25, step=1)
st.write(f'Tienes **{edad}** años')

En este caso, el usuario puede introducir una edad entre 0 y 120 años, con un valor inicial de 25 y un paso de 1. Si se necesita un valor decimal, se puede ajustar el parámetro step:

altura = st.number_input('Altura en metros', min_value=0.0, max_value=3.0, value=1.70, step=0.01)
st.write(f'Tu altura es **{altura}** metros')

El widget st.text_area ofrece un campo de texto de múltiples líneas, ideal para recopilar entradas de texto más extensas como comentarios, descripciones o código. Un ejemplo de uso podría ser:

comentarios = st.text_area('Déjanos tus comentarios')
if comentarios:
    st.write('Has escrito:')
    st.write(f'> {comentarios}')

Aquí, si el usuario introduce algún texto en st.text_area, se mostrará en la aplicación. Es posible ajustar la altura del área de texto mediante el parámetro height:

codigo = st.text_area('Introduce tu código', height=200)

Además, se pueden establecer valores por defecto y utilizar el parámetro placeholder para mostrar un texto orientativo cuando el campo está vacío:

busqueda = st.text_input('Buscar', placeholder='Escribe aquí para buscar...')

Los widgets de entrada también permiten controlar la interactividad de la aplicación mediante el uso de claves (key) y estados. Por ejemplo, para mantener el valor de un campo de texto entre ejecuciones:

if 'nombre' not in st.session_state:
    st.session_state['nombre'] = ''

st.session_state['nombre'] = st.text_input('Nombre', st.session_state['nombre'])
st.write(f'Bienvenido, **{st.session_state["nombre"]}**')

Es posible deshabilitar los widgets para evitar que el usuario interactúe con ellos en determinadas condiciones:

email = st.text_input('Correo electrónico', disabled=True)

Mediante la combinación de estos widgets, se pueden crear formularios interactivos que recogen información del usuario y reaccionan en tiempo real. Por ejemplo, una calculadora de índice de masa corporal (IMC):

peso = st.number_input('Peso en kg', min_value=0.0, max_value=200.0, value=70.0, step=0.1)
altura = st.number_input('Altura en metros', min_value=0.0, max_value=2.5, value=1.75, step=0.01)

if peso > 0 and altura > 0:
    imc = peso / (altura ** 2)
    st.write(f'Tu IMC es **{imc:.2f}**')

También es posible validar entradas y proporcionar retroalimentación al usuario:

nota = st.number_input('Introduce una nota entre 0 y 10', min_value=0.0, max_value=10.0, value=5.0, step=0.1)

if nota >= 5.0:
    st.success('¡Has aprobado!')
else:
    st.error('Lo siento, has suspendido.')

Estos widgets ofrecen múltiples opciones para personalizar el comportamiento y la apariencia de las entradas de datos, mejorando la experiencia de usuario en las aplicaciones de Streamlit.

Controles de fecha y hora: st.date_input, st.time_input

Los controles de fecha y hora son elementos esenciales para aplicaciones que requieren entradas temporales por parte del usuario. Streamlit proporciona los widgets st.date_input y st.time_input para facilitar la recolección de fechas y horas de manera interactiva y sencilla.

El widget st.date_input permite al usuario seleccionar una fecha. Es especialmente útil en aplicaciones donde se necesita especificar días para reservas, eventos o filtros temporales. A continuación, se muestra un ejemplo básico de su uso:

import streamlit as st
from datetime import date

fecha_seleccionada = st.date_input(
    "Selecciona una fecha",
    date.today()
)

st.write(f"Has seleccionado: **{fecha_seleccionada}**")

En este ejemplo, el widget muestra un calendario que por defecto tiene marcada la fecha actual gracias a date.today(). El usuario puede navegar por meses y años para elegir la fecha deseada. La variable fecha_seleccionada almacena el valor seleccionado y se muestra en la aplicación.

El widget st.date_input acepta varios parámetros opcionales que permiten personalizar su comportamiento:

  • label: Etiqueta que describe el propósito del widget.
  • value: Valor predeterminado. Puede ser una fecha simple o una lista de fechas para permitir selección múltiple.
  • min_value y max_value: Establecen los límites mínimo y máximo para la selección de fechas.
  • key: Clave única para el control del estado.

Por ejemplo, para restringir las fechas a un rango específico:

fecha_actual = date.today()
fecha_final = date(fecha_actual.year, 12, 31)

inicio = st.date_input(
    "Fecha de inicio",
    fecha_actual,
    min_value=date(fecha_actual.year, 1, 1),
    max_value=fecha_final
)

fin = st.date_input(
    "Fecha de fin",
    fecha_final,
    min_value=inicio,
    max_value=fecha_final
)

st.write(f"Rango seleccionado: **{inicio}** a **{fin}**")

Aquí, la fecha de fin no puede ser anterior a la fecha de inicio, garantizando un rango válido.

El widget st.time_input permite al usuario seleccionar una hora específica. Es útil en aplicaciones de programación de citas, alarmas o cualquier funcionalidad que requiera una entrada temporal precisa. Un ejemplo básico es el siguiente:

import streamlit as st
from datetime import time

hora_seleccionada = st.time_input(
    "Selecciona una hora",
    time(12, 00)
)

st.write(f"Has seleccionado: **{hora_seleccionada}**")

En este caso, el widget muestra un selector de hora con el valor predeterminado de las 12:00. El usuario puede ajustar las horas y minutos según sea necesario. La variable hora_seleccionada captura la hora elegida.

Al igual que st.date_input, el widget st.time_input también admite parámetros adicionales:

  • label: Etiqueta descriptiva para el widget.
  • value: Valor por defecto, que debe ser un objeto datetime.time.
  • key: Clave para el control del estado.

Es posible combinar ambos widgets para permitir la selección conjunta de fecha y hora:

import streamlit as st
from datetime import datetime, time

fecha = st.date_input("Fecha del evento", datetime.today())
hora = st.time_input("Hora del evento", time(18, 00))

fecha_hora = datetime.combine(fecha, hora)

st.write(f"El evento está programado para: **{fecha_hora}**")

En este ejemplo, se crea un objeto datetime combinando la fecha y la hora seleccionadas por el usuario. Esto es especialmente útil para aplicaciones que manejan eventos temporales específicos.

Además, es posible utilizar estos widgets en conjunto con otros elementos de Streamlit para crear interfaces más complejas. Por ejemplo, filtrar datos en función de un rango de fechas:

import streamlit as st
import pandas as pd

df = pd.read_csv("./ventas.csv", parse_dates=["fecha"])

fecha_minima = df["fecha"].min()
fecha_maxima = df["fecha"].max()

fecha_inicio = st.date_input(
    "Fecha de inicio", 
    df["fecha"].min(), 
    min_value=fecha_minima, 
    max_value=fecha_maxima
).strftime("%Y-%m-%d")
fecha_fin = st.date_input(
    "Fecha de fin", 
    df["fecha"].max(), 
    min_value=fecha_minima, 
    max_value=fecha_maxima
).strftime("%Y-%m-%d")


filtro = (df["fecha"] >= fecha_inicio) & (df["fecha"] <= fecha_fin)
datos_filtrados = df[filtro]

st.write(f"Mostrando datos desde **{fecha_inicio}** hasta **{fecha_fin}**")
st.dataframe(datos_filtrados)

En este caso, se utiliza st.date_input para que el usuario pueda seleccionar un rango de fechas, y se filtran los datos del DataFrame en función de ese rango.

Para mejorar la experiencia de usuario, se pueden añadir mensajes informativos que orienten al usuario en la selección de fechas y horas:

fecha_cita = st.date_input("Fecha de la cita")
if fecha_cita < date.today():
    st.warning("La fecha seleccionada es anterior a hoy.")
else:
    st.success("Fecha válida para programar la cita.")

Los widgets st.date_input y st.time_input proporcionan una manera eficiente y amigable de capturar entradas de fecha y hora en las aplicaciones de Streamlit, permitiendo crear interfaces interactivas y dinámicas.

Carga y manejo de archivos con st.file_uploader

El widget st.file_uploader permite al usuario cargar archivos en la aplicación Streamlit, facilitando el procesamiento de datos proporcionados por el usuario. Este widget es esencial para aplicaciones que requieren análisis de archivos como imágenes, documentos, hojas de cálculo o cualquier otro tipo de datos.

Para utilizar st.file_uploader, se especifica una etiqueta descriptiva que aparecerá en la interfaz:

archivo_subido = st.file_uploader("Selecciona un archivo")

Este código mostrará un botón que permite al usuario seleccionar un archivo desde su dispositivo. El objeto archivo_subido almacenará el archivo cargado, el cual puede ser un BytesIO, un StringIO o un UploadedFile, dependiendo del tipo de archivo y su tamaño.

Es posible restringir los tipos de archivos que el usuario puede cargar utilizando el parámetro type. Por ejemplo, para permitir solo archivos de texto plano:

archivo_texto = st.file_uploader("Carga un archivo de texto", type="txt")

También se pueden especificar múltiples extensiones aceptadas proporcionando una lista:

archivo_datos = st.file_uploader(
    "Carga un archivo de datos",
    type=["csv", "xlsx"]
)

En este caso, el usuario podrá cargar archivos con extensiones csv o xlsx, lo que permite flexibilidad en los formatos de entrada.

Para habilitar la carga de múltiples archivos simultáneamente, se utiliza el parámetro accept_multiple_files ajustándolo a True:

archivos_imagenes = st.file_uploader(
    "Carga una o más imágenes",
    type=["png", "jpg", "jpeg"],
    accept_multiple_files=True
)

La variable archivos_imagenes será una lista de objetos UploadedFile. Se pueden procesar individualmente utilizando un bucle:

if archivos_imagenes:
    for imagen in archivos_imagenes:
        st.image(imagen, caption=imagen.name)

Este código muestra cada imagen cargada junto con su nombre de archivo.

Una vez cargado el archivo, es posible leer y procesar su contenido. Por ejemplo, para leer un archivo de texto:

if archivo_texto is not None:
    contenido = archivo_texto.read().decode("utf-8")
    st.text_area("Contenido del archivo", value=contenido, height=250)

En el caso de archivos CSV, se puede utilizar pandas para leer y visualizar los datos:

import pandas as pd

if archivo_datos is not None:
    if archivo_datos.type == "text/csv":
        df = pd.read_csv(archivo_datos)
    else:
        df = pd.read_excel(archivo_datos)
    st.dataframe(df)

Este fragmento verifica el tipo de archivo y utiliza la función adecuada para leerlo. Luego, muestra los datos en un DataFrame interactivo.

Para manejar archivos PDF, se puede emplear la biblioteca PyPDF2 o similar:

import PyPDF2

archivo_pdf = st.file_uploader("Carga un documento PDF", type="pdf")

if archivo_pdf is not None:
    lector_pdf = PyPDF2.PdfReader(archivo_pdf)
    num_paginas = len(lector_pdf.pages)
    st.write(f"El documento tiene **{num_paginas}** páginas.")
    for i, pagina in enumerate(lector_pdf.pages):
        texto = pagina.extract_text()
        st.write(f"**Página {i+1}:**")
        st.write(texto)

Este código extrae y muestra el texto de cada página del PDF cargado.

Es importante manejar adecuadamente los archivos binarios, como imágenes o archivos de audio. Por ejemplo, para mostrar una imagen cargada:

imagen = st.file_uploader("Carga una imagen", type=["png", "jpg", "jpeg"])

if imagen is not None:
    st.image(imagen, caption="Imagen cargada", use_container_width=True)

Para archivos de audio, se puede utilizar st.audio:

audio = st.file_uploader("Carga un archivo de audio", type=["mp3", "wav"])

if audio is not None:
    st.audio(audio, format='audio/mp3')

Al trabajar con archivos potencialmente grandes, es recomendable informar al usuario sobre el progreso del procesamiento. Se puede emplear st.progress:

if archivo_subido is not None:
    tamaño = len(archivo_subido.getbuffer())
    barra_progreso = st.progress(0)
    for porcentaje in range(100):
        # Simular procesamiento
        time.sleep(0.01)
        barra_progreso.progress(porcentaje + 1)
    st.success(f"Archivo de **{tamaño} bytes** procesado correctamente.")

Además, es aconsejable manejar excepciones y errores para mejorar la robustez de la aplicación:

try:
    # Código para procesar el archivo
    pass
except Exception as e:
    st.error(f"Se produjo un error: {e}")

El parámetro key permite asignar una clave única al widget, lo cual es útil cuando existen múltiples widgets similares:

archivo1 = st.file_uploader("Archivo 1", key="uploader1")
archivo2 = st.file_uploader("Archivo 2", key="uploader2")

Para mejorar la experiencia de usuario, se pueden proporcionar instrucciones claras y utilizar placeholders:

if archivo_subido is None:
    st.info("Por favor, carga un archivo para continuar.")
else:
    # Procesar el archivo
    pass

También es posible limitar el tamaño máximo de los archivos mediante validaciones personalizadas:

tamaño_maximo = 10 * 1024 * 1024  # 10 MB

if archivo_subido is not None:
    if archivo_subido.size > tamaño_maximo:
        st.error("El archivo excede el tamaño máximo permitido de 10 MB.")
    else:
        # Procesar el archivo
        pass

Finalmente, es esencial considerar las implicaciones de seguridad al permitir cargas de archivos. Se deben validar y sanitizar los archivos antes de su procesamiento para evitar la ejecución de código malicioso o la exposición de datos sensibles.

Para seguir leyendo hazte Plus

¿Ya eres Plus? Accede a la app

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende Streamlit GRATIS online

Todas las lecciones de Streamlit

Accede a todas las lecciones de Streamlit y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Accede GRATIS a Streamlit y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  • Dominar el uso de st.button para ejecutar acciones al pulsar un botón.
  • Implementar st.checkbox para gestionar opciones booleanas en la interfaz.
  • Personalizar widgets con parámetros adicionales como value y disabled.
  • Incorporar emojis para mejorar la usabilidad y estética de los botones.