st.pyplot con Matplotlib y Seaborn en Streamlit

Intermedio
Streamlit
Streamlit
Actualizado: 26/04/2026

st.pyplot: mostrar figuras de Matplotlib

Matplotlib es la biblioteca de visualización más madura y extendida del ecosistema Python, con más de 20 años de desarrollo. Su integración con Streamlit es directa mediante st.pyplot: se crea la figura con la API habitual de Matplotlib y se pasa como argumento para que Streamlit la renderice como imagen PNG en la aplicación.

A diferencia de los gráficos nativos de Streamlit (que son interactivos), las figuras de Matplotlib se renderizan como imágenes estáticas. Esto los hace ideales para publicaciones, informes y visualizaciones donde se necesita un control pixel-perfect sobre cada elemento del gráfico:

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

# IMPORTANTE: Siempre crear la figura explícitamente
fig, ax = plt.subplots(figsize=(10, 4))

x = np.linspace(0, 4 * np.pi, 200)
ax.plot(x, np.sin(x), label="sin(x)", color="#FF4B4B", linewidth=2)
ax.plot(x, np.cos(x), label="cos(x)", color="#1F77B4", linewidth=2, linestyle="--")
ax.set_title("Funciones trigonométricas")
ax.set_xlabel("x (radianes)")
ax.set_ylabel("y")
ax.legend()
ax.grid(True, alpha=0.3)

st.pyplot(fig)
plt.close(fig)  # Liberar memoria

Nota importante: Siempre pasa la figura como argumento a st.pyplot(fig). Evita usar st.pyplot() sin argumento (es deprecated desde Streamlit 1.0).

flowchart LR
    A[Crear figure y axes con plt.subplots] --> B[Dibujar con ax.plot ax.bar etc]
    B --> C[Personalizar título ejes leyenda]
    C --> D[st.pyplot fig]
    D --> E[Streamlit renderiza como PNG]
    E --> F[plt.close fig libera memoria]
    G[Seaborn] --> H[sns.heatmap sns.violinplot]
    H --> I[Devuelve ax]
    I --> D
    F --> J[Sin fugas en aplicaciones largas]
    A -.->|fig comparte| K[Layout multi-axes]
    K --> D

Gráfico de barras con anotaciones

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

categorias = ["Python", "R", "Julia", "Scala", "Java"]
valores = [78, 14, 4, 2, 2]
colores = ["#FF4B4B" if v == max(valores) else "#CCCCCC" for v in valores]

fig, ax = plt.subplots(figsize=(8, 5))
barras = ax.bar(categorias, valores, color=colores)

for barra, valor in zip(barras, valores):
    ax.text(
        barra.get_x() + barra.get_width() / 2,
        barra.get_height() + 0.5,
        f"{valor}%",
        ha="center", va="bottom", fontweight="bold"
    )

ax.set_ylim(0, 90)
ax.set_title("Lenguajes de programación más usados en Ciencia de Datos (2026)")
ax.set_ylabel("Porcentaje de uso (%)")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)

st.pyplot(fig)
plt.close(fig)

La llamada a plt.close(fig) al final de cada bloque es fundamental para liberar memoria. Sin ella, Matplotlib mantiene la figura en memoria durante toda la sesión, lo que puede provocar fugas de memoria en aplicaciones que generan muchos gráficos.

Seaborn: visualizaciones estadísticas

Seaborn se construye sobre Matplotlib y proporciona una API de alto nivel orientada a la visualización estadística. Su integración con DataFrames de Pandas es nativa, lo que simplifica la creación de heatmaps, distribuciones, boxplots y análisis bivariantes con muy pocas líneas de código:

import streamlit as st
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

# Cargar dataset de ejemplo
@st.cache_data
def cargar_datos():
    return sns.load_dataset("tips")

df = cargar_datos()

# Selector de tipo de gráfico
tipo = st.selectbox("Tipo de visualización", ["Heatmap de correlación", "Distribución", "Boxplot", "Violin"])

fig, ax = plt.subplots(figsize=(10, 6))

if tipo == "Heatmap de correlación":
    correlacion = df.select_dtypes("number").corr()
    sns.heatmap(correlacion, annot=True, fmt=".2f", cmap="coolwarm",
                center=0, square=True, ax=ax)
    ax.set_title("Matriz de correlación")

elif tipo == "Distribución":
    columna = st.selectbox("Variable", df.select_dtypes("number").columns)
    sns.histplot(df[columna], kde=True, ax=ax, color="#FF4B4B")
    ax.set_title(f"Distribución de '{columna}'")

elif tipo == "Boxplot":
    sns.boxplot(data=df, x="day", y="total_bill", hue="sex",
                palette="Set2", ax=ax)
    ax.set_title("Distribución de propinas por día y género")

elif tipo == "Violin":
    sns.violinplot(data=df, x="day", y="total_bill", hue="time",
                   split=True, palette="muted", ax=ax)
    ax.set_title("Distribución de propinas (violín)")

st.pyplot(fig)
plt.close(fig)

Pairplot interactivo con selección de variables

import streamlit as st
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

@st.cache_data
def cargar_iris():
    return sns.load_dataset("iris")

df = cargar_iris()

st.title("Explorador de correlaciones — Dataset Iris")

cols_num = df.select_dtypes("number").columns.tolist()
variables = st.multiselect("Variables a comparar", cols_num, default=cols_num[:3])

if len(variables) >= 2:
    with st.spinner("Generando pairplot..."):
        fig = sns.pairplot(df, vars=variables, hue="species", palette="husl")
        fig.fig.suptitle("Pairplot del dataset Iris", y=1.02)
        st.pyplot(fig.fig)
        plt.close("all")
else:
    st.warning("Selecciona al menos 2 variables para generar el pairplot.")

Subplots múltiples en un panel

import streamlit as st
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

@st.cache_data
def datos():
    return sns.load_dataset("tips")

df = datos()

fig, axes = plt.subplots(2, 2, figsize=(12, 10))
fig.suptitle("Panel de análisis completo — Tips dataset", fontsize=16, y=1.01)

# Distribución de propinas
sns.histplot(df["total_bill"], kde=True, ax=axes[0, 0], color="#FF4B4B")
axes[0, 0].set_title("Distribución del gasto total")

# Boxplot por día
sns.boxplot(data=df, x="day", y="total_bill", ax=axes[0, 1])
axes[0, 1].set_title("Gasto por día de la semana")

# Scatterplot con regresión
sns.regplot(data=df, x="total_bill", y="tip", ax=axes[1, 0], color="#1F77B4")
axes[1, 0].set_title("Propina vs Gasto total")

# Countplot
sns.countplot(data=df, x="day", hue="sex", ax=axes[1, 1], palette="Set2")
axes[1, 1].set_title("Visitas por día y género")

plt.tight_layout()
st.pyplot(fig)
plt.close(fig)

Matplotlib y Seaborn son las opciones preferidas cuando se necesita control total sobre el estilo de los gráficos, especialmente para publicaciones, informes o visualizaciones estadísticas complejas que requieren anotaciones precisas o layouts personalizados.

Para adaptar los gráficos de Matplotlib al tema oscuro de Streamlit, se puede usar plt.style.use("dark_background") al inicio del bloque de creación de la figura. Otra opción es detectar el tema activo con st.context.theme y ajustar los colores dinámicamente.

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

Mostrar figuras de Matplotlib en Streamlit con st.pyplot(fig). Crear visualizaciones estadísticas avanzadas con Seaborn (heatmap, violinplot, pairplot). Personalizar el estilo de las figuras para que encajen con el tema de Streamlit. Crear gráficos interactivos combinando st.pyplot con widgets de Streamlit. Gestionar la memoria correctamente cerrando figuras con plt.close().