Gráficos con ggplot2 (B): más elementos

Programación y manejo de datos con R (Slides 06-B)

Pedro J. Pérez

Más elementos de un ggplot()

  • Ya hemos presentado los principales elementos de los gráficos hechos con ggplot2, pero es evidente que un gráfico tiene más elementos.

  • Lógicamente, hay que conocerlos un poco para poder ajustar los gráficos a nuestras necesidades y mejorar su calidad.


Veremos algo de los siguientes elementos:

  • Títulos del gráfico
  • Themes
  • Small multiples (o Facetting)
  • Anotaciones
  • Ejes
  • Escalas
  • Stats (transformaciones estadísticas)
  • Position adjustments
  • Coordenadas

Añadiendo títulos, leyenda, etc …a un ggplot

p <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
        geom_point()
p


Añadiendo títulos, leyenda, etc …a un ggplot

p +
p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo") +
p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo") +
labs(subtitle = "(diferenciando por especie de lirio)") +
p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo") +
labs(subtitle = "(diferenciando por especie de lirio)") +
labs(caption = "Datos provenientes del Iris dataset") +
p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo") +
labs(subtitle = "(diferenciando por especie de lirio)") +
labs(caption = "Datos provenientes del Iris dataset") +
labs(x = "Longitud del sépalo") +
p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo") +
labs(subtitle = "(diferenciando por especie de lirio)") +
labs(caption = "Datos provenientes del Iris dataset") +
labs(x = "Longitud del sépalo") +
labs(y = "Longitud del pétalo") +
p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo") +
labs(subtitle = "(diferenciando por especie de lirio)") +
labs(caption = "Datos provenientes del Iris dataset") +
labs(x = "Longitud del sépalo") +
labs(y = "Longitud del pétalo") +
labs(color = "Especie de lirio") +
p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo") +
labs(subtitle = "(diferenciando por especie de lirio)") +
labs(caption = "Datos provenientes del Iris dataset") +
labs(x = "Longitud del sépalo") +
labs(y = "Longitud del pétalo") +
labs(color = "Especie de lirio") +
labs(tag = "Plot 1")

El chunk no se suele escribir de esa forma, sino así:

p <- p +
labs(title = "Gráfico 1: Longitud del sépalo frente al pétalo",
    subtitle = "(diferenciando por especie de lirio)",
    caption = "Datos provenientes del Iris dataset",
    x = "Longitud del sépalo",
    y = "Longitud del pétalo",
    color = "Especie de lirio",
    tag = "Plot 1")

Texto alternativo: gráficos accesibles

  • Las personas que usan lectores de pantalla no “ven” el gráfico. Con labs(alt = ...) podemos añadir un texto alternativo que describa lo que muestra:
p + labs(alt = "Gráfico de puntos: la longitud del pétalo crece con
                la del sépalo; los lirios setosa forman un grupo aparte,
                con pétalos mucho más cortos")
  • En Quarto también se puede poner con la opción de chunk #| fig-alt: "..."

  • Un buen texto alternativo no describe el código, sino el mensaje del gráfico

A veces interesa eliminar elementos de los labels/títulos

p +
p +
labs(color = NULL) + #- borra el título de la leyenda
p +
labs(color = NULL) + #- borra el título de la leyenda
labs(x = NULL) + #- borra el título del eje X
p +
labs(color = NULL) + #- borra el título de la leyenda
labs(x = NULL) + #- borra el título del eje X
labs(subtitle = NULL) +
p +
labs(color = NULL) + #- borra el título de la leyenda
labs(x = NULL) + #- borra el título del eje X
labs(subtitle = NULL) +
labs(caption = NULL) +
p +
labs(color = NULL) + #- borra el título de la leyenda
labs(x = NULL) + #- borra el título del eje X
labs(subtitle = NULL) +
labs(caption = NULL) +
labs(title = NULL) +
p +
labs(color = NULL) + #- borra el título de la leyenda
labs(x = NULL) + #- borra el título del eje X
labs(subtitle = NULL) +
labs(caption = NULL) +
labs(title = NULL) +
labs(y = NULL)  + #- borra el título del eje Y
p +
labs(color = NULL) + #- borra el título de la leyenda
labs(x = NULL) + #- borra el título del eje X
labs(subtitle = NULL) +
labs(caption = NULL) +
labs(title = NULL) +
labs(y = NULL)  + #- borra el título del eje Y
labs(tag = NULL)

  • Para los labels de los ejes X e Y es muy frecuente usar: xlab(NULL) y ylab(NULL)

  • Queda la leyenda. La leyenda no es un elemento de los labels/título, sino del theme. Se puede eliminar con: theme(legend.position = "none")

Theme: cambiando la apariencia del gráfico

  • Podemos cambiar los detalles de la apariencia del gráfico; por ejemplo, el tamaño, fuente y color de los títulos, pero también de los puntos, las líneas, el fondo del gráfico, la apariencia de las grid-lines, el lugar para las leyendas, etc … etc …. Para hacerlo hay que usar las “funciones de tema”. Todas ellas comienzan con theme_()


  • En general con las funciones theme_() podemos cambiar/ajustar cualquier elemento del gráfico, con la excepción de la propia representación de los datos (ya sabemos que esto se hacen con las funciones geom_()). Estos elementos afectan a la apariencia y detalles del gráfico, pero no a la relación entre variables que se muestra realmente en el gráfico.

Themes/Temas predefinidos

p +
p +
theme_gray()  + #- tema por defecto
p +
theme_gray()  + #- tema por defecto
theme_light() +
p +
theme_gray()  + #- tema por defecto
theme_light() +
theme_dark() +
p +
theme_gray()  + #- tema por defecto
theme_light() +
theme_dark() +
theme_classic() +
p +
theme_gray()  + #- tema por defecto
theme_light() +
theme_dark() +
theme_classic() +
theme_minimal() +
p +
theme_gray()  + #- tema por defecto
theme_light() +
theme_dark() +
theme_classic() +
theme_minimal() +
theme_void()

En el pkg ggthemes hay muchos themes

library(ggthemes)
library(ggthemes)
p +
library(ggthemes)
p +
theme_economist() +
library(ggthemes)
p +
theme_economist() +
theme_fivethirtyeight() +
library(ggthemes)
p +
theme_economist() +
theme_fivethirtyeight() +
theme_stata() +
library(ggthemes)
p +
theme_economist() +
theme_fivethirtyeight() +
theme_stata() +
theme_solarized() +
library(ggthemes)
p +
theme_economist() +
theme_fivethirtyeight() +
theme_stata() +
theme_solarized() +
theme_excel()

Si te interesa el tema de los themes. [Aquí] tienes el repo de ggthemes y [aquí] puedes ver más ejemplos de themes.

¿Puedo definir mi propio theme? Sí, absolutely.

my_theme <- theme(
  axis.text.x = element_text(colour = "red", angle = 45, vjust = - 0.33) ,
  axis.text.y = element_text(colour = "#7700AA",  size = 14) ,
  text = element_text(size = 16))

p + my_theme



Podemos fijar el theme (para los siguientes gráficos)

#-podemos fijar un theme concreto
theme_set(theme_minimal())

# podemos fijar un theme y variar algún elemento (p.ej: eje X sin ticks ni escalas)
theme_set(theme_minimal() + theme(axis.text.x = element_blank()))

# si queremos volver al default theme
theme_set(theme_gray())

Ejemplos de elementos cuya apariencia podemos cambiar con theme()

  • En realidad se puede cambiar todo. Puedes mirar la ayuda con: help(theme) o con args(theme)
  • Algunos ejemplos
#- LEYENDA
p + theme(legend.position = "none")    #- que no aparezca leyenda
p + theme(legend.position = "bottom")  #- leyenda abajo
p + theme(legend.direction = "horizontal") #- leyenda horizontal!!

p + theme(legend.title = element_text(size = 22)) #- título de la leyenda a 22
p + theme(legend.key.size = unit(2.4, "cm"))   #- tamaño de los cuadros de la leyenda

#- Elementos de texto
p + theme(text = element_text(size = 20, face = "bold"))  #- cambiar tamaño de todos los elementos de texto
p + theme(text = element_text(face = "bold")) #- pone en negrita todos los elementos de texto

Más ejemplos de elementos cuya apariencia podemos cambiar con theme()

#- EJES
p + theme(axis.text.x = element_text(colour = "pink", size = 12,
                                     angle = 90, vjust = +3.5)) # apariencia de la escala del eje x
p + theme(axis.title.y = element_text(size = 15, angle = 75)) #- tamaño y ángulo del texto del eje Y

#- TÍTULOS
p + theme(plot.subtitle = element_text(hjust = -3)) #- posición horizontal del subtítulo (si lo tuviese)
p + theme(plot.caption = element_text(hjust = 8)) #- posición horizontal del pie de gráfico (si lo tuviese)

#- BACKGROUND
p + theme(panel.background = element_rect(fill = "green", colour = "pink",
                                          linetype = "longdash", linewidth = 3.5))

p + theme(panel.background = element_blank())
p + theme(panel.background = NULL)

p + theme(plot.background = element_rect(fill = "pink", colour = "purple",
                                         linetype = "dotted", linewidth = 7))

¿Cómo se llaman todos los elementos del gráfico?

Colores ( 🖥 🎨 )

Sé poquito de colores, pero claro, si quieres cambiar la apariencia de los gráficos, has de saber los colores de R, así que:

  • R tiene 657 colores con nombre. Para ver la lista ejecuta: aa <- as.data.frame(colours())

  • Si sabes el nombre del color que quieres, [aquí], podrás buscarlo y ver su color y su codificación en RGB y Hex.

  • También es interesante el [paquete paleteer] que agrupa un conjunto amplio de paletas de colores para usar en R.

Paletas de colores (y daltonismo)

  • Alrededor de un 8% de los hombres tiene algún tipo de daltonismo: el rojo y el verde de la paleta por defecto les cuesta distinguirlos

  • Mejor usar paletas pensadas para eso: viridis (viene con ggplot2) o algunas de ColorBrewer como "Dark2"

p + scale_color_viridis_d()

p + scale_color_brewer(palette = "Dark2")

Small multiples (o facetting)

  • Veámoslo en acción con el conjunto de datos iris. En iris, hay una variable: Species que es un factor, es una variable categórica.
#- volvemos a crear p, ahora sin títulos
p <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
     geom_point()
p

Small multiples con facet_grid() y facet_wrap()

p +
p +
facet_grid(
cols = vars(Species)) + # gráficos x columnas
p +
facet_grid(
cols = vars(Species)) + # gráficos x columnas
facet_grid(
rows = vars(Species)) + # gráficos x filas
p +
facet_grid(
cols = vars(Species)) + # gráficos x columnas
facet_grid(
rows = vars(Species)) + # gráficos x filas
facet_wrap(
vars(Species), nrow = 2, ncol = 2) # filas y columnas

Small multiples con facet_grid() y facet_wrap()

La forma habitual de escribir ese código es:

p + facet_grid(cols = vars(Species))   # gráficos x columnas

p + facet_grid(rows = vars(Species))   # gráficos x filas

p + facet_wrap(vars(Species), nrow = 2, ncol = 2) # graf x filas y columnas
  • En muchos ejemplos (y en internet) verás los facets escritos con una fórmula (~). Es equivalente:
p + facet_wrap(~ Species)                  #- igual que facet_wrap(vars(Species))
p + facet_grid(rows = vars(Species))       #- igual que facet_grid(Species ~ .)
p + facet_grid(cols = vars(Species))       #- igual que facet_grid(. ~ Species)

Small multiples con 2 variables categóricas

  • Iris sólo tiene un factor, así que vamos a discretizar una variable del dataset:
iris_2 <- iris |>
  mutate(Petal_2 = if_else(ntile(Petal.Width, 2) == 1, "pétalo estrecho", "pétalo ancho"))
iris_2  |> ggplot() +
geom_point(aes(Sepal.Length, Petal.Length, color = Species)) +
facet_grid(rows = vars(Petal_2), cols = vars(Species))

Ejes de los small multiples (!!)

  • Por defecto las escalas de los ejes de los small multiple son comunes, pero podemos cambiarlo:
p + facet_grid(rows = vars(Species))    #- escalas comunes

p + facet_grid(rows = vars(Species), scales = "free")   #- las escalas de cada small pueden variar

p + facet_grid(rows = vars(Species), scales = "free_y") #- solo dejamos libre/variar la escala del eje y

3.4 Más elementos de ggplot2: Anotaciones (!!)

  • Las anotaciones permiten resaltar algún fenómeno o observación de interés y son importantes a la hora de contar historias (storytelling) con los gráficos y visualizaciones.

  • En el entorno ggplot podemos hacer anotaciones en nuestros gráficos de varias maneras: veremos un poco de 3:

    • con la función annotate().

    • con geom_text()

    • con geom_vline() , geom_hline() y geom_abline()

Anotaciones con annotate()

p +
p +
annotate(geom = "text",
  x = 6,
  y = 2,
  label = "Una anotación",
  size = 5) +
p +
annotate(geom = "text",
  x = 6,
  y = 2,
  label = "Una anotación",
  size = 5) +
annotate("rect",
  xmin = 6,
  xmax = 7,
  ymin = -Inf,
  ymax = Inf,
  alpha = 0.2,
  fill = "pink") +
p +
annotate(geom = "text",
  x = 6,
  y = 2,
  label = "Una anotación",
  size = 5) +
annotate("rect",
  xmin = 6,
  xmax = 7,
  ymin = -Inf,
  ymax = Inf,
  alpha = 0.2,
  fill = "pink") +
annotate("segment",
  x = 5,
  xend = 7,
  y = 6,
  yend = 8,
  colour = "blue")

Anotaciones con annotate()

La forma habitual de escribir ese código es:

p + annotate(geom = "text", x = 6, y = 2, label = "Una anotación", size = 5) +
    annotate("rect", xmin = 6, xmax = 7,ymin = -Inf, ymax = Inf, alpha = 0.2, fill = "pink") +
    annotate("segment", x = 5, xend = 7, y = 6, yend = 8, colour = "blue")

Anotaciones con geom_text()

p +
p +
geom_text(aes(label = Petal.Length)) +
p +
geom_text(aes(label = Petal.Length)) +
geom_text(aes(label = Species))

Anotaciones con geom_text()

Así no parece muy útil, pero podemos mejorarlo: ponemos una etiqueta sólo en el lirio con el pétalo más largo de cada especie

iris_max <- iris |> group_by(Species) |>
  slice_max(Petal.Length, n = 1, with_ties = FALSE)

p_text <- p +
 geom_text(data = iris_max, aes(label = Species),
           color = "black", size = 4)

Etiquetas que no se solapan: ggrepel

  • Con geom_text() las etiquetas se ponen justo encima del punto y muchas veces se solapan. El paquete ggrepel las “aparta” automáticamente
iris_extremos <- iris |> group_by(Species) |>
  filter(Petal.Length %in% range(Petal.Length)) |>
  slice_head(n = 2)

p_repel <- p +
  ggrepel::geom_label_repel(data = iris_extremos,
      aes(label = paste(Species, Petal.Length)),
      size = 3.5, show.legend = FALSE)

Anotaciones con geom_xx_line()

p +
p +
geom_vline(xintercept = 6) +
p +
geom_vline(xintercept = 6) +
geom_hline(yintercept = 5,
  linewidth = 1.7,
  colour = "purple",
  linetype = "dashed") +
p +
geom_vline(xintercept = 6) +
geom_hline(yintercept = 5,
  linewidth = 1.7,
  colour = "purple",
  linetype = "dashed") +
geom_abline(intercept = 0.7,
  slope = 0.4,
  linewidth = 2,
  colour = "steelblue")

Anotaciones con geom_xx_line()

La forma habitual de escribir ese código es:

p + geom_vline(xintercept = 6)
p + geom_hline(yintercept = 5, linewidth = 1.7, colour = "purple", linetype = "dashed")
p + geom_abline(intercept = 0.7, slope = 0.4, linewidth = 2, colour = "steelblue")

3.5 Más elementos de ggplot2: límites de los ejes

  • Los límites o dominio del gráfico suelen obtenerse automáticamente de los datos, pero, según Hadley Wickham, hay dos razones por las que podemos estar interesados en cambiar los límites del gráfico:

    • centrarnos en una región específica del gráfico

    • aumentar los límites para que varios gráficos ajusten sus escalas.

  • Si quieres modificar el recorrido de los ejes, los “límites” de los ejes, puedes usar lims(). Para los ejes X e Y hay dos funciones auxiliares: xlim() e ylim().

En realidad-realidad los límites de los ejes se controlan con scale_xx()

  • . . . pero lo dejamos para la siguiente sección.

Límites de los gráficos: lims()

#limites: x[4-8] y[1-7]
p +
#limites: x[4-8] y[1-7]
p +
lims(x = c(NA,6)) +
#limites: x[4-8] y[1-7]
p +
lims(x = c(NA,6)) +
lims(y = c(1,8)) +
#limites: x[4-8] y[1-7]
p +
lims(x = c(NA,6)) +
lims(y = c(1,8)) +
lims(color = c("setosa")) +
#limites: x[4-8] y[1-7]
p +
lims(x = c(NA,6)) +
lims(y = c(1,8)) +
lims(color = c("setosa")) +
xlim(c(5, 6)) +
#limites: x[4-8] y[1-7]
p +
lims(x = c(NA,6)) +
lims(y = c(1,8)) +
lims(color = c("setosa")) +
xlim(c(5, 6)) +
ylim(c(NA, 5)) +
#limites: x[4-8] y[1-7]
p +
lims(x = c(NA,6)) +
lims(y = c(1,8)) +
lims(color = c("setosa")) +
xlim(c(5, 6)) +
ylim(c(NA, 5)) +
#- podemos dar la vuelta a los ejes
xlim(c (7, 3)) +
#limites: x[4-8] y[1-7]
p +
lims(x = c(NA,6)) +
lims(y = c(1,8)) +
lims(color = c("setosa")) +
xlim(c(5, 6)) +
ylim(c(NA, 5)) +
#- podemos dar la vuelta a los ejes
xlim(c (7, 3)) +
ylim(c(NA, 5))

Ojo: lims(), xlim() e ylim() eliminan (convierten en NA) los datos que quedan fuera de los límites. Por eso R avisa: Removed n rows containing missing values

Haciendo zoom en un gráfico

p +
p +
xlim(c(4, 5)) +
p +
xlim(c(4, 5)) +
ylim(c(NA, 5))

Haciendo zoom: cuidado!!

  • Si cambias los límites de un gráfico para hacer un zoom, hay que tener cuidado ya que si después utilizas alguna transformación estadística como por ejemplo geom_smooth(), las observaciones eliminadas al ajustar los límites no entrarán en el cálculo estadístico.
p + geom_smooth(color = "purple")
p + geom_smooth(color = "purple") + xlim(c(4, 5.7)) + ylim(c(1.5, 5))   #- ¡elimina puntos!
  • Se puede solucionar con coord_cartesian().

Haciendo zoom con coord_cartesian()

p + geom_smooth(color = "purple")
p + geom_smooth(color = "purple") + coord_cartesian(xlim = c(4, 5.7), ylim = c(1.5, 5))

Haciendo que el gráfico empiece en (0,0)

ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point() +
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point() +
expand_limits(y = 0, x = 0) +
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point() +
expand_limits(y = 0, x = 0) +
scale_x_continuous(expand = c(0, 0)) +
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point() +
expand_limits(y = 0, x = 0) +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0)) +
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point() +
expand_limits(y = 0, x = 0) +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0)) +
geom_vline(xintercept = 0) +
ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
geom_point() +
expand_limits(y = 0, x = 0) +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(expand = c(0, 0)) +
geom_vline(xintercept = 0) +
geom_hline(yintercept = 0)

Como nos cuentan aquí hay razones para que el eje Y de un gráfico empiece en 0.

3.6 Más elementos de ggplot2: Escalas (!!)

  • Las escalas permiten leer/interpretar un gráfico.

  • A veces es importante pararse a pensar cuál es la mejor escala para representar las variables. Quizás sea conveniente cambiar la escala de un eje para distribuir mejor las observaciones en el espacio, o para interpretar mejor las variaciones entre observaciones; por ejemplo la escala logarítmica o en porcentajes son a veces más apropiadas que las escalas originales.


  • Las escalas en ggplot2 se crean/controlan con una familia de funciones: scale_xx(). Estas funciones también construyen los elementos que permiten leer/interpretar los gráficos: los ejes y las leyendas.


  • Como ggplot2 genera las escalas y leyendas automáticamente, en la práctica podemos hacer gráficos sin saber cómo funcionan las scale_xx(). PERO, en realidad, para cada par variable/estética representada en un gráfico ggplot es necesaria una escala, y tendría que fijarse con una de las funciones de la familia scale_xx()

3.6 Más elementos de ggplot2: Escalas (!!)

  • ggplot2 genera las escalas automáticamente. Cuando hacemos este gráfico:
ggplot(iris, aes(Sepal.Length, Petal.Length)) +
  geom_point(aes (color = Species))


  • … “en realidad” se está haciendo:
ggplot(iris, aes(Sepal.Length, Petal.Length)) +
  geom_point(aes (color = Species)) +
  scale_x_continuous() +
  scale_y_continuous() +
  scale_color_discrete()

Escalas: ejemplos (!!!)

p +
p +
scale_y_reverse() +
p +
scale_y_reverse() +
scale_y_continuous() +
p +
scale_y_reverse() +
scale_y_continuous() +
scale_colour_grey() +
p +
scale_y_reverse() +
scale_y_continuous() +
scale_colour_grey() +
scale_color_brewer(palette = "Dark2") +
p +
scale_y_reverse() +
scale_y_continuous() +
scale_colour_grey() +
scale_color_brewer(palette = "Dark2") +
scale_color_discrete() +
p +
scale_y_reverse() +
scale_y_continuous() +
scale_colour_grey() +
scale_color_brewer(palette = "Dark2") +
scale_color_discrete() +
scale_x_sqrt() +
p +
scale_y_reverse() +
scale_y_continuous() +
scale_colour_grey() +
scale_color_brewer(palette = "Dark2") +
scale_color_discrete() +
scale_x_sqrt() +
scale_x_continuous(transform = "log") +
p +
scale_y_reverse() +
scale_y_continuous() +
scale_colour_grey() +
scale_color_brewer(palette = "Dark2") +
scale_color_discrete() +
scale_x_sqrt() +
scale_x_continuous(transform = "log") +
scale_y_log10()

Escalas: más cosas (!!!)

p +
p +
labs(x = "Eje X",
     y = "Eje Y",
     color = "Leyenda\n para el color") +
p +
labs(x = "Eje X",
     y = "Eje Y",
     color = "Leyenda\n para el color") +
scale_x_continuous(
 breaks = seq(3, 10, 0.5),
 limits = c(3, 10)) +
p +
labs(x = "Eje X",
     y = "Eje Y",
     color = "Leyenda\n para el color") +
scale_x_continuous(
 breaks = seq(3, 10, 0.5),
 limits = c(3, 10)) +
scale_y_continuous(
 breaks = seq(0, 12, 0.25),
 labels = scales::label_number(suffix = " cm")) +
p +
labs(x = "Eje X",
     y = "Eje Y",
     color = "Leyenda\n para el color") +
scale_x_continuous(
 breaks = seq(3, 10, 0.5),
 limits = c(3, 10)) +
scale_y_continuous(
 breaks = seq(0, 12, 0.25),
 labels = scales::label_number(suffix = " cm")) +
scale_color_manual(
 values = c("purple", "pink", "red2"),
 name = "Especies\n de lirios")

3.7 Stats (transformaciones estadísticas)

  • Algunos gráficos, como los de puntos, no requieren transformaciones estadísticas: lo que se grafica coincide con los valores de las observaciones. Ciertos gráficos, por ejemplo los boxplots, no se representan las variables originales, sino una transformación de estas.

  • Podemos usar transformaciones estadísticas en gráficos ggplot con la familia de funciones stat_xx().

  • Cada geom_xx() que utilicemos, en realidad necesita de un stat_xx(), entonces ¿por qué nunca lo hemos usado nosotros? Con ggplot2 la razón es casi siempre la misma: porque under the hood ggplot2 hace muchas cosas por nosotros. En concreto, cada vez que usamos un geom_xx() ggplot2 está fijando una transformación estadística por defecto por nosotros.

  • Cuando hacíamos:

ggplot(iris, aes(Petal.Length, Sepal.Length)) + geom_point()
  • En realidad, estamos haciendo:
ggplot(iris, aes(Petal.Length, Sepal.Length)) +
  geom_point(stat = "identity")

Stats (transformaciones estadísticas) (!!!)

p +
p +
geom_point(stat = "identity") +
p +
geom_point(stat = "identity") +
geom_point(stat = "unique") +
p +
geom_point(stat = "identity") +
geom_point(stat = "unique") +
geom_point(stat = "smooth")

Stats (transformaciones estadísticas) (!!!)

  • Es raro que tengamos que usar stat_xx() directamente

Stats: un ejemplo (!!!)

ggplot(iris,
 aes(Species, Sepal.Length)) +
ggplot(iris,
 aes(Species, Sepal.Length)) +
geom_boxplot() +
ggplot(iris,
 aes(Species, Sepal.Length)) +
geom_boxplot() +
geom_point(
  stat = "summary",
  fun = "mean",
  colour = "red", size = 4)

Stats: un ejemplo (!!!)

La forma habitual de escribir ese código es:

ggplot(iris, aes(Species, Sepal.Length)) +
  geom_boxplot() +
  geom_point(stat = "summary", fun = "mean",
             colour = "red", size = 4)

3.7 Stats: otro ejemplo (!!!)

ggplot(iris, aes(Sepal.Length)) + geom_histogram()

ggplot(iris, aes(Sepal.Length)) +
   geom_histogram(aes(y = after_stat(count / max(count))))

3.8 Position adjustments (un ejemplo)

p_pos <- ggplot(iris, aes(Sepal.Length, Petal.Length)) + geom_point()

p_pos + geom_point(position = "jitter", color = "pink")

También se puede usar geom_jitter()

p_pos + geom_jitter(color = "pink")

3.8 Position adjustments (otro ejemplo)

p_bar <- ggplot(mtcars, aes(factor(cyl), fill = factor(vs)))
p1 <- p_bar + geom_bar()                                  #- apiladas (por defecto)
p2 <- p_bar + geom_bar(position = "fill")                 #- apiladas al 100%
p3 <- p_bar + geom_bar(position = "dodge")                #- una al lado de otra
p4 <- p_bar + geom_bar(position = position_dodge2(preserve = "single"))

3.9 Coordenadas: algunos ejemplos

  • Es el sistema por defecto. Ya lo hemos usado para hacer zoom sin eliminar datos
p + coord_cartesian(xlim = c(4, 5.7), ylim = c(1.5, 5))

  • Intercambia los ejes X e Y (útil, p.ej., en gráficos de barras con etiquetas largas). Hoy en día suele bastar con intercambiar las variables en aes()
ggplot(iris, aes(Species, Sepal.Length)) + geom_boxplot() + coord_flip()

  • Fija la relación entre las unidades de los ejes: con ratio = 1, una unidad en X mide lo mismo que una unidad en Y
p + coord_fixed(ratio = 1)

  • Coordenadas polares. Así se hacen, p.ej., los gráficos de tarta (que no suelen ser buena idea!)
ggplot(mtcars, aes(x = "", fill = factor(cyl))) + geom_bar() + coord_polar(theta = "y")

4. Combinando gráficos

A veces interesa crear una figura compuesta de varios gráficos diferentes.


Podemos usar varios paquetes: gridExtra, patchwork o cowplot

4. Combinando gráficos

library(patchwork)
p1 <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) + geom_point() + theme(legend.position = "none")
p2 <- ggplot(iris)+ aes(Species, Sepal.Length) + geom_boxplot()
p3 <- ggplot(iris, aes(Sepal.Length, fill = Species)) + geom_density(position = "stack", alpha = 0.5)
p1 + p2 / p3

5. Exportando gráficos

A veces necesitaremos guardar el gráfico en un fichero.


Piensa que estamos guardando la imagen, la representación del gráfico, no el objeto R.

5. Exportando gráficos

Si queremos guardar (la representación gráfica de) un gráfico en un archivo (.jpg, png, …)

  • Podemos usar la “Export Tab” en el Plot Pane de Rstudio. Podemos cambiar las dimensiones (anchura y altura) del gráfico.

  • Podemos usar la función ggsave(). Nos permite cambiar el tamaño y la resolución del gráfico. Si no le decimos qué gráfico (plot =), guarda el último que hemos dibujado

my_plot <- p + labs(title = "Mi gráfico")
ggsave("my_plot.png", plot = my_plot, width = 8, height = 6, units = "in", dpi = "retina")

Si queremos guardar una copia completa del gráfico, no de su representación visual, sino del objeto R, podemos hacerlo con saveRDS().

saveRDS(my_plot, "my_plot.rds")

8. Asistentes para ggplot2

Hay varios asistentes para crear o modificar gráficos ggplot a través de interfaces gráficas.


Por ejemplo: ggThemeAssist, esquisse y ggannotate

8. Asistentes para ggplot2

Hay varios asistentes para crear o modificar gráficos ggplot a través de interfaces gráficas. Por ejemplo: [ggThemeAssist], [esquisse] y [ggannotate].


  • El paquete ggThemeAssist (sólo funciona en RStudio, no en Positron) facilita, mediante un addin de RStudio, la edición de los detalles de un gráfico; es decir, puedes comenzar haciendo un gráfico básico en RStudio, para después usar ggThemeAssist para modificar los elementos estéticos de gráfico como títulos, leyendas, colores etc… etc…
  • El paquete esquisse permite crear gráficos ggplot desde cero con una interfaz gráfica: ejecuta esquisse::esquisser(iris), haz el gráfico arrastrando variables y copia el código que genera.
  • El paquete ggannotate permite crear anotaciones en gráficos ggplot.

Juntándolo todo: un gráfico “de verdad”

Tarea: con los datos penguins (vienen con R desde la versión 4.5) haz un gráfico que:

  • represente la longitud de la aleta (flipper_len) frente al peso (body_mass), con el color según la especie (species)
  • tenga título, subtítulo, nombres de los ejes en castellano y la fuente de los datos
  • tenga un panel para cada isla (island)
  • use una paleta apta para daltónicos y theme_minimal(), con la leyenda abajo
ggplot(penguins, aes(flipper_len, body_mass, color = species)) +
  geom_point(alpha = 0.7) +
  facet_wrap(vars(island)) +
  scale_color_viridis_d() +
  labs(title = "Pingüinos del archipiélago Palmer",
       subtitle = "Los pingüinos con aletas más largas pesan más",
       x = "Longitud de la aleta (mm)", y = "Peso (g)", color = "Especie",
       caption = "Datos: paquete datasets (R >= 4.5)") +
  theme_minimal() +
  theme(legend.position = "bottom")