Facetas en ggplot2 con facet_wrap y facet_grid

Con ggplot2 puedes crear gráficos de paneles, también llamados gráficos de Trellis o facetas con las funciones facet_grid o facet_wrap. Estas funciones son muy similares, pero existen algunas diferencias entre ellas, ya que la primera crea una matriz de paneles en base a dos variables discretas (también funciona para una, pero no se recomienda) mientras que la segunda crea un conjunto de paneles en base a una única variable categórica (también funciona con dos, pero no se recomienda).

Una variable discreta: facet_wrap

Considera, por ejemplo, que tienes un conjunto de observaciones que pertenecen a grupos diferentes. En este escenario, puedes mostrar todos los datos en el mismo gráfico y resaltar los grupos con un color o marcador diferente.

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Gráfico de dispersión por grupo
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point()

Gráfico de dispersión con varios grupos en ggplot2

El problema es que en ocasiones el gráfico no es legible, por lo que una alternativa sería dividir los datos en diferentes gráficos para ver cada grupo de manera individual. Para ello puedes hacer uso de la función facet_wrap pasando el nombre de la variable que define los grupos como una fórmula, esto es: ~grupo.

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo)

Facetas en ggplot2 con facet_wrap

Cambia el orden de los paneles ordenando los niveles de la variable categórica con factor.

Número de filas y columnas

El número por defecto de filas y columnas dependerá de tus datos. Si tu variable categórica tiene cuatro grupos como es el caso, la función facet_wrap creará dos columnas y dos filas, pero en este ejemplo quizás sea mas interesante tener una fila, ya que hace el gráfico más legible. Para ello puedes establecer nrow = 1 o ncol = 4.

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos (2 columnas)
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo, nrow = 1) # O ncol = 4

Múltiples paneles en ggplot2 con la función facet_wrap

Si en lugar de facet_wrap usásemos facet_grid se crearían los mismos paneles, pero siempre habría una sola fila o una sola columna, por eso no se recomienda su uso y es mejor usar facet_wrap y poder tener la libertad de poder elegir el número de filas o columnas.

Escalas de los ejes

Por defecto, todos los paneles tendrán la misma escala de los ejes, pero si los datos presentan distinta escala para cada grupo puedes hacer que cada panel tenga su propia escala estableciendo scales = "free", de modo que cada gráfico tendrá rangos diferentes. Liberar las escalas hace más sencillo leer patrones en cada panel, mientras que dejarlas fijas hace más sencillo ver patrones entre los paneles. Ten en cuenta que también puedes dejar libre un único eje con scales = "free_x" o scales = "free_y".

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo, scales = "free")

Paneles de ggplot2 con escala libre

Dirección de los paneles

La dirección por defecto de los paneles es horizontal (dir = "h") pero también puedes establecerla como vertical con dir = "v". Observa que al cambiarlo, el panel superior de la derecha ahora corresponde al tercer grupo en lugar de al segundo.

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Vertical ribbon of plots
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo, dir = "v")

Paneles de facet_wrap en posición vertical

Posición de las etiquetas

La función facet_wrap proporciona un argumento llamado strip.position que permite personalizar la posición de las etiquetas o cintas. El valor por defecto es "top" (arriba), pero también podría ser "bottom" (abajo), "left" (izquierda) o "right" (derecha).

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo, strip.position = "bottom")

Posición de las etiquetas de un gráfico de paneles en ggplot2

Resaltar cada grupo mostrando todos los datos en los paneles

Es posible agregar todos los datos a todos los paneles y resaltar los datos correspondientes para cada uno de ellos. Para ello tendrás que crear una nueva capa pasando como entrada el mismo data frame pero eliminando la variable categórica (en este ejemplo se llama grupo).

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(data = transform(df, grupo = NULL), colour = "grey85") +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo, strip.position = "bottom")

Resaltar cada grupo mostrando todos los datos en paneles de ggplot2

Dos variables discretas: facet_grid

La función facet_grid es muy similar a facet_wrap, pero esta función crea paneles mostrando todas las combinaciones de datos para dos variables categóricas. Existen dos formas de introducir datos: la función puede tomar una fórmula como entrada con los nombres de las variables categóricas o puedes pasar los nombres de las variables a los argumentos rows (para las filas) y cols (para las columnas) haciendo uso de la función vars.

Múltiples paneles en R con la función facet_grid de ggplot2

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo1 <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
grupo2 <- ifelse(y < 0.5, "A", "B")
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo1 = grupo1, grupo2 = grupo2)

# Matriz de gráficos
ggplot(df, aes(x = x, y = y, color = grupo1)) +
  geom_point(show.legend = FALSE) +
  facet_grid(grupo1 ~ grupo2) # O facet_grid(rows = vars(grupo1), cols = vars(grupo2)) 

Escala de los ejes

La función facet_grid también proporciona el argumento scales que da libertad a los ejes para variar a través de las filas y/o columnas.

facet_grid en ggplot2 con free scales

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo1 <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
grupo2 <- ifelse(y < 0.5, "A", "B")
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo1 = grupo1, grupo2 = grupo2)

# Matriz de gráficos
ggplot(df, aes(x = x, y = y, color = grupo1)) +
  geom_point(show.legend = FALSE) +
  facet_grid(grupo1 ~ grupo2, scales = "free")

Tamaño de los paneles

Si la escala de los paneles varía, puedes utilizar el argumento space para hacer que los paneles tengan tamaños diferentes. Los posibles valores son "fixed" (por defecto), "free_y" para liberar las alturas, "free_x", para liberar el ancho y "free" para dejar que tanto la altura como el ancho varíen. Ten en cuenta que en este ejemplo este argumento no provoca ningún efecto ya que todos los paneles tienen la misma escala.

Función facet_grid en R

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo1 <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
grupo2 <- ifelse(y < 0.5, "A", "B")
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo1 = grupo1, grupo2 = grupo2)

# Matriz de gráficos
ggplot(df, aes(x = x, y = y, color = grupo1)) +
  geom_point(show.legend = FALSE) +
  facet_grid(grupo1 ~ grupo2, space = "free_x")

La función facet_grid proporciona más argumentos, como shrink, labeller, as.table, switch, drop y margins. Recuerda leer la documentación original para obtener detalles adicionales en caso de ser necesario.

Personalización de las etiquetas y los paneles

Usando los argumentos de la función theme puedes personalizar los textos y los paneles. En los siguientes ejemplos destacamos algunos casos de uso habituales.

Personalización de las etiquetas de facet_wrap

Puedes personalizar el estilo de texto de las etiquetas con el argumento strip_text. Este argumento toma la función element_text como entrada, donde puedes especificar los diferentes estilos, como el color, tamaño, ajuste horizontal, etc. Si quieres eliminar las etiquetas utiliza element_blank.

Para personalizar el color de fondo tan solo tienes que pasar la función element_rect a strip.background y en ella establecer el color de fondo con fill. Si quieres agregar un borde a la cinta tendrás que establecer un tipo de línea, un color y un grosor con los argumentos correspondientes.

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo) +
  theme(strip.text = element_text(face = "bold", color = "white", hjust = 0, size = 15),
        strip.background = element_rect(fill = "dodgerblue3", linetype = "solid",
                                        color = "black", linewidth = 1))

Color de fondo y de texto de los textos de un gráfico de facetas en ggplot2 hecho con facet_wrap

Personalización de las etiquetas de facet_grid

Si creaste un gráfico de paneles con facet_grid puedes personalizar las cintas de la misma manera que en el ejemplo anterior, pero también puedes personalizarlas de manera individual para cada eje haciendo uso de strip.text.x, strip.text.y, strip.background.x y strip.background.y.

library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo1 <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
grupo2 <- ifelse(y < 0.5, "A", "B")
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo1 = grupo1, grupo2 = grupo2)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y,)) +
  geom_point(show.legend = FALSE) +
  facet_grid(grupo1 ~ grupo2) +
  theme(strip.text.x = element_text(face = "bold", color = "white", hjust = 1, size = 15),
        strip.text.y = element_text(face = "bold", color = "white", hjust = 0, size = 15),
        strip.background.x = element_rect(fill = "dodgerblue3", linetype = "solid",
                                          color = "black", linewidth = 1),
        strip.background.y = element_rect(fill = "firebrick2", linetype = "solid",
                                          color = "gray30", linewidth = 1))

Personalización de las etiquetas de un gráfico de paneles con facet_grid

Eliminar el color de fondo de las etiquetas

Ten en cuenta que es posible eliminar el color de fondo de las etiquetas pasando la función element_blank a strip.background.

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo) +
  theme(strip.text = element_text(size = 15),
        strip.background = element_blank())

Eliminar el color de fondo de las etiquetas de un gráfico de facetas de ggplot2

Aumentar o reducir el espacio entre paneles

Por defecto hay un pequeño espacio entre paneles. Puedes incrementar o reducir dicho espacio pasando una unidad (función unit) al argumento panel.spacing de la función theme.

# install.packages("ggplot2")
library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo) +
  theme(panel.spacing = unit(0, 'points'))

Eliminar o incrementar el espacio entre paneles de las facetas de ggplot2

Agregar un borde a los paneles

Recuerda que también puedes personalizar otros parámetros de los gráficos, como por ejemplo agregar un borde a los paneles. Puedes logarlo con panel.border, siguiendo el ejemplo mostrado a continuación.

library(ggplot2)

# Simulación de datos
set.seed(4)
x <- runif(500)
y <- 4 * x ^ 2 + rnorm(length(x), sd = 5)
grupo <- ifelse(x < 0.4, "G1", ifelse(x < 0.6, "G2", ifelse(x < 0.8, "G3", "G4")))
x <- x + runif(length(x), -0.5, 0.5)

# Data frame
df <- data.frame(x = x, y = y, grupo = grupo)

# Paneles de gráficos
ggplot(df, aes(x = x, y = y, color = grupo)) +
  geom_point(show.legend = FALSE) +
  facet_wrap(~grupo) +
  theme(panel.border = element_rect(fill = "transparent", # Necesario para agregar el borde
                                    color = "black", linewidth = 1.5))

Agregar un borde a los paneles de un gráfico de facetas de ggplot2

También te puede interesar