Programación y manejo de datos con R (Slides 06-C)
Mientras entendíamos el funcionamiento de ggplot2 nos centramos en un solo tipo de gráfico: los gráficos de puntos
Ahora veremos distintos tipos de gráficos: histogramas, gráficos de cajas, de barras, de líneas, scatter plots, etc… etc…
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:
[R-graph gallery]: Impresionante!!
[Top 50 ggplot2 Visualizations (With Full R Code)]: de r-statistics.co, más básico pero muy didáctico
[Extensiones ggplot2]: Impresionante!!
[R-graph gallery - ggplot2 package]: otra vez, impresionante!!
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
Se utilizan para mostrar la distribución de UNA variable continua, por ejemplo la longitud del sépalo (Sepal.Length)
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.
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ónLos 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"))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()geom_jitter() los outliers salen dos veces (como outlier del boxplot y como punto). Se evita con geom_boxplot(outlier.shape = NA)Para ordenar las cajas de un boxplot o las barras de un gráfico de barras, antes hay que saber 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
factor()factor() le decimos a R cuáles son las categorías (los levels) y en qué orden vanfactor() los pone en orden alfabéticoNA … ¡sin avisar!fct_fct_relevel(): a mano
fct_reorder() ordena según la mediana del sueldo de cada categoría. .desc = TRUE: de mayor a menorCambiar el orden de los levels no cambia los datos: cambia cómo se ordenan las tablas y, sobre todo, los gráficos
fct_recode(): cambiar el nombre ("nuevo" = "viejo")
fct_lump_n(estudios, n = 2) se queda con las 2 más frecuentes y junta las demás en "Other"iris |>
mutate(Species = fct_relevel(Species,
1 "virginica")) |>
ggplot(aes(Species, Sepal.Width)) +
geom_boxplot()fct_relevel() pone virginica la primera; el resto se queda como estaba
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()
fct_reorder()fct_reorder(Species, Sepal.Width) ordena las especies según la mediana de Sepal.Width. De mayor a menor: .desc = TRUEPara 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
Regla:
¿una fila por observación? → geom_bar()
¿Ya tienes calculado el valor de cada barra (un recuento, una media, un %…)? → geom_col()
geom_col()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()Se utilizan sobre todo para mostrar la evolución de una variable en el tiempo (series temporales)
#> # 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
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 agrupacolorMuestran la relación entre dos variables continuas. Los hemos usado todo el tema, pero tienen un problema cuando hay muchos datos: el overplotting
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())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 …
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
geom_point() usamos geom_point_interactive() y decidimos qué se ve al pasar el ratón (tooltip) y qué se resalta (data_id)Tarea: con los datos penguins (vienen con R desde la versión 4.5):
Haz un boxplot del peso (body_mass) para cada especie (species), con los puntos encima (geom_jitter()). ¡Que los outliers no salgan dos veces!
Haz un gráfico de barras con el número de pingüinos de cada isla (island), coloreando las barras según la especie
Algunos truquillos que se usan mucho
geom_text() también puede usar el stat "count": así pone el recuento de cada barra, sin calcularlo antesmarquee se pueden poner colores en los títulos: {#color texto}. Así el subtítulo hace de leyendaggtext, pero los colores había que escribirlos en HTML: <span style='color:#F8766D;'>setosa</span>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))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ísinset_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 variablep_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)theme(), con family. Con systemfonts podemos usar cualquiera de Google Fonts:ragg.ggsave() ya lo usa (si ragg está instalado)showtext o extrafont: siguen funcionando, pero ahora se recomienda systemfonts + ragg