Streamlit — Módulo 2

Widgets, Sidebar y Navegación

@josephinoo

2026-04-15

🗂️

Módulo 2

Widgets · Sidebar · Navegación

¿Qué construimos hoy?

📊 Ver Datos
📈 Ver Gráfico
Cargar CSV
tariffs.csv ✅
Filtrar año
Todos ▾
Dashboard — Aranceles USA 🇺🇸
2,847
filas
25%
arancel máx
47
países
datecountryproduct_categorytariff_rate_pct
2018-07-06ChinaTech/Industrial25.0
2018-03-08GlobalSteel25.0
↕ scroll · clic para ordenar · filtrable

✅ Sidebar con menú · ✅ Dataset real de Kaggle · ✅ Tabla interactiva · ✅ Gráfico Plotly

El Sidebar — El Panel Lateral 📌

¿Qué es el Sidebar?

😕 Sin sidebar — todo revuelto
Mi App
⚙️ Widget 1
⚙️ Widget 2
📊 Contenido mezclado con controles...
😍 Con sidebar — limpio y organizado
⚙️ Config
Widget 1
Widget 2
Mi App
📊 Contenido limpio y enfocado

Regla de oro: controles, filtros y configuración → sidebar · tablas, gráficos y resultados → centro

Las dos formas de usar el Sidebar

📝 Forma 1 — Prefijo directo
st.sidebar.title("Configuración")
st.sidebar.slider("Año", 2018, 2024)
st.sidebar.selectbox("País", ["USA","China"])
st.sidebar.button("Aplicar")
Simple para 2–3 widgets
ó
📦 Forma 2 — Bloque with
with st.sidebar:
    st.title("Configuración")
    st.slider("Año", 2018, 2024)
    st.selectbox("País", ["USA","China"])
    st.button("Aplicar")
Más limpio cuando crece el sidebar

Las dos formas hacen exactamente lo mismo. La mayoría prefiere with st.sidebar: cuando hay más de 3 widgets porque es más fácil de leer.

selectbox y radio — El Usuario Elige 🎯

st.selectbox() — Lista desplegable

📄 código
opcion = st.selectbox(
    label="¿Qué quieres ver?",
    options=["Datos", "Gráfico", "Resumen"],
    index=0,     # cuál empieza seleccionado
    key="menu",  # ID único (importante si hay varios)
    help="Elige la vista"  # tooltip con ?
)

# La variable guarda el texto elegido:
st.write(f"Elegiste: {opcion}")
🌐 demo
¿Qué quieres ver?
→ Elegiste: Datos
💡 index=0 → primer elemento por defecto
💡 Devuelve el texto de la opción elegida
💡 key es el ID único del widget

st.radio() — Botones de opción visibles

📄 código
pagina = st.radio(
    label="Navegar a:",
    options=["📊 Ver Datos", "📈 Ver Gráfico"],
    index=0,           # opción inicial
    horizontal=False,  # True = en fila horizontal
    key="navegacion"
)

if pagina == "📊 Ver Datos":
    st.write("Mostrando la tabla...")
elif pagina == "📈 Ver Gráfico":
    st.write("Mostrando el gráfico...")
🌐 demo
Navegar a:
📊 Ver Datos
📈 Ver Gráfico
→ Mostrando la tabla...
💡 Ideal para 2–4 opciones
💡 horizontal=True → botones en fila

Selectbox vs Radio — ¿Cuándo usar cuál?

selectbox 📋 radio 📻
Opciones visibles Solo la elegida Todas siempre
Cantidad ideal 5 o más ✅ 2 a 4 ✅
Espacio que ocupa Muy poco Más espacio
Úsalo para... Países, años, categorías largas Menú de páginas 👈

Para el menú de navegación → usaremos st.radio en el sidebar. Pocas opciones, siempre visibles.

Cargar Datos — El Dataset Real 📁

El dataset de hoy

Kaggle · gratuito
US Tariff & Trade War Impact Dataset
2018–presente · belbino
🔗 kaggle.com/datasets/belbino/us-tariff-and-trade-war-impact-dataset-2018-present
Columnas del CSV:
📅 date
🌍 country
📦 product_category
💰 tariff_rate_pct
📰 headline
🔗 announcement_source

¿Por qué este dataset? Tiene texto (países), números (aranceles) y fechas → perfecto para filtros, tablas y gráficos.

Descargar el dataset — 3 pasos

1
Ir a Kaggle y crear cuenta gratuita
🔗 kaggle.com → buscar "us tariff belbino" o usar el link directo de arriba
2
Hacer clic en "Download"
Se descarga un .zip — extraer el archivo CSV que hay adentro
3
Guardar el CSV en la carpeta del proyecto
mi-proyecto/
  ├── app.py
  └── tariffs.csv   ← aquí

Pausa — descarga el CSV ahora. Los que ya lo tienen esperan 2 minutos.

st.file_uploader() — el usuario sube el archivo

📄 código
archivo = st.file_uploader(
    label="Sube el CSV de Kaggle",
    type=["csv"],   # solo acepta CSV
    key="uploader",
    help="Descárgalo de Kaggle primero"
)

# ⚠️ SIEMPRE verificar antes de usar
if archivo is not None:
    df = pd.read_csv(archivo)
    st.success("¡Archivo cargado! ✅")
    st.write(df)
else:
    st.info("Sube un archivo para comenzar")
🌐 demo
📁
Haz clic aquí
o arrastra un CSV
⚠️ Si no verificas con
if archivo is not None:
la app da error al arrancar

Leer el CSV con pandas y mostrarlo

import pandas as pd   # una vez, arriba del todo

if archivo is not None:
    df = pd.read_csv(archivo)  # CSV → tabla en memoria

    # Métricas rápidas
    col1, col2, col3 = st.columns(3)
    col1.metric("Filas",         len(df))
    col2.metric("Países únicos", df["country"].nunique())
    col3.metric("Arancel máx", f"{df['tariff_rate_pct'].max():.1f}%")

    st.divider()

    # Tabla interactiva — el usuario puede ordenar y buscar
    st.dataframe(
        df,
        use_container_width=True,
        height=300,
        hide_index=True
    )
Resultado:
date ↕country ↕product_category ↕tariff_rate_pct ↕
2018-07-06ChinaTech/Industrial25.0
2018-03-08GlobalSteel25.0
2018-03-08GlobalAluminum10.0
↕ scroll · clic para ordenar · filtrable
🐼 df es solo el nombre que le damos a la tabla. Viene de "DataFrame". Puedes llamarlo como quieras.

El Menú de Navegación 🗺️

La idea — solo un if/elif

No hay magia. Es Python normal. Cuando el usuario cambia el radio → el script corre de nuevo → el if decide qué página mostrar.

El código del menú — 3 bloques

① El sidebar con el menú
with st.sidebar:
    st.title("🗂️ Navegación")
    pagina = st.radio("Ir a:", ["📊 Ver Datos", "📈 Ver Gráfico"])
② Página 1 — la tabla de datos
if pagina == "📊 Ver Datos":
    st.title("Tabla de Aranceles")
    st.dataframe(df)
③ Página 2 — el gráfico
elif pagina == "📈 Ver Gráfico":
    st.title("Gráfico de Aranceles")
    st.plotly_chart(fig)

Demo interactiva del menú

Plotly Express — Tu Primer Gráfico 📊

¿Por qué Plotly?

🖱️
Interactivo
Hover, zoom, pan — sin código extra
🎨
Bonito
Sin ajustar colores ni fuentes
🐼
Con pandas
Le pasas el DataFrame directo
Fácil
Gráfico básico = 2 líneas

pip install plotly — una vez, luego ya está disponible en todos tus proyectos.

Tu primer gráfico de barras

import plotly.express as px   # siempre así, arriba

# Datos de ejemplo
datos = {
    "País":    ["China", "Mexico", "Canada", "EU"],
    "Arancel": [25,       15,       7,        20]
}
df_ej = pd.DataFrame(datos)

# Crear el gráfico — 1 línea ✨
fig = px.bar(
    df_ej,
    x="País",        # columna para el eje X
    y="Arancel",     # columna para el eje Y
    title="Aranceles por País",
    color="Arancel",
    color_continuous_scale="Reds"
)

st.plotly_chart(fig, use_container_width=True)
3 cosas a recordar:
1import plotly.express as px
2px.bar(df, x="...", y="...")
3st.plotly_chart(fig)
📊 bar
📈 line
🥧 pie
🔵 scatter
px.bar(df, x="País", y="Arancel")

Multi-página con Archivos Separados 📂

Dos formas de organizar la app

🧩 Opción A — un solo archivo
with st.sidebar:
    pagina = st.radio("Ir a:",
        ["Datos", "Gráfico"])

if pagina == "Datos":
    st.dataframe(df)
elif pagina == "Gráfico":
    st.plotly_chart(fig)
✅ Simple · bueno para demos
⚠️ Se hace muy largo con muchas páginas
vs
📁 Opción B — archivos separados
mi-proyecto/
  app.py           ← portada
  pages/
    1_Datos.py     ← página 1
    2_Grafico.py   ← página 2
    3_Filtros.py   ← página 3
✅ Organizado · fácil de mantener
⚠️ Necesita la carpeta pages/

Streamlit detecta automáticamente la carpeta pages/ y crea el menú lateral. Sin código extra de navegación.

La carpeta pages/ y el menú automático

Estructura del proyecto:
📁 mi-proyecto/
   📄 app.pyportada
   📁 pages/especial
      📄 1_Datos.pypágina 1
      📄 2_Grafico.pypágina 2
      📄 3_Filtros.pypágina 3
   📄 tariffs.csv
💡 Los números 1_, 2_, 3_ controlan el orden. El guion bajo se convierte en espacio en el menú.
Así se ve la app:
Navegación
🏠 app
📊 Datos
📈 Grafico
🔍 Filtros
🇺🇸 Dashboard
Bienvenido.
👈 Selecciona una página
Menú generado automáticamente por Streamlit ✨

¿Qué va en cada archivo?

app.py
1_Datos.py
2_Grafico.py
# app.py — portada
import streamlit as st

# ⚠️ DEBE ser el PRIMER comando de Streamlit en el archivo
st.set_page_config(
    page_title="Dashboard Aranceles",
    page_icon="🇺🇸",
    layout="wide"
)

st.title("🇺🇸 Dashboard — Aranceles USA")
st.write("Bienvenido. Usa el menú lateral para navegar.")
st.info("👈 Selecciona una página en el menú de la izquierda")

st.stop() y st.set_page_config()

❌ Sin st.stop() — app rota
archivo = st.file_uploader("CSV")

# archivo es None al arrancar
df = pd.read_csv(archivo)
# ↑ ERROR: no se puede leer None
st.dataframe(df)
🔴 La app explota al arrancar
✅ Con st.stop() — app robusta
archivo = st.file_uploader("CSV")

if archivo is None:
    st.info("Sube un archivo 👆")
    st.stop()   # ← para aquí

# Solo llega aquí si hay archivo
df = pd.read_csv(archivo)  # seguro ✅
st.dataframe(df)
🟢 Espera pacientemente al usuario

Regla: siempre que dependas de algo que el usuario aún no hizost.stop() antes de usarlo. Y set_page_config() siempre va primero en el archivo.

Resumen del Módulo 2 🏁

Todo lo que aprendiste hoy

📌
01
Sidebar
with st.sidebar: para organizar controles
📋
02
selectbox
Lista desplegable — 5+ opciones
📻
03
radio
Opciones visibles — menú de páginas
📁
04
file_uploader
Subir CSV · verificar != None
🗺️
05
Navegación
radio + if/elif = menú de páginas
📂
06
pages/
Archivos separados · menú automático
📊
07
Plotly básico
px.bar() + st.plotly_chart()
🛑
08
st.stop()
Para la app elegantemente si falta algo
⚙️
09
set_page_config
Título + ícono · siempre primero

Tu producto parcial ✔️

✅ App Multi-página con Dataset Real
app.py con set_page_config + mensaje de bienvenida
1_Datos.py con file_uploader + st.dataframe
2_Grafico.py con px.bar + st.plotly_chart
st.stop() en cada página que usa el CSV
Carpeta pages/ con menú automático
Dataset real de Kaggle cargado y visualizado
$ streamlit run app.py
✅ Módulo 2 Completo

¡A construir! 🗂️

Módulo 2 — Completado

Preguntas antes de cerrar 🙋