Sobre el concepto de capas en ggplot2

Herramientas: ggplot2

Si has buscado información sobre ggplot2 o la Layered Grammar of Graphics probablemente hayas visto esta representación visual de las capas:

Búsqueda de imágenes para Layered Grammar of Graphics

Aquí podemos ver una versión de Thomas Lin Pedersen, uno de los desarrolladores de ggplot2, de su reciente taller sobre ggplot2.

Pedersen: The grammar of graphics > The idea > Decompose graphics into its constituents

Personalmente esa representación no me parece correcta, ya que creo que mezcla conceptos distintos:

  • Por una parte tendríamos los elementos componentes de la grámatica.
  • Por otra parte, tendríamos lo que podemos llamar “capas gráficas”.

Como indica Wickham en la sección “What is the grammar of graphics?” de su libro ggplot2: Elegant Graphics for Data Analysis, las capas son uno de los componentes de la gramática (en ggplot2 con las funciones geom_ o stat_):

Layers made up of geometric elements and statistical transformation. Geometric objects, geoms for short, represent what you actually see on the plot: points, lines, polygons, etc.

Y en la página de referencia de ggplot2 encontramos las siguientes secciones:

  • Plot basics
  • Layer: geoms
  • Layer: stats
  • Layer: position adjustment
  • Layer: annotations
  • Aesthetics
  • Scales
  • Guides: axes and legends
  • Facetting
  • Facetting: labels
  • Coordinate systems
  • Themes
  • Programming with ggplot2
  • Extending ggplot2
  • Vector helpers
  • Data
  • Autoplot and fortify

Es decir, se especifica claramente cuáles de los componentes generan capas gráficas.

El propio Pedersen utiliza esta otra imagen para explicar que los componentes interactúan entre sí de varias formas.

Componentes de la LGG

Pero a la hora de explicar los distintos componentes, vuelve a utilizar la primera imagen.

La cuestión es que, como veremos a continuación, los distintos componentes actúan de formas distintas.

El orden de las capas afecta al gráfico final

Como observamos en estos dos gráficos, el orden de las capas (geom_ y/o stat_) afecta al apilamiento de las marcas gráficas; si queremos ver todos los puntos, tienen que estar en una capa superior (de otra forma, se dibujan, pero quedan tapados por las barras).

ggplot(mpg, aes(drv, cty, fill = drv)) +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white")

ggplot(mpg, aes(drv, cty, fill = drv)) +
  geom_jitter(shape = 21, color = "white") +
  stat_summary(fun = "mean", geom = "col")

El orden de los componentes no afecto al gráfico final

ggplot(mpg, aes(drv, cty, fill = drv)) +
  scale_x_discrete(name = "Nombre del eje x") +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white")

ggplot(mpg, aes(drv, cty, fill = drv)) +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white") +
  scale_x_discrete(name = "Nombre del eje x")

No podemos usar dos veces el mismo componente

Si tratamos de usar el mismo componente como dos “capas”, ggplot2 nos indicará que solo se aplica el último de ellos.

ggplot(mpg, aes(drv, cty, fill = drv)) +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white") +
  scale_fill_brewer(palette = "Set2") +
  scale_fill_brewer(palette = "Dark2")
## Scale for 'fill' is already present. Adding another scale for 'fill', which
## will replace the existing scale.

Este comportamiento es el mismo independientemente que indiquemos el mismo argumento en las dos llamadas, o distintos argumentos:

ggplot(mpg, aes(drv, cty, fill = drv)) +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white") +
  scale_x_discrete(name ="Nombre para el eje x") +
  scale_x_discrete(labels = c("A","B","C"))
## Scale for 'x' is already present. Adding another scale for 'x', which will
## replace the existing scale.

Esto no pasa con las capas reales, aunque al tratarse de elementos idénticos la primera capa queda oculta por la segunda:

ggplot(mpg, aes(drv, cty, fill = drv)) +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white") +
  geom_jitter(shape = 21, color = "white")

Capas de anotación

Por otra parte, en los distintos esquemas que he encontrado no encuentro ninguno que mencione las funciones de anotación de ggplot2, esto puede deberse a que estas funciones no heredan datos (y por tanto, mapeos de variables a canales gráficos).

Por lo demás, su apilamiento funciona igual que el resto de las capas gráficas.

ggplot(mpg, aes(drv, cty, fill = drv)) +
  geom_hline(yintercept = 18, color ="black", size = 5) +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white") +
  geom_jitter(shape = 21, color = "white")

ggplot(mpg, aes(drv, cty, fill = drv)) +
  stat_summary(fun = "mean", geom = "col") +
  geom_jitter(shape = 21, color = "white") +
  geom_jitter(shape = 21, color = "white") +
  geom_hline(yintercept = 18, color ="black", size = 5)

Propuesta

Por tanto, considero que esta versión de la imagen identifica mejor la relación entre las capas gráficas y el resto de componentes.


Más posts