Gráficos con ggplot2 (C): Tipos de gráficos

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

Pedro J. Pérez

Galerías con ejemplos

En estas slides presentaremos ejemplos de algunos de los gráficos más utilizados en el análisis de datos. Puedes ver listados más completos en:

¿Qué gráfico uso?

Depende de qué quieres mostrar y de qué tipo de variables tienes:

Qué quieres mostrar Variables Gráfico geom
La distribución de una variable 1 continua histograma, densidad geom_histogram(), geom_density()
Comparar distribuciones entre grupos 1 continua + 1 categórica boxplot, violín, ridges geom_boxplot(), geom_violin(), ggridges
Cuántas observaciones hay de cada categoría 1 categórica barras geom_bar()
Un valor (ya calculado) para cada categoría 1 categórica + 1 numérica barras geom_col()
La evolución en el tiempo fecha + 1 continua líneas geom_line()
La relación entre dos variables 2 continuas puntos (scatter) geom_point()

Evidentemente, el tipo de gráfico se ha de elegir en función de la información que se quiere mostrar. [Aquí] puedes encontrar ayuda para elegir el tipo de gráfico. Por ejemplo:

[From Data to Viz], [The Data Visualisation Catalogue], [The chart chooser], [The Chart Chooser: Interactive Version], etc …

En las siguientes slides veremos un ejemplo de cada uno

Histogramas con geom_histogram()

ggplot(iris, aes(Sepal.Length)) +
ggplot(iris, aes(Sepal.Length)) +
geom_histogram(bins = 60) + labs(title = "60 intervalos (o bins)") +
ggplot(iris, aes(Sepal.Length)) +
geom_histogram(bins = 60) + labs(title = "60 intervalos (o bins)") +
geom_histogram(bins = 40) + labs(title = "40 intervalos") +
ggplot(iris, aes(Sepal.Length)) +
geom_histogram(bins = 60) + labs(title = "60 intervalos (o bins)") +
geom_histogram(bins = 40) + labs(title = "40 intervalos") +
geom_histogram(binwidth = 0.5) + labs(title = "En lugar de elegir el nº de intervalos, \n se puede elegir la anchura del intervalo: \n binwidth =  0.5") +
ggplot(iris, aes(Sepal.Length)) +
geom_histogram(bins = 60) + labs(title = "60 intervalos (o bins)") +
geom_histogram(bins = 40) + labs(title = "40 intervalos") +
geom_histogram(binwidth = 0.5) + labs(title = "En lugar de elegir el nº de intervalos, \n se puede elegir la anchura del intervalo: \n binwidth =  0.5") +
geom_histogram(binwidth = 0.5,
               color = "black",
               fill = "tomato") + labs(title = "binwidth =  0.5, color = black, fill = tomato") +
ggplot(iris, aes(Sepal.Length)) +
geom_histogram(bins = 60) + labs(title = "60 intervalos (o bins)") +
geom_histogram(bins = 40) + labs(title = "40 intervalos") +
geom_histogram(binwidth = 0.5) + labs(title = "En lugar de elegir el nº de intervalos, \n se puede elegir la anchura del intervalo: \n binwidth =  0.5") +
geom_histogram(binwidth = 0.5,
               color = "black",
               fill = "tomato") + labs(title = "binwidth =  0.5, color = black, fill = tomato") +
geom_histogram(binwidth = 0.5,
               aes(fill = Species),
               color = "black") + labs(title = "binwidth =  0.5, color = black, aes(fill = Species)") +
ggplot(iris, aes(Sepal.Length)) +
geom_histogram(bins = 60) + labs(title = "60 intervalos (o bins)") +
geom_histogram(bins = 40) + labs(title = "40 intervalos") +
geom_histogram(binwidth = 0.5) + labs(title = "En lugar de elegir el nº de intervalos, \n se puede elegir la anchura del intervalo: \n binwidth =  0.5") +
geom_histogram(binwidth = 0.5,
               color = "black",
               fill = "tomato") + labs(title = "binwidth =  0.5, color = black, fill = tomato") +
geom_histogram(binwidth = 0.5,
               aes(fill = Species),
               color = "black") + labs(title = "binwidth =  0.5, color = black, aes(fill = Species)") +
facet_grid(cols = vars(Species))

¿Por qué elegir bins o binwidth? Si no lo hacemos, ggplot2 usa 30 intervalos y nos avisa: stat_bin() using bins = 30. Pick better value with binwidth. El número de intervalos cambia mucho la forma del histograma: hay que probar varios.

Histograma, densidad y puntos, juntos

  • geom_density() es como un histograma “suavizado”. Para dibujarlos juntos, el histograma tiene que estar en la misma escala que la densidad: y = after_stat(density). Y con geom_jitter() vemos además dónde está cada observación
ggplot(iris, aes(Sepal.Length)) +
  geom_histogram(aes(y = after_stat(density)),
                 bins = 20, fill = "grey80") +
  geom_density(color = "steelblue", linewidth = 1) +
  geom_jitter(aes(y = -0.03), height = 0.02,
              alpha = 0.5, color = "tomato")

7.2 geom_density() y Joy Division plots

ggplot(iris, aes(Sepal.Length, fill = Species)) + geom_density(alpha = 0.5)
ggplot(iris, aes(x = Sepal.Length, y = Species)) +
      ggridges::geom_density_ridges(aes(fill = Species), alpha = 0.5)

¿Por qué “Joy Division plots”?

  • Los gráficos de ridges (crestas) se llaman así por la portada del disco Unknown Pleasures (1979) del grupo Joy Division

  • La portada era un gráfico de las señales de un púlsar, con muchas curvas apiladas. Lo podemos imitar con ggridges 😎

set.seed(1979)
pulsar <- tibble(linea = rep(1:40, each = 300)) |>
  mutate(pico = if_else(runif(n()) < 0.3,
                        rnorm(n(), 0, 0.3), 0),
         x = rnorm(n()) + pico)

ggplot(pulsar, aes(x, y = linea, group = linea)) +
  ggridges::geom_density_ridges(fill = "black",
        color = "white", scale = 4, linewidth = 0.4) +
  theme_void() +
  theme(plot.background = element_rect(fill = "black"))

7.3 Gráficos de caja (Boxplots)

ggplot(iris, aes(x = Species,  y = Sepal.Length)) +
ggplot(iris, aes(x = Species,  y = Sepal.Length)) +
geom_boxplot() +
ggplot(iris, aes(x = Species,  y = Sepal.Length)) +
geom_boxplot() +
geom_boxplot(aes(fill = Species),
             outlier.colour = "purple") +
ggplot(iris, aes(x = Species,  y = Sepal.Length)) +
geom_boxplot() +
geom_boxplot(aes(fill = Species),
             outlier.colour = "purple") +
geom_jitter(width = 0.15, alpha = 1/4, color = "tomato") +
ggplot(iris, aes(x = Species,  y = Sepal.Length)) +
geom_boxplot() +
geom_boxplot(aes(fill = Species),
             outlier.colour = "purple") +
geom_jitter(width = 0.15, alpha = 1/4, color = "tomato") +
geom_point(stat = "summary", fun = "mean",
           color = "purple", size = 2.5) +
ggplot(iris, aes(x = Species,  y = Sepal.Length)) +
geom_boxplot() +
geom_boxplot(aes(fill = Species),
             outlier.colour = "purple") +
geom_jitter(width = 0.15, alpha = 1/4, color = "tomato") +
geom_point(stat = "summary", fun = "mean",
           color = "purple", size = 2.5) +
geom_violin(aes(fill = Species), alpha = 0.6) +
ggplot(iris, aes(x = Species,  y = Sepal.Length)) +
geom_boxplot() +
geom_boxplot(aes(fill = Species),
             outlier.colour = "purple") +
geom_jitter(width = 0.15, alpha = 1/4, color = "tomato") +
geom_point(stat = "summary", fun = "mean",
           color = "purple", size = 2.5) +
geom_violin(aes(fill = Species), alpha = 0.6) +
coord_flip()
  • Las capas se dibujan en el orden en que las añadimos: por eso el violín tapa la caja
  • [ 🌶🌶 ] al añadir geom_jitter() los outliers salen dos veces (como outlier del boxplot y como punto). Se evita con geom_boxplot(outlier.shape = NA)

Un paréntesis: factores

Para ordenar las cajas de un boxplot o las barras de un gráfico de barras, antes hay que saber qué es un factor

¿Qué es un factor?

  • Un factor es la forma que tiene R de guardar variables categóricas: variables que solo pueden tomar unos valores concretos (especie, continente, nivel de estudios, …)
    Además, un factor guarda cuáles son esas categorías (sus levels) y en qué orden van

  • Veámoslo con unos datos inventados: los estudios y el sueldo de 8 personas

encuesta <- tibble(
  estudios = c("Grado", "ESO", "Máster", "Grado", "Bachiller", "Grado", "ESO", "Bachiller"),
  sueldo   = c(1800, 1100, 2400, 2000, 1300, 1700, 1000, 1400))


count(encuesta, estudios)
estudios
<chr>
n
<int>
Bachiller 2
ESO 2
Grado 3
Máster 1
  • Ahora estudios es un string, y R lo ordena alfabéticamente

  • Pero el orden natural es otro: ESO, Bachiller, Grado y Máster … ¿cómo se lo decimos a R?

Crear un factor: factor()

  • Con factor() le decimos a R cuáles son las categorías (los levels) y en qué orden van
encuesta <- encuesta |>
  mutate(estudios = factor(estudios,
1    levels = c("ESO", "Bachiller", "Grado", "Máster")))

2levels(encuesta$estudios)
#> [1] "ESO"       "Bachiller" "Grado"     "Máster"
1
las categorías, en el orden que queremos
2
levels() nos dice cuáles son las categorías y en qué orden van
count(encuesta, estudios)
estudios
<fct>
n
<int>
ESO 2
Bachiller 2
Grado 3
Máster 1
  • Ahora count() respeta nuestro orden. Y fíjate en el tipo de la columna: <fct>

algunos detalles sobre los factores

  • Si no le damos los levels, factor() los pone en orden alfabético
factor(c("Grado", "ESO", "Máster"))
#> [1] Grado  ESO    Máster
#> Levels: ESO Grado Máster
  • Un valor que no esté entre los levels se convierte en NA … ¡sin avisar!
factor(c("Grado", "Doctorado"), levels = c("ESO", "Bachiller", "Grado", "Máster"))
#> [1] Grado <NA> 
#> Levels: ESO Bachiller Grado Máster
  • Muchas veces los factores ya vienen hechos: por ejemplo, Species en iris. Y para volver a tener un string: as.character()
class(iris$Species)
#> [1] "factor"

a veces necesitamos cambiar el orden de los levels

  • Las funciones del paquete forcats (se carga con el tidyverse) empiezan todas por fct_

fct_relevel(): a mano

levels(fct_relevel(encuesta$estudios, "Máster"))
#> [1] "Máster"    "ESO"       "Bachiller" "Grado"

fct_infreq(): por frecuencia

levels(fct_infreq(encuesta$estudios))
#> [1] "Grado"     "ESO"       "Bachiller" "Máster"

fct_rev(): al revés

levels(fct_rev(encuesta$estudios))
#> [1] "Máster"    "Grado"     "Bachiller" "ESO"

fct_reorder(): según otra variable

levels(fct_reorder(encuesta$estudios,
                   encuesta$sueldo, .desc = TRUE))
#> [1] "Máster"    "Grado"     "Bachiller" "ESO"
  • fct_reorder() ordena según la mediana del sueldo de cada categoría. .desc = TRUE: de mayor a menor

Cambiar el orden de los levels no cambia los datos: cambia cómo se ordenan las tablas y, sobre todo, los gráficos

Cambiar las categorías

fct_recode(): cambiar el nombre ("nuevo" = "viejo")

encuesta |>
  mutate(estudios = fct_recode(estudios,
                     "Secundaria" = "ESO")) |>
  count(estudios)
estudios
<fct>
n
<int>
Secundaria 2
Bachiller 2
Grado 3
Máster 1

fct_collapse(): juntar varias categorías en una

encuesta |>
  mutate(estudios = fct_collapse(estudios,
    "Universidad" = c("Grado", "Máster"))) |>
  count(estudios)
estudios
<fct>
n
<int>
ESO 2
Bachiller 2
Universidad 4
  • Y si hay muchas categorías, fct_lump_n(estudios, n = 2) se queda con las 2 más frecuentes y junta las demás en "Other"

Los factores deciden el orden de las categorías

  • ggplot2 dibuja las categorías en el orden de los levels. Y si la variable es un string, en orden alfabético
levels(iris$Species)
#> [1] "setosa"     "versicolor" "virginica"
iris |>
  mutate(Species = fct_relevel(Species,
1                               "virginica")) |>
  ggplot(aes(Species, Sepal.Width)) +
  geom_boxplot()
1
fct_relevel() pone virginica la primera; el resto se queda como estaba

Reordenar las categorías de un gráfico

  • Para cambiar el orden de un gráfico no tocamos el gráfico: cambiamos el orden de los levels. Las funciones de forcats (todas empiezan por fct_):
Para ordenar las categorías … usamos …
según otra variable (por defecto, su mediana) fct_reorder(Species, Sepal.Width)
por frecuencia, de la más frecuente a la menos fct_infreq(class)
a mano fct_relevel(Species, "virginica")
al revés fct_rev(class)
  • Se puede hacer dentro de aes(): aes(fct_reorder(Species, Sepal.Width), Sepal.Width). Es rápido, pero el nombre del eje es toda la expresión, así que lo quitamos con labs(x = NULL)

  • … o antes, con mutate(), como en la slide anterior: el eje conserva el nombre de la variable

  • Ojo: en las barras horizontales la primera categoría sale abajo. Por eso a veces hace falta fct_rev()

Ordenar los boxplots

  • Las categorías salen en orden alfabético. Casi siempre se ven mejor ordenadas según la variable que dibujamos: fct_reorder()
ggplot(iris, aes(Species, Sepal.Width)) +
  geom_boxplot()

ggplot(iris, aes(fct_reorder(Species, Sepal.Width),
                 Sepal.Width)) +
  geom_boxplot() + labs(x = NULL)

  • fct_reorder(Species, Sepal.Width) ordena las especies según la mediana de Sepal.Width. De mayor a menor: .desc = TRUE

7.4 Gráficos de barras

ggplot(mpg, aes(y = class)) +
ggplot(mpg, aes(y = class)) +
geom_bar() +
ggplot(mpg, aes(y = class)) +
geom_bar() +
geom_bar(fill = "steelblue") +
ggplot(mpg, aes(y = class)) +
geom_bar() +
geom_bar(fill = "steelblue") +
geom_bar(aes(y = forcats::fct_rev(forcats::fct_infreq(class))),
         fill = "steelblue") +
ggplot(mpg, aes(y = class)) +
geom_bar() +
geom_bar(fill = "steelblue") +
geom_bar(aes(y = forcats::fct_rev(forcats::fct_infreq(class))),
         fill = "steelblue") +
labs(y = NULL)
  • Para que las barras salgan en horizontal basta con poner la variable en el eje Y: aes(y = class). Antes se hacía con coord_flip(), y lo verás en muchos ejemplos de internet

  • fct_infreq() ordena las categorías por frecuencia y fct_rev() les da la vuelta. Como el nombre del eje sería toda esa expresión, lo quitamos con labs(y = NULL)

geom_bar() vs geom_col() [ 🌟 ]

¿Cuántos pingüinos hay de cada especie? El mismo gráfico se puede hacer de dos formas:

geom_bar(): R cuenta por ti. Le das los datos originales (una fila por pingüino) y sólo x

ggplot(penguins, aes(x = species)) +
  geom_bar()

geom_col(): tú le das la altura. Primero cuentas (count() crea la columna n) y luego le das x e y

penguins |> count(species) |>
  ggplot(aes(x = species, y = n)) +
  geom_col()

Regla:
¿una fila por observación? → geom_bar()
¿Ya tienes calculado el valor de cada barra (un recuento, una media, un %…)? → geom_col()

Ordenar las barras con geom_col()

  • Con geom_bar() ordenábamos por frecuencia con fct_infreq(). Con geom_col() el orden lo marca otra variable, la altura de cada barra: para eso está fct_reorder()
mpg |> count(class) |>
  ggplot(aes(n, class)) +
  geom_col()

mpg |> count(class) |>
  ggplot(aes(n, fct_reorder(class, n))) +
  geom_col() + labs(y = NULL)

  • Ordenadas se leen mucho mejor: de un vistazo ves cuál es la mayor y cuál la menor

Gráficos de líneas con geom_line()

economics |>
economics |>
ggplot(aes(date, unemploy)) +
economics |>
ggplot(aes(date, unemploy)) +
geom_line() +
economics |>
ggplot(aes(date, unemploy)) +
geom_line() +
geom_line(color = "steelblue", linewidth = 1) +
economics |>
ggplot(aes(date, unemploy)) +
geom_line() +
geom_line(color = "steelblue", linewidth = 1) +
scale_x_date(date_breaks = "10 years", date_labels = "%Y") +
economics |>
ggplot(aes(date, unemploy)) +
geom_line() +
geom_line(color = "steelblue", linewidth = 1) +
scale_x_date(date_breaks = "10 years", date_labels = "%Y") +
labs(x = NULL, y = "Desempleados (miles)",
     title = "Desempleo en EE.UU.")
#> # A tibble: 6 × 6
#>   date         pce    pop psavert uempmed unemploy
#>   <date>     <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
#> 1 1967-07-01  507. 198712    12.6     4.5     2944
#> 2 1967-08-01  510. 198911    12.6     4.7     2945
#> 3 1967-09-01  516. 199113    11.9     4.6     2958
#> 4 1967-10-01  512. 199311    12.9     4.9     3143
#> 5 1967-11-01  517. 199498    12.8     4.7     3066
#> 6 1967-12-01  525. 199657    11.8     4.8     3018

Gráficos de líneas: ¿por qué no sale bien?

  • Tarea: queremos la esperanza de vida de España, Francia e Italia. ¿Por qué sale este gráfico tan raro?
df_gap <- gapminder::gapminder |>
  filter(country %in%
           c("Spain", "France", "Italy"))

ggplot(df_gap, aes(year, lifeExp)) +
  geom_line()

  • geom_line() une los puntos en el orden del eje X, pero cada año hay 3 puntos (uno por país): por eso hace “zigzag”. Hay que decirle qué puntos van juntos, con group … o con color, que también agrupa
ggplot(df_gap, aes(year, lifeExp,
                   group = country)) +
  geom_line()

ggplot(df_gap, aes(year, lifeExp,
                   color = country)) +
  geom_line()

Gráficos de líneas: varias series

  • Si los datos están en formato largo (una columna con el nombre de la serie y otra con su valor), basta con mapear esa columna a color
economics_long |>
  filter(variable %in% c("psavert", "uempmed")) |>
  ggplot(aes(date, value, color = variable)) +
  geom_line(linewidth = 0.8) +
  labs(x = NULL, y = NULL, color = NULL)

Scatter plots: el problema del overplotting

  • Con muchas observaciones (diamonds tiene casi 54.000) los puntos se tapan unos a otros y no vemos dónde hay más datos. Soluciones: transparencia (alpha) o contar puntos por zonas (geom_bin2d())
ggplot(diamonds, aes(carat, price)) + geom_point()
ggplot(diamonds, aes(carat, price)) + geom_point(alpha = 0.05)
ggplot(diamonds, aes(carat, price)) + geom_bin2d(bins = 60)

8. Gráficos interactivos

Permiten al usuario interactuar con el gráfico, abriéndose posibilidades como: zooming, highlight, o mostrar información adicional al pinchar en algún elemento del gráfico, etc …

Gráficos interactivos

  • Los gráficos interactivos permiten al usuario interactuar con el gráfico

  • En general, JavaScript (JS) es el lenguaje utilizado para hacer gráficos interactivos con librerías como D3, Chart.js, Plotly, vis.js, Highcharts, …

  • Desde hace años, el paquete de R htmlwidgets facilita el uso de las librerías de JS en R

  • Paquetes de R como leaflet, DT, dygraphs, networkD3 y muchos otros utilizan el framework de htmlwidgets para hacer disponibles los gráficos interactivos de JS en R. [Aquí] puedes ver los paquetes que usan htmlwidgets

  • [Aquí] puedes ver una galería con ejemplos

Gráficos interactivos (plotly)

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

Gráficos interactivos (plotly)

p1 <- p + facet_grid(cols = vars(Species))
ggplotly(p1)

Gráficos interactivos (ggiraph)

  • ggiraph es otra opción: en lugar de geom_point() usamos geom_point_interactive() y decidimos qué se ve al pasar el ratón (tooltip) y qué se resalta (data_id)
library(ggiraph)
p_g <- ggplot(iris, aes(Sepal.Length, Petal.Length, color = Species)) +
  geom_point_interactive(aes(tooltip = paste(Species, Petal.Length), data_id = Species), size = 2)

girafe(ggobj = p_g, width_svg = 8, height_svg = 3.5)

Otros htmlwidgets: tablas (DT) y mapas (leaflet)

DT::datatable(iris, options = list(pageLength = 5))
library(leaflet)
leaflet() |>
  addTiles() |>
  addMarkers(lng = -0.3425, lat = 39.4785, popup = "Facultat d'Economia (UV)")

Para practicar: los pingüinos de Palmer

Tarea: con los datos penguins (vienen con R desde la versión 4.5):

  1. Haz un boxplot del peso (body_mass) para cada especie (species), con los puntos encima (geom_jitter()). ¡Que los outliers no salgan dos veces!

  2. Haz un gráfico de barras con el número de pingüinos de cada isla (island), coloreando las barras según la especie

ggplot(penguins, aes(species, body_mass)) +
  geom_boxplot(outlier.shape = NA) +
  geom_jitter(width = 0.15, alpha = 0.4, color = "steelblue")

ggplot(penguins, aes(island, fill = species)) +
  geom_bar()

Extensiones

Algunos truquillos que se usan mucho

Extensión: los números encima de las barras

  • geom_text() también puede usar el stat "count": así pone el recuento de cada barra, sin calcularlo antes
ggplot(mpg, aes(x = class)) +
  geom_bar(fill = "steelblue") +
  geom_text(stat = "count",
            aes(label = after_stat(count)),
            vjust = -0.5)

Extensión: la leyenda, en el subtítulo [ 🌶 ]

  • Con el paquete marquee se pueden poner colores en los títulos: {#color texto}. Así el subtítulo hace de leyenda
library(marquee)     #- pak::pak("marquee")
ggplot(iris, aes(Sepal.Length, Petal.Length,
                 color = Species)) +
  geom_point() +
  labs(subtitle = "Lirios {#F8766D **setosa**},
                   {#00BA38 **versicolor**} y
                   {#619CFF **virginica**}") +
  theme(plot.subtitle = element_marquee(size = 16),
        legend.position = "none")

  • Antes se hacía con el paquete ggtext, pero los colores había que escribirlos en HTML: <span style='color:#F8766D;'>setosa</span>

Extensión: small multiples con todos los datos de fondo

  • Si a una capa le quitamos la variable de los facets, esa capa sale entera en todos los paneles: sirve de fondo para comparar
iris_fondo <- iris |> select(-Species)

ggplot(iris, aes(Sepal.Length)) +
  geom_histogram(data = iris_fondo,
                 fill = "grey85", bins = 15) +
  geom_histogram(aes(fill = Species), bins = 15) +
  facet_wrap(vars(Species))

europa <- gapminder::gapminder |>
  filter(continent == "Europe")
paises <- europa |>
  filter(country %in% c("Spain", "Portugal",
                        "Italy", "Greece"))
df_fondo <- europa |> rename(pais = country)

ggplot(paises, aes(year, lifeExp)) +
  geom_line(data = df_fondo, aes(group = pais),
            color = "grey85") +
  geom_line(color = "firebrick", linewidth = 1) +
  facet_wrap(vars(country))

  • En df_fondo la columna se llama pais, no country: por eso sus líneas salen en todos los paneles. group = pais hace que haya una línea por país

Extensión: un gráfico dentro de otro [ 🌶 ]

  • Con inset_element() del paquete patchwork podemos meter un gráfico pequeño dentro de otro: por ejemplo, para enseñar un detalle o la distribución de una variable
p_grande <- ggplot(iris, aes(Sepal.Length,
                             Petal.Length,
                             color = Species)) +
  geom_point()

p_peque <- ggplot(iris, aes(Petal.Length)) +
  geom_histogram(bins = 15, fill = "grey60") +
  theme_void()

p_grande +
  inset_element(p_peque,
                left = 0.55, bottom = 0.03,
1                right = 0.95, top = 0.4)
1
dónde va el gráfico pequeño, de 0 a 1 (desde la esquina de abajo a la izquierda): aquí, abajo a la derecha

Extensión: otro tipo de letra [ 🌶 ]

  • La letra (la fuente) se cambia en el theme(), con family. Con systemfonts podemos usar cualquiera de Google Fonts:
#- la descarga de Google Fonts y la deja lista:
systemfonts::require_font("Lobster")

p_grande +
  labs(title = "Longitud del sépalo y del pétalo") +
  theme(plot.title = element_text(family = "Lobster",
                                  size = 20))


  • Para que se vea, el gráfico tiene que dibujarse con ragg.
    En RStudio, en Tools → Global Options → General → Graphics,
    el Backend tiene que ser AGG.
    ggsave() ya lo usa (si ragg está instalado)


  • Antes se hacía con showtext o extrafont: siguen funcionando, pero ahora se recomienda systemfonts + ragg