Primera aplicación con st.write y st.set_page_config

Básico
Streamlit
Streamlit
Actualizado: 26/04/2026

st.set_page_config: configuración global de la página

st.set_page_config debe ser la primera llamada de Streamlit en el script. Configura el título de la pestaña del navegador, el ícono, el layout y el estado inicial del sidebar:

import streamlit as st

st.set_page_config(
    page_title="Mi Dashboard",
    page_icon="📊",           # Emoji o URL de imagen
    layout="wide",            # "centered" (por defecto) o "wide"
    initial_sidebar_state="expanded",  # "auto", "expanded", "collapsed"
    menu_items={
        "Get Help": "https://docs.streamlit.io",
        "Report a bug": "https://github.com/streamlit/streamlit/issues",
        "About": "## Mi Dashboard\nVersión 1.0.0"
    }
)

Si se llama st.set_page_config después de otras llamadas a Streamlit, se produce un error. Colocarlo siempre al principio del script.

Arquitectura de una app Streamlit

Cada app combina cuatro piezas que conviene tener claras desde el principio: el script Python, los widgets (que leen y escriben valores en el front-end), st.session_state para persistir datos entre reruns y la cache para evitar recomputaciones. El servidor Streamlit orquesta estas piezas en cada interacción:

flowchart TB
    Browser[Navegador del usuario] -->|WebSocket| Server[Streamlit Server]
    Server -->|Ejecuta script| Script[app.py]
    Script --> Widgets["Widgets: button, selectbox, slider"]
    Script --> State["(st.session_state)"]
    Script --> Cache["("@st.cache_data / @st.cache_resource")"]
    Widgets -->|Valor nuevo| Server
    State -->|Persiste entre reruns| Script
    Cache -->|Salta computo costoso| Script
    Script -->|Delta UI| Browser

st.write: la función más versátil

st.write es la navaja suiza de Streamlit. Acepta prácticamente cualquier tipo de dato Python y lo renderiza de la forma más adecuada:

import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# Texto plano y Markdown
st.write("Hola, este es texto plano.")
st.write("**Negrita**, *cursiva* y `código inline` con Markdown.")

# Números y listas
st.write(42)
st.write([1, 2, 3, 4, 5])
st.write({"clave": "valor", "número": 100})

# DataFrames de Pandas
df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})
st.write(df)

# Figuras de Matplotlib
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
st.write(fig)

# Magic: st.write se puede omitir en ciertas versiones
# simplemente escribiendo la variable al final de una línea
df  # Esto también muestra el DataFrame (Streamlit Magic)

Primera aplicación completa

Construyamos una aplicación de análisis de datos paso a paso:

import streamlit as st
import pandas as pd
import numpy as np

st.set_page_config(
    page_title="Análisis de ventas",
    page_icon="📈",
    layout="wide"
)

st.title("Dashboard de Análisis de Ventas")
st.markdown("Esta aplicación muestra el análisis de ventas con datos de ejemplo.")

# Generar datos de ejemplo
@st.cache_data
def generar_datos():
    np.random.seed(42)
    meses = ["Ene", "Feb", "Mar", "Abr", "May", "Jun",
             "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"]
    return pd.DataFrame({
        "mes": meses,
        "ventas": np.random.randint(8000, 20000, 12),
        "costes": np.random.randint(5000, 12000, 12),
        "clientes": np.random.randint(50, 200, 12)
    })

df = generar_datos()

# Métricas destacadas
col1, col2, col3 = st.columns(3)
col1.metric("Ventas totales", f"€ {df['ventas'].sum():,.0f}")
col2.metric("Coste total", f"€ {df['costes'].sum():,.0f}")
col3.metric("Media clientes/mes", f"{df['clientes'].mean():.0f}")

st.divider()

# Gráfico interactivo
st.subheader("Evolución mensual de ventas y costes")
st.line_chart(df.set_index("mes")[["ventas", "costes"]])

# Tabla de datos
st.subheader("Datos detallados")
st.dataframe(df, use_container_width=True, hide_index=True)

El flujo top-down en acción

El modelo de re-ejecución de Streamlit se hace evidente con widgets:

import streamlit as st
import pandas as pd
import numpy as np

st.title("Generador de datos configurables")

# Cada vez que el usuario cambia estos widgets, todo el script se re-ejecuta
n_filas = st.slider("Número de filas", 10, 1000, 100)
semilla = st.number_input("Semilla aleatoria", value=42, step=1)
incluir_negativo = st.checkbox("Incluir valores negativos", value=False)

# Este código se ejecuta con los valores actuales de los widgets
np.random.seed(int(semilla))
if incluir_negativo:
    datos = np.random.randn(n_filas)  # Normal estándar (-∞ a +∞)
else:
    datos = np.abs(np.random.randn(n_filas))  # Solo positivos

df = pd.DataFrame({"valor": datos})

col1, col2 = st.columns(2)
with col1:
    st.write(f"Filas generadas: **{len(df)}**")
    st.write(f"Mínimo: **{df['valor'].min():.4f}**")
    st.write(f"Máximo: **{df['valor'].max():.4f}**")
    st.write(f"Media: **{df['valor'].mean():.4f}**")
with col2:
    st.line_chart(df)

Cuando el usuario mueve el slider de n_filas, Streamlit:

  1. Re-ejecuta el script completo de arriba a abajo.
  2. n_filas toma el nuevo valor del slider.
  3. datos y df se recalculan con el nuevo n_filas.
  4. Las métricas y el gráfico se actualizan en pantalla.

Este comportamiento es completamente automático: no hay que gestionar eventos ni callbacks.

Diferencia entre st.write y funciones específicas

st.write es conveniente para prototipos, pero para código de producción conviene usar las funciones específicas porque son más explícitas y tienen más parámetros:

# st.write genérico
st.write("## Mi título")
st.write(df)

# Funciones específicas con más control
st.header("Mi título")                     # Solo texto, no DataFrames
st.dataframe(df, use_container_width=True) # Tabla con opciones avanzadas
st.line_chart(df)                          # Solo gráficos

La regla práctica: usa st.write para exploración rápida y funciones específicas para código que va a producción.

Añadir interactividad básica

Una aplicación completamente estática no aprovecha Streamlit. Añadir un widget transforma el dashboard en una herramienta interactiva:

import streamlit as st
import pandas as pd
import numpy as np

st.title("Filtro interactivo de datos")

# Widget de filtro
umbral = st.slider("Mostrar valores mayores que", 0, 100, 50)

# Los datos se filtran en tiempo real
datos = pd.DataFrame({"valor": np.random.randint(0, 100, 200)})
filtrado = datos[datos["valor"] > umbral]

st.write(f"Mostrando {len(filtrado)} de {len(datos)} registros (umbral: {umbral})")
st.bar_chart(filtrado["valor"].value_counts().sort_index())

Con estas bases, ya puedes construir aplicaciones Streamlit funcionales. Los siguientes módulos profundizan en cada tipo de elemento: texto enriquecido, widgets avanzados, gráficos, layouts y gestión del estado.

Alan Sastre - Autor del tutorial

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

Crear una aplicación Streamlit funcional desde cero con st.write. Configurar la página con st.set_page_config (título, icono, layout). Comprender el modelo de re-ejecución top-down con ejemplos prácticos. Usar st.write para mostrar distintos tipos de datos (texto, DataFrames, gráficos). Combinar widgets con lógica Python para crear interactividad real.