Menu

ggplot2 en R: guía para principiantes de la gramática de gráficos

Cómo funciona ggplot2: el modelo mental de datos + aes() + geom, mapear vs fijar estéticas, labs(), facet_wrap(), temas y guardar gráficos con ggsave().

ggplot2 construye gráficos a partir de capas

ggplot2 es el paquete de graficado más usado de R, y la razón por la que la gente lo defiende con pasión es una idea de diseño: la gramática de gráficos. R base te da una función por gráfico —plot(), hist(), barplot()— cada una con sus propios argumentos. ggplot2, en cambio, te da un pequeño conjunto de piezas componibles —un dataset, un mapeo de columnas a propiedades visuales y capas de dibujo— que se combinan con + en cualquier gráfico. Aprende la gramática una vez y cada nuevo tipo de gráfico es la misma frase con una palabra cambiada. Como extra, los valores por defecto (panel gris, ejes sensatos, leyendas automáticas) resultan presentables sin ningún esfuerzo de estilo.

Es un paquete adicional, así que necesita una instalación única y una carga por sesión:

install.packages("ggplot2")   # once, on your machine
library(ggplot2)              # at the top of every script that uses it

Una expectativa que conviene saber de antemano: ggplot2 quiere un data frame (no vectores sueltos), idealmente en formato largo y ordenado (tidy): una fila por observación, una columna por variable. Si tus datos están en formato ancho, pivotarlos a formato largo primero suele disolver lo que parecía un problema de graficado.

El modelo mental: datos, mapeo, geometría

Cada ggplot responde tres preguntas, una por parte:

  1. Datos: ¿qué data frame? ggplot(mtcars, ...)
  2. Mapeo: ¿qué columnas dirigen qué propiedades visuales? aes(x = wt, y = hp)
  3. Geometría: ¿cómo deben dibujarse las observaciones? + geom_point()

Esta es la anatomía, token a token:

ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point()
  • ggplot(mtcars, ...) inicia un gráfico cuyos datos por defecto son mtcars. Por sí solo dibuja un panel gris vacío: aún no hay capas.
  • aes(x = wt, y = hp) es el mapeo estético: la posición horizontal viene de la columna wt, la vertical de hp. Fíjate en que escribes los nombres de columna a secas, no mtcars$wt: el mapeo se evalúa dentro de los datos que suministraste.
  • + geom_point() añade una capa que dibuja cada fila como un punto. El + es realmente una suma de capas: el gráfico es un objeto que vas construyendo, y puedes seguir añadiendo —otro geom, etiquetas, un tema— cada uno con otro +.

Ejecútalo y obtienes el mismo gráfico de dispersión de peso contra potencia que la versión en R base de la guía del gráfico de dispersión, sobre un panel gris con líneas de cuadrícula blancas. Cambia geom_point() por geom_line() y el mismo mapeo se convierte en un gráfico de líneas: eso es la gramática haciendo su trabajo.

Los geoms que realmente usarás

Una docena de geoms cubre casi todo el trabajo del día a día:

geom_point()       # scatter plot: two numeric variables
geom_line()        # line chart: trends over an ordered variable
geom_col()         # bar chart from pre-computed heights (needs y)
geom_bar()         # bar chart that counts raw rows for you (no y)
geom_histogram()   # distribution of one numeric variable (set binwidth)
geom_boxplot()     # distributions compared across groups
geom_smooth()      # fitted trend line; method = "lm" for straight

Las capas se apilan, y ahí es donde ggplot2 empieza a superar a R base en expresividad: geom_point() + geom_smooth(method = "lm") es un gráfico de dispersión con una línea de regresión y una banda de confianza, en una línea legible. Como los gráficos son objetos, también puedes guardar una base y ramificar desde ella:

p <- ggplot(mtcars, aes(x = wt, y = hp)) + geom_point()

p + geom_smooth(method = "lm")   # one variant
p + geom_smooth()                # another (loess curve)

Mapear vs fijar: la clásica confusión con aes()

El error que comete todo principiante de ggplot2, normalmente en la primera semana: poner un color literal dentro de aes(). La regla es corta —dentro de aes() significa "varía con los datos"; fuera significa "ajuste fijo"— y las dos ubicaciones hacen cosas completamente distintas:

# MAPPING: color varies by a column - each cylinder count gets its own
# color, and a legend appears automatically
ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
    geom_point(size = 2)

# SETTING: every point is literally steelblue - no legend, no mapping
ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point(color = "steelblue", size = 2)

Y la trampa en sí:

# WRONG: "blue" inside aes() is treated as data, not as a color
ggplot(mtcars, aes(x = wt, y = hp, color = "blue")) +
    geom_point()

Esto dibuja puntos rosa salmón con una leyenda cuya única entrada dice "blue". Por qué: aes() mapea columnas a propiedades, así que color = "blue" crea una falsa columna de una sola categoría cuyo valor es la palabra "blue" en todas partes, y ggplot asigna a esa categoría su primer color por defecto, que resulta ser un salmón rojizo. Si querías decir "haz los puntos azules", el color va fuera del mapeo: geom_point(color = "blue"). La misma regla gobierna size, shape, fill y alpha. (Fíjate también en el factor(cyl) del ejemplo de mapeo: cyl es numérica, y envolverla en factor() pide colores distintos por grupo en lugar de un degradado de color continuo.)

Etiquetas, facetas y temas

labs() nombra todo en un solo lugar, y un gráfico no está terminado hasta que tiene etiquetas de verdad:

ggplot(mtcars, aes(x = wt, y = hp, color = factor(cyl))) +
    geom_point(size = 2) +
    labs(title = "Horsepower vs. weight",
         x     = "Weight (1000 lbs)",
         y     = "Horsepower",
         color = "Cylinders")

Las facetas son la característica estrella de ggplot2: dividir un gráfico en pequeños múltiplos, un panel por grupo, con ejes compartidos para que los paneles se comparen honestamente:

ggplot(mtcars, aes(x = wt, y = hp)) +
    geom_point() +
    facet_wrap(~ cyl)

Aparecen tres paneles —uno para los coches de 4, 6 y 8 cilindros— dispuestos en una rejilla con el valor del grupo rotulado sobre cada panel. En R base esto es un malabarismo con par(mfrow) y límites compartidos manuales; aquí es una línea. Las facetas premian los datos ordenados, y por eso ggplot2 encaja tan naturalmente con un pipeline de dplyr: filtra y resume, y luego canaliza el resultado directamente a ggplot().

Los temas reestilizan la tinta que no es de datos en una llamada: + theme_minimal() (fondo blanco limpio), + theme_bw(), + theme_classic() (solo ejes, sin cuadrícula), o el gris por defecto. Elige uno por proyecto y mantén la coherencia: un informe donde todas las figuras comparten un tema se lee como un solo documento y no como un álbum de recortes.

Guardar con ggsave() — y cuándo R base sigue bastando

ggsave() escribe el gráfico más reciente en disco, infiriendo el formato de la extensión del archivo:

ggsave("hp-vs-weight.png", width = 8, height = 5)          # last plot shown
ggsave("hp-vs-weight.pdf", plot = p, width = 8, height = 5) # a saved object

width y height están en pulgadas por defecto; defínelos explícitamente, porque los tamaños de fuente escalan con las dimensiones de salida y los valores por defecto rara vez coinciden con el destino de la figura.

En cuanto a cuándo molestarse: para un vistazo de cinco segundos a una variable durante un análisis, plot() y compañía de R base son menos tecleo y cero dependencias; no hay premio por usar ggplot2 en todas partes. ggplot2 se gana el puesto en el momento en que una figura involucra grupos, leyendas, facetas o una audiencia: la gramática escala a una complejidad que el graficado base solo maneja con esfuerzo.

Lo que te llevas

  • ggplot2 compone cada gráfico a partir de datos + mapeo aes() + capas geom, unidos por +; aprende la gramática una vez y reutilízala para todo tipo de gráfico.
  • aes() mapea columnas a propiedades visuales: nombres de columna a secas, evaluados dentro de tu data frame.
  • Dentro de aes() = varía con los datos (y recibe leyenda); fuera = ajuste fijo. aes(color = "blue") es el bug clásico.
  • labs() para los títulos, facet_wrap(~ group) para los pequeños múltiplos, theme_minimal() y compañía para el estilo, ggsave() con dimensiones explícitas para exportar.
  • Vistazo rápido en solitario: R base. Grupos, facetas o una audiencia: ggplot2.

Esto cierra el capítulo de graficado; desde aquí, el siguiente paso natural es la estadística descriptiva, poniendo números a las formas que estos gráficos revelan.

Preguntas frecuentes

¿Qué es ggplot2 en R?

ggplot2 es el paquete de graficado más popular de R. En lugar de una función por tipo de gráfico, compones cada gráfico a partir de las mismas tres piezas —un data frame, un mapeo aes() de columnas a propiedades visuales, y una o más capas geom_*()— unidas con +. Forma parte del tidyverse.

¿Cómo se instala ggplot2?

Ejecuta install.packages("ggplot2") una vez, y luego library(ggplot2) al inicio de cada script que lo use. Instalar pone el paquete en tu máquina; library() lo carga en la sesión actual.

¿Qué hace aes() en ggplot2?

aes() mapea columnas de tus datos a propiedades visuales: aes(x = wt, y = hp, color = factor(cyl)) dice que la posición horizontal viene de wt, la vertical de hp, y el color de los puntos del número de cilindros. Todo lo que está dentro de aes() varía con los datos; todo lo que está fuera es un ajuste fijo.

¿Por qué mis puntos de ggplot no salen del color que pedí?

Pusiste el color dentro de aes(): aes(color = "blue") no fija un color, mapea una categoría inventada llamada "blue", así que ggplot elige su propio color por defecto y añade una leyenda. Para fijar un color literal, ponlo fuera del mapeo: geom_point(color = "blue").

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR