La gramática de los gráficos

r
visualizacion
ggplot2
Por qué ggplot2 piensa en términos gramaticales (datos + aesthetics + geoms + scales + facets + coords + themes), cómo se traduce eso a código y por qué cambia tu forma de visualizar.

¿Por qué una “gramática” de los gráficos?

La mayoría de librerías de visualización exponen funciones tipo histogram(), barplot(), scatterplot(). Cada una con sus propios argumentos. ¿Quieres añadir una línea de tendencia a tu scatter? Aprende otra función. ¿Quieres facetar por categoría? Otra. La curva de aprendizaje es horizontal: cada gráfico nuevo es un esfuerzo nuevo.

En 1999, Leland Wilkinson publicó The Grammar of Graphics, una propuesta radical: en lugar de un catálogo de gráficos, un sistema gramatical de componentes que se combinan. Igual que combinas palabras en frases, combinas componentes en gráficos.

Hadley Wickham implementó esa idea en R como ggplot2. Eso es lo que hace que ggplot2 sea un lenguaje, no una librería de utilidades.

La consecuencia práctica: una vez aprendes los 7 componentes, cualquier gráfico que veas en una revista lo puedes reconstruir mentalmente. Y la mayoría los puedes escribir directamente.

Los 7 componentes de Wilkinson

Cualquier gráfico se descompone en estas capas:

Capa Qué define
Data El dataset de entrada (data.frame o tibble)
Aesthetics Cómo se mapean variables del dataset a propiedades visuales (x, y, color, size, shape…)
Geometries Los objetos geométricos que aparecen (puntos, líneas, barras, polígonos)
Scales Cómo se traducen los valores del dato a unidades visuales (rangos, transformaciones logarítmicas, paletas)
Facets División del gráfico en sub-paneles (small multiples)
Coordinates Sistema de coordenadas (cartesiano, polar, mapa)
Themes Aspecto no relacionado con los datos (tipografía, fondo, leyendas)

No todos los gráficos usan los siete. Casi todos usan los primeros tres (data + aesthetics + geometries). Los demás se añaden según necesidad.

Cómo se traducen a ggplot2

En código, esos siete componentes se mapean directamente:

library(ggplot2)
library(palmerpenguins)   # install.packages("palmerpenguins") si no lo tienes

ggplot(data = penguins,                              # 1. Data
       mapping = aes(x = bill_length_mm,             # 2. Aesthetics
                     y = flipper_length_mm,
                     color = species)) +
  geom_point(size = 2) +                             # 3. Geometry
  scale_x_continuous(name = "Largo del pico (mm)") + # 4. Scale
  facet_wrap(~ island) +                             # 5. Facet
  coord_cartesian(xlim = c(30, 60)) +                # 6. Coord
  theme_minimal()                                    # 7. Theme

Léelo: “sobre el dataset penguins, mapea el largo del pico al eje X y el de la aleta al eje Y coloreando por especie. Dibuja puntos. Pon una escala continua con un nombre legible en el eje X. Faceta por isla. Recorta el rango del eje X. Aplica el tema minimal”.

Cada línea es una capa que se suma a las anteriores. Por eso el operador entre componentes es +.

El + como suma de capas

Esta es la observación que separa entender ggplot2 de copiar código de StackOverflow.

ggplot(penguins, aes(bill_length_mm, flipper_length_mm)) +
  geom_point()

Aquí hay dos capas: una base (ggplot()) y un geom. Si quiero añadir una línea de tendencia, no cambio la función, añado otra capa:

ggplot(penguins, aes(bill_length_mm, flipper_length_mm)) +
  geom_point() +
  geom_smooth(method = "lm")

¿Y si quiero el smooth solo para una especie?

ggplot(penguins, aes(bill_length_mm, flipper_length_mm)) +
  geom_point() +
  geom_smooth(data = dplyr::filter(penguins, species == "Adelie"),
              method = "lm")

Cada geom_*() puede tener su propio dataset y sus propios aesthetics, sobrescribiendo lo heredado del ggplot() base. Esa es la composicionalidad que la gramática habilita y que otras librerías no tienen.

Tu primer ggplot

Para que el resto de la ruta tenga base concreta, escribe esto:

library(ggplot2)
library(palmerpenguins)

ggplot(penguins, aes(x = bill_length_mm, y = flipper_length_mm)) +
  geom_point(aes(color = species))

Lo que has hecho:

  1. Has cargado ggplot2 y un dataset de ejemplo.
  2. Has llamado ggplot() con tres cosas: el data frame, el aesthetic x y el aesthetic y.
  3. Has añadido una capa geom_point() que dibuja un punto por fila del data frame, coloreado según la especie.

El resultado es un scatter plot con tres clusters claros, uno por especie. Ya tienes un EDA real con tres líneas de código.

Trampas habituales

  • Olvidar el +. Si terminas una línea sin +, la siguiente queda fuera del gráfico. R no avisa: simplemente la siguiente línea se ejecuta como código suelto. Diagnóstico: tu gráfico no muestra la capa que acabas de añadir.
  • + al principio de la siguiente línea (en lugar de al final). ggplot2 acepta este estilo, pero es una fuente de errores cuando refactorizas: si borras una línea y olvidas el + huérfano, todo lo siguiente queda fuera. Convención sana: + siempre al final de la línea, nunca al principio.
  • Pensar en términos de funciones. Si te encuentras buscando “qué función dibuja un histograma con boxplot superpuesto”, estás pensando mal. Lo correcto es “añado un geom_histogram y luego un geom_boxplot como capas”. La gramática piensa en capas, no en figuras prefabricadas.

En la siguiente entrega

Tienes el modelo mental. La pieza más importante a fondo es el segundo componente, aesthetics (aes()). Es lo que mapea tus variables a propiedades visuales, y es el origen del 80 % de los errores que la gente comete en ggplot2. Lo vemos a continuación.