Qué es FacetGrid
FacetGrid es la clase de bajo nivel que gestiona las cuadrículas de subgráficos en Seaborn. Las funciones figure-level (relplot, displot, catplot) la utilizan internamente para organizar los subgráficos condicionados a variables categóricas. Sin embargo, crear un FacetGrid directamente permite un nivel de personalización mucho mayor, ya que se puede mapear cualquier función de visualización, incluidas las de Matplotlib, SciPy o bibliotecas de terceros.
Mientras que
relplotocatplotestán limitados a las funciones de Seaborn,FacetGridpermite crear cuadrículas con cualquier función que acepte arrays o DataFrames como entrada.
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
sns.set_theme(style="ticks")
tips = sns.load_dataset("tips")
penguins = sns.load_dataset("penguins")
Creación básica de FacetGrid
# FacetGrid con variable de columna
g = sns.FacetGrid(tips, col="time", height=5, aspect=1.0)
plt.show()
El FacetGrid se crea vacío — define la cuadrícula pero aún no mapea ningún gráfico. Se usa map() o map_dataframe() para poblar los subgráficos.
map(): mapear funciones con arrays
map() recibe una función y los nombres de las columnas que se pasan como arrays posicionales:
g = sns.FacetGrid(tips, col="time", hue="smoker", palette="Set1", height=5)
g.map(sns.scatterplot, "total_bill", "tip", alpha=0.6)
g.add_legend()
g.set_axis_labels("Importe ($)", "Propina ($)")
g.set_titles("{col_name}")
plt.show()
map_dataframe(): mapear funciones con data=
map_dataframe() pasa el subconjunto del DataFrame completo a la función mediante el parámetro data=. Es necesario para funciones que aceptan data=:
g = sns.FacetGrid(penguins.dropna(), col="island", height=4, aspect=1.0)
g.map_dataframe(
sns.scatterplot,
x="bill_length_mm",
y="bill_depth_mm",
hue="species",
palette="Set2",
alpha=0.7
)
g.add_legend(title="Especie")
g.set_titles("Isla: {col_name}")
g.set_axis_labels("Longitud del pico (mm)", "Profundidad del pico (mm)")
plt.show()
Cuadrículas de filas y columnas
g = sns.FacetGrid(
tips,
col="time",
row="smoker",
hue="sex",
palette=["#3498db", "#e74c3c"],
height=4,
aspect=1.2,
margin_titles=True # títulos en los márgenes derecho/superior
)
g.map_dataframe(sns.scatterplot, x="total_bill", y="tip", alpha=0.6)
g.set_titles(col_template="{col_name}", row_template="{row_name}")
g.set_axis_labels("Importe ($)", "Propina ($)")
g.add_legend(title="Género")
g.fig.suptitle("Propina según turno y condición de fumador", y=1.02)
plt.tight_layout()
plt.show()
col_wrap para muchas categorías
diamonds = sns.load_dataset("diamonds").sample(3000, random_state=42)
g = sns.FacetGrid(
diamonds,
col="cut",
col_wrap=3, # máximo 3 columnas
height=3.5,
aspect=1.0
)
g.map_dataframe(
sns.histplot,
x="price",
bins=20,
color="steelblue",
alpha=0.7
)
g.set_titles("{col_name}")
g.set_axis_labels("Precio ($)", "Conteo")
g.fig.suptitle("Distribución de precios por tipo de corte", y=1.02)
plt.tight_layout()
plt.show()
Mapear funciones de Matplotlib
La gran ventaja de FacetGrid es que puede mapear cualquier función de Matplotlib:
def plot_scatter_with_regression(x, y, **kwargs):
"""Función personalizada: scatter + línea de regresión con Matplotlib."""
from scipy import stats
ax = plt.gca()
ax.scatter(x, y, **kwargs)
slope, intercept, r, p, se = stats.linregress(x, y)
x_line = np.linspace(x.min(), x.max(), 100)
ax.plot(x_line, slope * x_line + intercept, color="red", linewidth=2)
ax.set_title(f"r={r:.2f}, p={p:.3f}", fontsize=9)
g = sns.FacetGrid(penguins.dropna(), col="species", height=4, aspect=1.0)
g.map(plot_scatter_with_regression, "bill_length_mm", "body_mass_g",
alpha=0.5, s=30, color="steelblue")
g.set_axis_labels("Longitud del pico (mm)", "Masa corporal (g)")
g.set_titles("{col_name}")
g.fig.suptitle("Regresión personalizada por especie", y=1.05)
plt.tight_layout()
plt.show()
Personalización post-creación
g = sns.FacetGrid(tips, col="time", height=5, aspect=1.2)
g.map_dataframe(sns.boxplot, x="day", y="total_bill",
palette="Set2", order=["Thur", "Fri", "Sat", "Sun"])
# Personalizar cada subgráfico individualmente
for ax, titulo in zip(g.axes.flatten(), ["Almuerzo", "Cena"]):
ax.set_title(titulo, fontsize=14, fontweight="bold")
ax.set_xlabel("Día de la semana", fontsize=11)
ax.set_ylabel("Importe total ($)", fontsize=11)
ax.set_xticklabels(["Jue", "Vie", "Sáb", "Dom"])
ax.axhline(
y=tips["total_bill"].mean(),
color="red",
linestyle="--",
alpha=0.5,
label="Media global"
)
g.axes[0, 0].legend(loc="upper left")
g.fig.suptitle("Distribución del importe por turno", fontsize=15, y=1.02)
plt.tight_layout()
plt.show()
refline: añadir líneas de referencia
g = sns.FacetGrid(penguins.dropna(), col="species", height=4)
g.map_dataframe(sns.scatterplot, x="flipper_length_mm", y="body_mass_g",
alpha=0.6, color="steelblue")
# Añadir líneas de referencia a todos los subgráficos
g.refline(x=penguins["flipper_length_mm"].mean(),
y=penguins["body_mass_g"].mean(),
color="red", linestyle="--", linewidth=1.5)
g.set_titles("{col_name}")
g.set_axis_labels("Longitud de aleta (mm)", "Masa corporal (g)")
g.fig.suptitle("Masa vs aleta con medias globales de referencia", y=1.05)
plt.tight_layout()
plt.show()
Cuándo usar FacetGrid en lugar de relplot, displot o catplot
Las funciones figure-level de Seaborn son, en realidad, envoltorios de FacetGrid con una función de dibujo fija. Si solo necesitas dibujar un scatterplot, un histplot o un boxplot facetado, casi siempre es más rápido y legible usar relplot, displot o catplot. Sin embargo, hay tres situaciones en las que FacetGrid sigue siendo irreemplazable.
La primera es cuando quieres componer varias capas dentro de cada celda. Por ejemplo, superponer un kdeplot sobre un scatterplot, o añadir una línea de media por encima de un histograma. Con FacetGrid puedes llamar a map o map_dataframe tantas veces como capas necesites, y cada una se dibujará sobre la misma cuadrícula.
La segunda es cuando la función de dibujo no es nativa de Seaborn: rutinas de Matplotlib, funciones propias, ajustes de SciPy o gráficos especializados (streamplots, contornos, imágenes). Como ya hemos visto, basta con aceptar **kwargs y usar plt.gca() dentro de la función.
La tercera es cuando necesitas control fino sobre la estructura de los ejes antes de dibujar: compartir un rango concreto, imponer ticks manuales, ajustar aspect ratio o preparar twin axes. FacetGrid te entrega la figura ya construida mediante g.axes, mientras que las funciones figure-level crean la cuadrícula dentro de la llamada y te limitan la intervención previa.
Buenas prácticas y errores comunes
- Ordena las categorías explícitamente. Seaborn usa el orden alfabético o el de aparición en el DataFrame, que rara vez es el deseado. Usa
col_order=,row_order=yhue_order=para fijar la secuencia, o convierte la columna apd.Categorical(..., ordered=True)antes de crear el grid. - Comparte ejes cuando la comparación importa. Por defecto
FacetGridusasharex=True, sharey=True, lo que facilita comparar magnitudes entre celdas. Si cada faceta tiene escalas muy distintas, ponsharex=Falsepara evitar que las más pequeñas queden aplastadas. - Filtra los valores nulos antes de crear el grid.
FacetGridno los elimina por ti y pueden aparecer facetas vacías o ejes descolocados. Llama a.dropna(subset=[...])sobre el DataFrame. - Cuidado con
col_wrapyrowa la vez. Son incompatibles: si usascol_wrap, no puedes usarrow. Elige una estructura 2D (col+row) o envuelta (col+col_wrap). - Evita un número excesivo de facetas. Por encima de 12-16 celdas el gráfico se vuelve ilegible. Si tienes decenas de categorías, considera agrupar las minoritarias en "otros" o usar una interfaz interactiva como Plotly o Streamlit.
tight_layoutrompe a veces elsuptitle. Si el título superior queda cortado, ajustay=1.03o reemplazaplt.tight_layout()porg.fig.subplots_adjust(top=0.9)para dejar margen manualmente.
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, Seaborn 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 Seaborn
Explora más contenido relacionado con Seaborn y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Crear cuadrículas de gráficos con sns.FacetGrid(). Mapear funciones de Seaborn y Matplotlib con map() y map_dataframe(). Controlar el número de columnas con col_wrap y el tamaño con height y aspect. Personalizar títulos, etiquetas y leyendas del FacetGrid. Combinar FacetGrid con funciones no nativas de Seaborn.