🏠↩︎ De vuelta a la página principal del curso
🚀 Objetivo de la unidad
Que el estudiante conozca los distintos tipos de visualización de datos y reconozca sus casos de uso.
🇷 ⬇ Descargar projecto de R de la práctica 🇷 ⬇ Descargar projecto de R de la práctica (Pirámide poblacional)
# install.packages("ggplot2")
# install.packages("svglite") # Para expotar como svg
library(data.table)
library(ggplot2)
Para la práctica utilizaremos los siguientes conjuntos de datos:
mw <- data.table(ggplot2::midwest)
* El archivo Personas09.csv contiene los microdatos a nivel
persona de la Ciudad de México del Censo de
Población y Vivienda 2020 del INEGI en formato csv. Este archivo
está disponible para su descarga aquí
(Archivos para descarga > Muestra (cuestionario ampliado) > Bases
de datos > Ciudad de México > CSV ⬇).
p_raw <- fread("../data/Censo2020_CA_cdmx_csv/Personas09.CSV")
Para crear una visualización, debemos:
ggplot()
, que crea un lienzo en
blanco.aes()
cómo deseamos asignar variables a
atributos estéticos.geom_...()
.Cada capa de la visualización se apila con el opeerador
+
.
Creamos lienzo en blanco
ggplot()
💡 Recuerde que nuestras visualizaciones se iran desplegando en la ventana de Plots o, en el caso de visualizaciones interactivas, en la ventana de Viewer.
La primera y más importante capa en la gramática de gráficos son los
datos. El objeto que contiene los datos con los que construiremos
nuestra visualización se pasa como parámetro de la función
ggplot()
.
ggplot(data = mw)
El siguiente paso es definir la variable que deseamos usar para cada atributo estético de la visualización.
En la capa de la estética utilizamos la función aes()
para asignar variables de datos a atributos gráficos utilizados por el
sistema de dibujo subyacente, como posición 2D, color, tipo de línea,
tamaño, figura de los puntos, entre otros.
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty, color = state)
Después de definir los atributos gráficos que deseamos utilizar,
debemos especificar uno o varios objetos geométricos para indicar cómo
deben dibujarse los puntos de datos. Los objetos geométricos (o
geoms
) pueden ser puntos, líneas, barras, polígonos, áreas,
histogramas, rectas con el mejor ajuste, entre otros. Cuál utilizar dependerá
del tipo y total de variables de datos que querramos representar y qué
mensaje querramos comunicar con la visualización.
💡 El sitio The R Graph Gallery contiene decenas de ejemplos con código en R de visualizaciones de datos. “Imitation is not just the sincerest form of flattery - it’s the sincerest form of learning.”
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty) +
geom_point()
Los objetos geométricos tienen sus propios parámetros para
ajustar sus atributos gráficos.
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty) +
geom_point(color = "purple", alpha = 0.50, size = 3)
Es posible agrupar cuantos objetos geométricos querramos.
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty) +
geom_point() +
geom_smooth()
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Algunos geoms
utilizan transformaciones
estadísticas que aplican cálculos y agregaciones de forma implícita a
los datos antes de graficarlos.
mw[, above_5_percblack := ifelse(test = percblack >= 5, yes = "Sí", no = "No")]
ggplot(data = mw) +
aes(x = state, fill = above_5_percblack) +
geom_bar(stat = "count")
ggplot(data = mw) +
aes(x = poptotal) +
geom_histogram(bins = 100)
ggplot(data = mw) +
aes(x = percpovertyknown, y = state) +
geom_boxplot()
💡 Sobre las visualizaciones de caja en ggplot2:
Igualmente, es posible especificar objetos primitivos, es decir,
objetos geométricos independientes de los datos.
mu <- mean(mw[, percpovertyknown])
ggplot(data = mw) +
aes(x = percpovertyknown, y = state) +
geom_boxplot() +
geom_vline(xintercept = mu, linetype = "dotted")
Cada vez que asignamos variables de datos a atributos gráficos (con
la función aes()
), ggplot2 usa una escala particular para
determinar el rango de valores al que se deben asignar los datos.
Por ejemplo, cuando especificamos:
ggplot(data = mw) + aes(x = percollege, y = percbelowpoverty) + geom_point()
,
ggplot2 agrega automáticamente una escala predeterminada para cada
asignación.
Cada escala se puede representar mediante una función con el
siguiente nombre: scale_
, seguido del nombre del atributo
estética, seguido de un _
y seguido el tipo de dato de la
variable de la escala.
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty) +
geom_point() +
scale_x_continuous() +
scale_y_continuous() +
scale_colour_discrete()
Si bien las escalas predeterminadas funcionan bien, es posible
agregar explícitamente diferentes escalas para reemplazar las
predeterminadas.
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty) +
geom_point() +
scale_x_reverse() +
scale_y_reverse()
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty, color = state) +
geom_point() +
scale_color_manual(values = c("#993300", "#ff3300", "#ff6600", "#ff9999", "#ffccff")) # Colores definidos con su código hexadecimal
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty, color = state) +
geom_point() +
scale_color_brewer(palette = "Blues") # https://rdrr.io/cran/RColorBrewer/man/ColorBrewer.html
Las facetas (o facets
) nos permiten agrupar datos por
variables y luego graficar cada grupo individualmente un panel
independiente, pero en la misma visualización (imagen).
ggplot(data = mw) +
aes(x = percollege, y = percbelowpoverty) +
geom_point() +
facet_grid(facets = "state~above_5_percblack")
El sistema de coordenadas define cómo se asignan los puntos de datos a ubicaciones gráficos 2D en el plano. Elegir el sistema de coordenadas correcto puede mejorar considerablemente la legibilidad de las visualizaciones de datos.
Al igual que con las escalas, los sistemas de coordenadas se
especifican con funciones que comienzan con coord_
y se
agregan como una capa.
Existe una serie de diferentes sistemas de coordenadas, que incluye:
coord_cartesian()
es el sistema de coordenadas
cartesianas predeterminado, donde especifica los valores x y y. Este
sistema de coordenadas es el predeterminado, por lo que no es necesario
agregarlo en cada ocasión como capa. No obstante, especificar sus
parámetros permite establecer límites en los ejes, y por tanto, acercar
o alejar la visualización.coord_flip()
es un sistema de coordenadas cartesianas
con el eje x y el eje y “volteados”.coord_polar()
es un sistema de coordenadas
polares.ggplot(data = mw) +
aes(x = state, fill = above_5_percblack) +
geom_bar(stat = "count") +
coord_flip()
Otra excelente manera de mejorar la presentación de sus visualizaciones de datos es elegir un tema no predeterminado para que los elementos gráficos destaquen, haciéndolos más bonitos, vibrantes y congruentes con el tipo variables de datos que querramos representar y qué mensaje querramos comunicar con la visualización. ggplot2 incluye varios temas entre los que podemos elegir.
ggplot(data = mw) +
aes(x = state, fill = above_5_percblack) +
geom_bar(stat = "count") +
coord_flip() +
theme_classic()
Los títulos, etiquetas y anotaciones textuales (en el lienzo, los ejes, los objetos geométricos y la leyenda) son una parte importante para hacer que una visualización sea comprensible y que comunique información de manera eficiente. Aunque no es una parte explícita de la gramática de gráficos, se consideraría una variante de objeto geométrico.
ggplot(data = mw) +
aes(y = state, fill = above_5_percblack) +
geom_bar(stat = "count") +
theme_classic() +
labs(x = "Total de condados",
y = "Estado",
title = "Illinois es el estado del medio oeste de Estados Unidos de América\ncon mayor número de condados y condados en los que 5% de su población\nes afrodescendiente",
subtitle = "Total de condados el medio oeste de Estados Unidos de América por estado",
fill = "Condados en los que\n5% de su población es\nafrodescendiente",
caption = "Fuente de datos: Censo de Estados Unidos de América del 2000")
Una vez que la visualización esté completa, este se puede exportar
desde la ventana de Plots de forma manual o con la función
ggsave()
de forma programática después de asignar la
visualización a un objeto.
v <- ggplot(data = mw) +
aes(y = state, fill = above_5_percblack) +
geom_bar(stat = "count") +
theme_classic() +
labs(x = "Total de condados",
y = "Estado",
title = "Illinois es el estado del medio oeste de Estados Unidos de América\ncon mayor número de condados y condados en los que 5% de su población\nes afrodescendiente",
subtitle = "Total de condados el medio oeste de Estados Unidos de América por estado",
fill = "Condados en los que\n5% de su población es\nafrodescendiente",
caption = "Fuente de datos: Censo de Estados Unidos de América del 2000")
ggsave("./viz/myviz.svg", v, width = 10, height = 5)
A pesar de que ggplot2 es una herramienta de visualización de datos robusta, no se tiene un control absoluto de todos los elementos gráficos. Por ello, es recomendable importar la visualización como svg, un formato de archivo vectorial, que después es posible cargar en programas de edición de imágenes digitales alternas para terminar de ajustar los mínimos detalles.
💡 Gimp e Inkscape son programas de edición de imágenes digitales gratuitos en los que resulta muy cómodo el ajuste de visualizaciones de datos.
En esta sección de la práctica, construiremos una pirámide poblacional de la Ciudad de México en el 2020.
Creamos nueva variable categórica de tipo factor utilizando la variable “SEXO”.
p_raw[, sexo_cat := factor(SEXO, levels = c(1, 3), labels = c("Hombres", "Mujeres"))]
Filtramos fuera las observaciones en las que la variable “EDAD”
contenga el valor “999” o un NA y seleccionamos únicamente las variables
necesarias para nuestra visualización: “ID_PERSONA”, “FACTOR”,
“sexo_cat” y “EDAD”.
p <- p_raw[EDAD != 999 & !is.na(EDAD), .(ID_PERSONA, FACTOR, sexo_cat, EDAD)]
Graficamos la distribución de edad en la población de la Ciudad
de México por sexo.
ggplot(data = p) +
aes(x = EDAD, weight = FACTOR, fill = sexo_cat) +
geom_histogram(binwipersonash = 100, position = "identity", alpha = 0.5)
## Warning: Ignoring unknown parameters: binwipersonash
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Utilizamos coord_flip()
para “voltear” el eje x y
el eje y del sistema de coordenadas cartesianas de la visualización.
ggplot(data = p) +
aes(x = EDAD, weight = FACTOR, fill = sexo_cat) +
geom_histogram(binwipersonash = 100, position = "identity", alpha = 0.5) +
coord_flip()
## Warning: Ignoring unknown parameters: binwipersonash
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Creamos nueva variable categórica de tipo factor con grupos
quinquenales de edad utilizando la variable “EDAD” con ayuda de la
función cut()
. De forma predeterminada, las etiquetas de
los factores resultantes se construyen utilizando la notación de
intervalo (a,b], en donde a no es un valor incluído en el intervalo y b
es un valor incluído en el intervalo.
edades_quinquenales <- cut(x = p$EDAD,
breaks = seq(0, 110, by = 5),
include.lowest = TRUE,
right = TRUE)
# unique(edades_quinquenales)
p[, edad_quinquenal := edades_quinquenales]
Creamos un nuevo data table con la población total por sexo y
grupo quinquenal de edad.
p_grouped <- p[, .(pob = sum(FACTOR)), by = .(sexo_cat, edad_quinquenal)]
Graficamos nevamente la distribución de edad en la población de
la Ciudad de México por sexo pero utilizando el nuevo data table
agrupado.
ggplot(data = p_grouped) +
aes(x = edad_quinquenal, y = pob, fill = sexo_cat) +
geom_bar(stat = "Identity", position = "identity", alpha = 0.5) +
coord_flip()
Para que la población de hombres y la población de mujeres se
visualicen “reflejadas”, debemos transformar la variable “pob” a
negativa para uno de los dos sexos.
p_grouped[, pob := ifelse(sexo_cat == "Hombres", yes = -pob, no = pob)]
ggplot(data = p_grouped) +
aes(x = edad_quinquenal, y = pob, fill = sexo_cat) +
geom_bar(stat = "Identity") +
coord_flip()
En la última visualización, podemos observar que las etiquetas
del eje x, es decir, el total de la población, está en notación
científica. R decide utilizar esta notación dada la longitud de las
etiquetas. No obstante, la notación científica no es un formato que
facilite la lectura. Para ello, personalizaremos los límites, los saltos
y las etiquetas de la escala del eje y con
scale_y_continuous()
.
ggplot(data = p_grouped) +
aes(x = edad_quinquenal, y = pob, fill = sexo_cat) +
geom_bar(stat = "Identity") +
scale_y_continuous(limits = c(-400000, 400000),
breaks = seq(-400000, 400000, by = 100000),
labels = c(400, 300, 200, 100, 0, 100, 200, 300, 400)) +
coord_flip()
Para ajustar los colores de las barras, utilizamos
scale_fill_manual()
.
ggplot(data = p_grouped) +
aes(x = edad_quinquenal, y = pob, fill = sexo_cat) +
geom_bar(stat = "Identity") +
scale_fill_manual(values = c("#a35994ff", "#009482ff")) +
scale_y_continuous(limits = c(-400000, 400000),
breaks = seq(-400000, 400000, by = 100000),
labels = c(400, 300, 200, 100, 0, 100, 200, 300, 400)) +
coord_flip()
“Limpiamos el desorden” quitando elementos que no agregan valor
informativo y bajamos la leyenda abajo para facilitar la asociación de
los colores a cada sexo respectivamente.
ggplot(data = p_grouped) +
aes(x = edad_quinquenal, y = pob, fill = sexo_cat) +
geom_bar(stat = "Identity") +
scale_fill_manual(values = c("#a35994ff", "#009482ff")) +
scale_y_continuous(limits = c(-400000, 400000),
breaks = seq(-400000, 400000, by = 100000),
labels = c(400, 300, 200, 100, 0, 100, 200, 300, 400)) +
coord_flip() +
theme_minimal() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.position = "bottom")
Agregamos y modificamos los textos adecuados.
ggplot(data = p_grouped) +
aes(x = edad_quinquenal, y = pob, fill = sexo_cat) +
geom_bar(stat = "Identity") +
scale_fill_manual(values = c("#a35994ff", "#009482ff")) +
scale_y_continuous(limits = c(-400000, 400000),
breaks = seq(-400000, 400000, by = 100000),
labels = c(400, 300, 200, 100, 0, 100, 200, 300, 400)) +
coord_flip() +
labs(title = "Pirámide poblacional de la Ciudad de México",
subtitle = "Población total (en miles de personas) por edad quinquenal",
caption = "Censo de Población y Vivienda 2020 del INEGI\nElaborado por el CEDUA de El Colegio de México") +
theme_minimal() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
legend.position = "bottom",
legend.title = element_blank())
Finalmente, podemos crear una nueva variable que utilicemos como
etiquetas en las barras y facilitar la lectura del total de la población
por grupo quinquenal.
p_grouped[, pob_label := ifelse(sexo_cat == "Hombres",
yes = paste0(round(-pob/1000), " "),
no = paste0(" ", round(pob/1000)))]
ggplot(data = p_grouped) +
aes(x = edad_quinquenal, y = pob, fill = sexo_cat, label = pob_label) +
geom_bar(stat = "Identity") +
scale_fill_manual(values = c("#a35994ff", "#009482ff")) +
scale_y_continuous(limits = c(-400000, 400000),
breaks = seq(-400000, 400000, by = 100000),
labels = c(400, 300, 200, 100, 0, 100, 200, 300, 400)) +
geom_text(size = 3) +
coord_flip() +
labs(title = "Pirámide poblacional de la Ciudad de México",
subtitle = "Población total (en miles de personas) por edad quinquenal",
caption = "Censo de Población y Vivienda 2020 del INEGI\nElaborado por el CEDUA de El Colegio de México") +
theme_minimal() +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
legend.position = "bottom",
legend.title = element_blank())