Streamlit — Módulo 1

Introducción y entorno de trabajo

@josephinoo

2026-04-13

🎈

Módulo 1

Introducción y Entorno de Trabajo

¿Qué es Streamlit?

La promesa de Streamlit

Python → App Web 🚀

¿Qué problema resuelve?

😩
Sin Streamlit
Aprender HTML/CSS/JS
Frameworks web complejos
Backend + Frontend separados
Despliegue complicado
Semanas de trabajo
VS
😍
Con Streamlit
Solo Python
Un solo archivo .py
App lista al instante
Deploy en 1 click
Horas, no semanas

Quién usa Streamlit

🔬
Data Scientists
Modelos de ML en producción sin ingeniería web
📊
Analistas
Dashboards interactivos desde pandas y matplotlib
🎓
Estudiantes
Proyectos finales con interfaz profesional
🏢
Empresas
Prototipos rápidos y herramientas internas

🏆 Más de 30 millones de apps creadas · Usado por Google, Airbnb, Uber, NASA

Instalación y primer arranque

Requisitos previos

Python 3.8+
python --version
pip (viene con Python)
pip --version
Un terminal / VS Code
cualquier editor de texto sirve

💡 Recomendado: Crea un entorno virtual primero → python -m venv venvsource venv/bin/activate

Instalación — 1 solo comando

Terminal
$ pip install streamlit

Luego verificar: streamlit --version → debería mostrar la versión instalada

Tu primera app — hello.py

📄 hello.py
import streamlit as st

st.title("¡Hola, Streamlit! 🎈")
st.write("Mi primera app en Python.")
$ streamlit run hello.py
🌐 localhost:8501
¡Hola, Streamlit! 🎈
Mi primera app en Python.

Anatomía del comando streamlit run

streamlit
El programa principal
run
Subcomando: ejecutar una app
hello.py
Tu script de Python
Opciones útiles:
--server.port 8502 — cambiar el puerto
--server.headless true — no abrir el browser
--logger.level debug — ver más logs

El Scripting Flow — el corazón de Streamlit 🧠

¿Cómo ejecuta Streamlit tu código?

De arriba → abajo, siempre 🔄

El flujo paso a paso

1
Usuario abre la app
Streamlit ejecuta el script completo de arriba a abajo
2
Usuario interactúa (click, slider, input...)
Streamlit vuelve a ejecutar TODO el script desde cero
3
Streamlit compara el resultado
Solo actualiza en pantalla lo que cambió (DOM diffing)
4
Pantalla actualizada ✅
El usuario ve el nuevo resultado al instante

Demo del Scripting Flow

📄 app.py
import streamlit as st
st.title("Demo")
nombre = st.text_input("Tu nombre")
if nombre:
st.write(f"¡Hola, {nombre}! 👋")
🌐 localhost:8501
Demo
🔄 Ejecuciones del script:

La regla de oro 🥇

🔄
Cada interacción del usuario = re-ejecución completa del script
El orden del código importa — lo que está arriba se ejecuta primero
Las variables no persisten entre ejecuciones (a menos que uses st.session_state)
El código Python normal funciona exactamente igual — Streamlit solo agrega widgets

Widgets de Texto y Títulos 📝

st.title() · st.header() · st.subheader()

📄 código
import streamlit as st

st.title("Título Principal")
# Argumento: texto (str)
# Nivel H1 — el más grande

st.header("Sección")
# Argumento: texto (str)
# Nivel H2 — para secciones

st.subheader("Subsección")
# Argumento: texto (str)
# Nivel H3 — para subsecciones
🌐 resultado
Título Principal
Sección
Subsección

Los tres aceptan anchor (para links internos) y help (tooltip). Ej: st.title("App", anchor="inicio")

st.write() — el comando todo-en-uno

st.write() acepta casi cualquier cosa:
st.write("Texto normal")
Texto normal
st.write("**Negrita** y *cursiva*")
Negrita y cursiva
st.write(42)
42
st.write({"a": 1, "b": 2})
{ "a": 1, "b": 2 }
st.write(df)
📊 tabla interactiva
st.write(figura)
📈 gráfico

st.text() · st.markdown() · st.caption()

📄 código
st.text("Texto plano sin formato.")
# Argumento: body (str)
# Sin markdown — literal

st.markdown("**Negrita**, *cursiva*, `código`")
# Argumento: body (str)
# unsafe_allow_html=True → HTML directo

st.caption("Nota al pie o aclaración")
# Argumento: body (str)
# Texto pequeño y gris — ideal para
# fuentes, notas y aclaraciones
🌐 resultado
Texto plano sin formato.
Negrita, cursiva, código
Nota al pie o aclaración

st.code() · st.divider()

📄 código
st.code("""
def saludar(nombre):
    return f"Hola, {nombre}!"
""", language="python")
# language: "python","sql","bash","json"...
# line_numbers=True → muestra nros de línea

st.divider()
# Sin argumentos
# Solo dibuja una línea separadora
# Equivalente a st.markdown("---")
🌐 resultado
def saludar(nombre):
    return f"Hola, {nombre}!"

Inputs Simples — El Usuario Habla 🎛️

st.button()

clicked = st.button(
    label="Haz clic aquí",  # texto del botón (str) *obligatorio*
    key="mi_boton",         # ID único (str) — necesario si hay varios
    help="Tooltip al hover",# texto de ayuda (str)
    type="primary",         # "primary" (azul) o "secondary" (gris)
    disabled=False,         # deshabilitar (bool)
    use_container_width=True# ancho completo (bool)
)

if clicked:
    st.write("¡Botón presionado! 🎉")
⚠️ Comportamiento clave:
Devuelve True solo en la ejecución inmediatamente posterior al click
En la siguiente re-ejecución vuelve a False
Para estado persistente → st.session_state

st.checkbox() · st.text_input()

st.checkbox()
activo = st.checkbox(
    label="Activar opción",
    value=False,    # estado inicial (bool)
    key="check1",   # ID único
    help="Ayuda",   # tooltip
    disabled=False  # deshabilitar
)
# Devuelve True/False
st.text_input()
texto = st.text_input(
    label="Escribe algo",
    value="",         # valor inicial (str)
    max_chars=100,    # máx caracteres (int)
    key="input1",     # ID único
    type="default",   # "default" o "password"
    placeholder="..."  # texto fantasma
)
# Devuelve el string escrito

st.number_input() · st.slider()

st.number_input()
num = st.number_input(
    label="Edad",
    min_value=0,    # mínimo (int/float)
    max_value=120,  # máximo (int/float)
    value=25,       # valor inicial
    step=1,         # incremento
    format="%d",    # formato de display
    key="num1"
)
# Devuelve int o float
Resultado: 25
25
st.slider()
val = st.slider(
    label="Temperatura",
    min_value=0,    # mínimo
    max_value=100,  # máximo
    value=50,       # inicial (o tupla para rango)
    step=1,         # paso
    format="%d°C",  # formato del label
    key="slider1"
)
# value=(20,80) → slider de rango
Valor: 50°C

Feedback Visual — La App Habla 💬

Los mensajes de estado

st.success("Operación exitosa ✅")
✅ Operación exitosa
st.error("Algo salió mal ❌")
❌ Algo salió mal
st.warning("Cuidado ⚠️")
⚠️ Cuidado con esto
st.info("Para tu información 💡")
💡 Para tu información
Todos comparten los mismos argumentos:
body (str) — el mensaje  ·  icon (str) — emoji o None  ·  expanded (bool) — colapsable si es largo

st.balloons() · st.spinner()

🎈 st.balloons()
if st.button("Celebrar"):
    st.balloons()
# Sin argumentos
# Lanza una animación de globos
# Perfecto para onboarding y logros
⏳ st.spinner()
with st.spinner("Procesando..."):
    time.sleep(2)      # simulación
    resultado = calcular()
# text (str): mensaje del spinner
# Se usa como context manager (with)
# Mientras dura el bloque → spinner activo

Layout Básico — Organizar la App 🏗️

st.columns()

col1, col2, col3 = st.columns(3)
# Argumento 1: n_columns (int) o lista de pesos
# st.columns([2, 1, 1]) → primera columna más ancha
# gap="small"/"medium"/"large" — espacio entre cols

with col1:
    st.metric("Ventas", "$ 1,234")

with col2:
    st.metric("Clientes", "89")

with col3:
    st.metric("Conversión", "7.2%")
🌐 resultado
Ventas
$ 1,234
Clientes
89
Conversión
7.2%

st.expander() · st.container()

st.expander()
with st.expander("Ver detalles"):
    # label: texto del header (str)
    # expanded=False: cerrado por defecto
    # Ideal para: configs, logs,
    # información secundaria
    st.write("Contenido oculto...")
    st.code("print('dentro!')")
Ver detalles
st.container()
with st.container():
    # Sin argumentos obligatorios
    # border=True → borde visible
    # height=300 → altura fija + scroll
    # Agrupa widgets lógicamente
    st.write("Elemento 1")
    st.write("Elemento 2")
    # Útil para agrupar, aplicar
    # estilos o controlar layout
Elemento 1
Elemento 2

Media — Imágenes y Video 🖼️

st.image() · st.video()

📷 st.image()
st.image(
  image,                 # path, URL, PIL, numpy
  caption="Texto",       # pie de imagen (str)
  width=300,             # ancho en px
  use_column_width=True, # 100% ancho
  clamp=False,           # clamp de píxeles
  channels="RGB",        # "RGB" o "BGR"
  output_format="auto"   # "JPEG","PNG","auto"
)
🏔️
300 × 200 px
caption: "Mi foto"
🎬 st.video()
st.video(
  data,                # URL, path local, bytes
  format="video/mp4", # MIME type
  start_time=0,       # segundo de inicio
  subtitles=None      # subs VTT o dict
)
# ✓ URLs de YouTube
# ✓ Archivos .mp4 / .webm
# ✓ bytes en memoria
0:00 / 0:42
🔊
video.mp4

El Scripting Flow en acción — Todo junto 🎯

App completa de ejemplo

📄 app_completa.py
import streamlit as st

st.title("🎛️ Mi App de Demostración")
st.divider()

# Sección de inputs
col1, col2 = st.columns(2)

with col1:
    st.header("Configuración")
    nombre = st.text_input("Tu nombre", placeholder="Ej: Ana")
    edad = st.slider("Edad", 1, 100, 25)
    activo = st.checkbox("Modo avanzado")

with col2:
    st.header("Controles")
    nivel = st.number_input("Nivel", 1, 10, 1)
    if st.button("Generar", type="primary"):
        st.balloons()

st.divider()

# Sección de output — reacciona a los inputs
if nombre:
    st.success(f"¡Hola {nombre}! Tienes {edad} años.")
    if activo:
        with st.expander("Detalles avanzados"):
            st.info(f"Nivel configurado: {nivel}")
            st.code(f"usuario = dict(nombre='{nombre}', edad={edad})")
else:
    st.warning("Ingresa tu nombre para comenzar.")
🌐 resultado
🎛️ Mi App de Demostración
Tu nombre
Edad
Valor: 25
Nivel
Nivel: 1

¿Por qué el orden importa?

❌ Orden incorrecto
st.write(f"Hola {nombre}")  # ← ERROR
# nombre no existe todavía!

nombre = st.text_input("Nombre")
NameError: name 'nombre' is not defined
✅ Orden correcto
nombre = st.text_input("Nombre")
# ↑ primero definimos el widget

if nombre:
    st.write(f"Hola {nombre}")  # ✅
Funciona perfectamente 🎉

El scripting flow garantiza que el código se lee como un libro: de arriba a abajo. Primero defines, luego usas.

Resumen del Módulo 1 🏁

Todo lo que aprendiste hoy

🐍
01
Streamlit = Python → Web App
Sin HTML, sin JS, sin frameworks
💻
02
pip install + streamlit run
Dos comandos para arrancar
🔄
03
Scripting Flow
Cada interacción = re-ejecución completa
📝
04
Texto y Títulos
title, header, write, markdown, code...
🎛️
05
Inputs Simples
button, checkbox, text_input, slider...
🏗️
06
Layout y Feedback
columns, expander, success, error...

Tu producto parcial ✔️

App Base Ejecutándose
import streamlit as st

st.title("Mi Primera App 🎈")
st.write("¡Está funcionando!")

nombre = st.text_input("¿Cómo te llamas?")
edad = st.slider("¿Cuántos años tienes?", 1, 100, 25)

if nombre:
    st.success(f"¡Bienvenido/a, {nombre}! Tienes {edad} años. 🎉")
    st.balloons()
else:
    st.info("Escribe tu nombre arriba 👆")
$ streamlit run mi_app.py
✅ Módulo 1 Completo

¡A construir! 🚀

Módulo 1 — Completado

Preguntas antes de cerrar 🙋