Introducción

En este taller aprenderá el uso del paquete ggplot, el cual permite visualizar datos a través de gráficos. Este paquete esta inspirado en la “gramática de gráficos”, la cual propone que cualquier gráfico puede ser creado a partir de 3 componentes: Set de datos, Sistema de coordenadas y Geometrías (patrones que representan puntos de datos). Para hacer mas versatil su uso, se recomienda conocer el funcionamiento del paquete dplyr y el uso de tuberías (pipes). ggplot es uno de los paquetes contenidos en la librería tidyverse, por tanto, puede usarse en conjunto con los otros paquetes de tidyverse, tales como: dplyr.

Estructura base

ggplot(data = ---, mapping = aes(x = ---, y = ---)) + geom_----()

Objetivos

Conceptos básicos a desarrollar

En esta práctica se desarrollarán los siguientes conceptos:

Bibliotecas necesarias para el taller

library(tidyverse)
library(lubridate)

Inicio

Para comenzar, se empezará por el primer componente de la gramática de datos: Set de datos.

Set de datos

Al set de datos debe realizarle el debido proceso de limpieza y organización que se observo en el taller respectivo a este tema. Para este taller se comenzará con la base de datos limpia. Cargue la base de datos limpia sobre la cual se trabajará todo el taller. La base de datos puede encontrarla en https://github.com/TRACE-LAC/TRACE-LAC-data/blob/main/datos_limpios_covid.RDS?raw=true.

url_data <- "https://github.com/TRACE-LAC/TRACE-LAC-data/blob/main/datos_limpios_covid.RDS?raw=true"

covid <- readr::read_rds(url_data)

covid$estado <- replace(covid$estado, covid$estado == "leve", "Leve")
covid$recuperado <- replace(covid$recuperado, covid$recuperado == "fallecido", "Fallecido")

ggplot es una librería que permite guardar el conjunto de datos con cada gráfica que se produce por lo que grandes bases de datos requieren mayor tiempo de procesamiento. Por lo tanto, antes de emplear herramientas de visualización para una base de datos resulta conveniente obtener una muestra de los datos y realizar las pruebas de gráficos con esta. Cuando los gráficos han sido probados se puede ejecutar el código con la base de datos completa. Para crear la muestra puede hacer uso de sample_n del paquete dplyr.

#Obtenga una muestra de la base de datos de trabajo
covid_s <- covid %>% sample_n(size = 10000)

Una vez obtenida la muestra es necesario explorar sus datos para conocer su estado actual.

paste("Numero de filas =", nrow(covid_s))
## [1] "Numero de filas = 10000"
covid_s %>% str(vec.len = 3)
## tibble [10,000 × 22] (S3: tbl_df/tbl/data.frame)
##  $ fecha_reporte_web           : POSIXct[1:10000], format: "2021-06-07" "2022-06-23" ...
##  $ id_de_caso                  : num [1:10000] 3574838 6134916 2338933 4739675 ...
##  $ fecha_de_notificacion       : POSIXct[1:10000], format: "2021-05-26" "2022-06-08" ...
##  $ codigo_divipola_departamento: num [1:10000] 76 23 5 15 11 5 5 11 ...
##  $ nombre_departamento         : chr [1:10000] "VALLE" "CORDOBA" "ANTIOQUIA" ...
##  $ codigo_divipola_municipio   : num [1:10000] 76364 23001 5088 15001 ...
##  $ nombre_municipio            : chr [1:10000] "JAMUNDI" "MONTERIA" "BELLO" ...
##  $ edad                        : num [1:10000] 53 80 36 2 65 47 47 69 ...
##  $ unidad_de_medida_de_edad    : num [1:10000] 1 1 1 1 1 1 1 1 ...
##  $ sexo                        : chr [1:10000] "F" "M" "F" ...
##  $ tipo_de_contagio            : chr [1:10000] "Relacionado" "Comunitaria" "Relacionado" ...
##  $ ubicacion_del_caso          : chr [1:10000] "Casa" "Casa" "Casa" ...
##  $ estado                      : chr [1:10000] "Leve" "Leve" "Leve" ...
##  $ recuperado                  : chr [1:10000] "Recuperado" "Recuperado" "Recuperado" ...
##  $ fecha_de_inicio_de_sintomas : POSIXct[1:10000], format: "2021-05-16" "2022-06-05" ...
##  $ fecha_de_muerte             : Date[1:10000], format: NA NA ...
##  $ fecha_de_diagnostico        : POSIXct[1:10000], format: "2021-05-27" "2022-06-07" ...
##  $ fecha_recuperacion          : POSIXct[1:10000], format: "2021-06-08" "2022-06-30" ...
##  $ tipo_de_recuperacion        : chr [1:10000] "Tiempo" "Tiempo" "Tiempo" ...
##  $ pertenencia_etnica          : num [1:10000] 6 6 6 6 6 6 5 6 ...
##  $ nombre_del_grupo_etnico     : chr [1:10000] NA NA NA ...
##  $ fecha_nacimiento            : num [1:10000] 1969 1942 1986 2020 ...

Tras observar el estado actual se debe preguntar que datos desea graficar y para ello que variables necesita tener. En caso de que no tenga las variables pero si los datos para obtenerlas puede crearlas. Por ejemplo, puede obtener los días que tomo al individuo pasar de un estado a otro o días de retraso en la notificación desde el inicio de síntomas. A continuación, haciendo uso de la función mutate se crean dos nuevas variables: retraso_notificación y tiempo_recuperacion.

covid_s <- covid_s %>% mutate(
  retraso_notificacion = as.numeric((as.Date(covid_s$fecha_de_notificacion) - as.Date(covid_s$fecha_de_inicio_de_sintomas))),
  tiempo_recuperacion = as.numeric(as.Date(covid_s$fecha_recuperacion)-(as.Date(covid_s$fecha_de_inicio_de_sintomas))))

Una vez conforme con la exploración de los datos puede continuar con el segundo componente de la gramática de datos: Sistema de coordenadas.

Sistema de coordenadas

El sistema de coordenadas contiene el plano y las variables que se emplearán como ejes en la gráfica. El primer elemento es el sistema de coordenadas es el plano. Para crear un plano ejecute el siguiente comando.

\*Capa base
#Por fines educativos en este taller las variables reciben nombres genéricos pero significativos. No es obligatorio que tengan los nombres que les asignamos en el taller, pero si que sean claros y significativos.
coordenadas <- covid_s %>% ggplot(); coordenadas

¿Qué puede observar?

Ese espacio en blanco es el plano para el gráfico que se construirá. Exploré el objeto en el cual guardó el gráfico.

str(coordenadas, vec.len = 3)
## List of 9
##  $ data       : tibble [10,000 × 24] (S3: tbl_df/tbl/data.frame)
##   ..$ fecha_reporte_web           : POSIXct[1:10000], format: "2021-06-07" "2022-06-23" ...
##   ..$ id_de_caso                  : num [1:10000] 3574838 6134916 2338933 4739675 ...
##   ..$ fecha_de_notificacion       : POSIXct[1:10000], format: "2021-05-26" "2022-06-08" ...
##   ..$ codigo_divipola_departamento: num [1:10000] 76 23 5 15 11 5 5 11 ...
##   ..$ nombre_departamento         : chr [1:10000] "VALLE" "CORDOBA" "ANTIOQUIA" ...
##   ..$ codigo_divipola_municipio   : num [1:10000] 76364 23001 5088 15001 ...
##   ..$ nombre_municipio            : chr [1:10000] "JAMUNDI" "MONTERIA" "BELLO" ...
##   ..$ edad                        : num [1:10000] 53 80 36 2 65 47 47 69 ...
##   ..$ unidad_de_medida_de_edad    : num [1:10000] 1 1 1 1 1 1 1 1 ...
##   ..$ sexo                        : chr [1:10000] "F" "M" "F" ...
##   ..$ tipo_de_contagio            : chr [1:10000] "Relacionado" "Comunitaria" "Relacionado" ...
##   ..$ ubicacion_del_caso          : chr [1:10000] "Casa" "Casa" "Casa" ...
##   ..$ estado                      : chr [1:10000] "Leve" "Leve" "Leve" ...
##   ..$ recuperado                  : chr [1:10000] "Recuperado" "Recuperado" "Recuperado" ...
##   ..$ fecha_de_inicio_de_sintomas : POSIXct[1:10000], format: "2021-05-16" "2022-06-05" ...
##   ..$ fecha_de_muerte             : Date[1:10000], format: NA NA ...
##   ..$ fecha_de_diagnostico        : POSIXct[1:10000], format: "2021-05-27" "2022-06-07" ...
##   ..$ fecha_recuperacion          : POSIXct[1:10000], format: "2021-06-08" "2022-06-30" ...
##   ..$ tipo_de_recuperacion        : chr [1:10000] "Tiempo" "Tiempo" "Tiempo" ...
##   ..$ pertenencia_etnica          : num [1:10000] 6 6 6 6 6 6 5 6 ...
##   ..$ nombre_del_grupo_etnico     : chr [1:10000] NA NA NA ...
##   ..$ fecha_nacimiento            : num [1:10000] 1969 1942 1986 2020 ...
##   ..$ retraso_notificacion        : num [1:10000] 10 3 4 3 NA 0 1 10 ...
##   ..$ tiempo_recuperacion         : num [1:10000] 23 25 14 17 NA 43 14 30 ...
##  $ layers     : list()
##  $ scales     :Classes 'ScalesList', 'ggproto', 'gg' <ggproto object: Class ScalesList, gg>
##     add: function
##     clone: function
##     find: function
##     get_scales: function
##     has_scale: function
##     input: function
##     n: function
##     non_position_scales: function
##     scales: NULL
##     super:  <ggproto object: Class ScalesList, gg> 
##  $ mapping    : Named list()
##   ..- attr(*, "class")= chr "uneval"
##  $ theme      : list()
##  $ coordinates:Classes 'CoordCartesian', 'Coord', 'ggproto', 'gg' <ggproto object: Class CoordCartesian, Coord, gg>
##     aspect: function
##     backtransform_range: function
##     clip: on
##     default: TRUE
##     distance: function
##     expand: TRUE
##     is_free: function
##     is_linear: function
##     labels: function
##     limits: list
##     modify_scales: function
##     range: function
##     render_axis_h: function
##     render_axis_v: function
##     render_bg: function
##     render_fg: function
##     setup_data: function
##     setup_layout: function
##     setup_panel_guides: function
##     setup_panel_params: function
##     setup_params: function
##     train_panel_guides: function
##     transform: function
##     super:  <ggproto object: Class CoordCartesian, Coord, gg> 
##  $ facet      :Classes 'FacetNull', 'Facet', 'ggproto', 'gg' <ggproto object: Class FacetNull, Facet, gg>
##     compute_layout: function
##     draw_back: function
##     draw_front: function
##     draw_labels: function
##     draw_panels: function
##     finish_data: function
##     init_scales: function
##     map_data: function
##     params: list
##     setup_data: function
##     setup_params: function
##     shrink: TRUE
##     train_scales: function
##     vars: function
##     super:  <ggproto object: Class FacetNull, Facet, gg> 
##  $ plot_env   :<environment: 0x7ff8ed730178> 
##  $ labels     : Named list()
##  - attr(*, "class")= chr [1:2] "gg" "ggplot"

Como puede observar se ha creado una lista. Las lista pueden contener numerosos elementos de R sin importar su tipo o longitud. En esta lista se encuentran 9 elementos de los cuales la base de datos que se emplea en este taller es solo uno de ellos, de ahí la importancia de obtener una muestra de los datos.

Ahora que se tiene el plano se puede construir sobre el. Es hora de poner los ejes al plano. Los ejes pueden ser variables continuas o discretas, sin embargo, cada tipo de gráfica responde a una necesidad diferente. Dada la estructura de ggplot en capas puede hacer uso de elementos ggplot ya creados para continuar con la elaboración del gráfico.

Haga uso de los datos (data) almacenados en el objeto ggplot coordenadas y adicione una nueva característica.

coordenadas <- coordenadas$data %>% 
  ggplot(aes(x = tiempo_recuperacion, y = edad));coordenadas

## Este resultado también puede obtenerlo directamente empleando
# covid_s %>% 
#   ggplot(aes(x = tiempo_recuperacion, y = edad))

Ahora que el plano está creado puede adicionarse el última componente de la gramática de datos: Geometrías.

Geometrías

Las geometrías se refieren a los elementos gráficos que se contendrán en la gráfica. Las geometrías siempre empiezan por el nombre geom_. Algunos ejemplos:

Tabla traducida de: Little J. ggplot2 - quick and easy [Internet]. Rfun. 2022
Tipo de gráfica Nombre geom
Gráfica de barras: geom_bar() geom_col()
Histograma: geom_hist()
Gráfico de dispersión: geom_point() geom_jitter()
Gráfico de líneas: geom_line()
Gráfico de cajas y bigotes geom_boxplot()
Gráfico de densidad: geom_density() geom_violin()
Mapa de calor: geom_heatmap()
Creación de mapas: geom_sf()
Línea de regresión: geom_smooth() 1
Gráfico de punto: geom_point()

[1] Regresión local polinomial (LOESS) Ya se tiene el plano y los ejes. Ahora agréguele puntos.

geometrias_continuas <- coordenadas + geom_point(); geometrias_continuas
## Warning: Removed 1067 rows containing missing values (geom_point).

## Este resultado también puede obtenerlo directamente empleando sin #
# covid_s %>% 
#   ggplot(aes(x = tiempo_recuperacion, y = edad)) + 
#   geom_point()

Entre las ventajas de ggplot esta que se pueden sumar elementos a los ya existente. Por ejemplo, agréguele una línea de regresión.

geometrias_continuas <- geometrias_continuas + geom_smooth(); geometrias_continuas
## `geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
## Warning: Removed 1067 rows containing non-finite values (stat_smooth).
## Warning: Removed 1067 rows containing missing values (geom_point).

## Este resultado también puede obtenerlo directamente empleando sin #
# covid_s %>% 
#   ggplot(aes(x = edad, y = tiempo_recuperacion)) + 
#   geom_point() + 
#   geom_smooth()

Como se menciono antes es posible usar funciones de dplyr junto a ggplot. Para obtener una visualización más clara puede filtrar por el tiempo de recuperación.

grafica_base <-
covid_s %>% 
  filter(tiempo_recuperacion >= 50, unidad_de_medida_de_edad == 1) %>% 
   ggplot(aes(x = edad, y = tiempo_recuperacion)) + 
   geom_point() + 
   geom_smooth(); grafica_base
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

ggplot permite dar otras características a las gráficas a partir de variables. Entre estas se puede encontrar característica como color de borde, color de relleno, forma o dividir la gráfica.

grafica_base + facet_wrap(~sexo)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'


## Este resultado también puede obtenerlo directamente empleando sin #
# covid_s %>% 
#  filter(tiempo_recuperacion >= 50, unidad_de_medida_de_edad == 1) %>% 
#   ggplot(aes(x = edad, y = tiempo_recuperacion)) + 
#   geom_point() + 
#   geom_smooth() + 
#   facet_wrap(~sexo)

ggplot permite añadir múltiple geometrías usando el mismo set de datos, y cada geometría puede presentar distintos atributos de visualización.

Es importante diferencias dos tipos de atributos en ggplot: globales y locales

  • Los atributos globales son aquellos aplicados a todas las geometrías del gráfico a través de la función ggplot.

  • Los atributos locales son los aplicados exclusivamente a una geometría.

covid_s %>%
  filter(tiempo_recuperacion >= 50, unidad_de_medida_de_edad == 1) %>%
  ggplot(aes(x = edad, y = tiempo_recuperacion, colour = "red")) +
  geom_point() +
  geom_smooth() +
  facet_wrap(~sexo)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

  
## Este resultado también puede obtenerlo con este código
# grafica_base +
#   (aes(colour = "red")) +
#   facet_wrap(~sexo)

Puede observar que tanto la geometría de puntos como la de la línea de regresión tomaron el color rojo.

Además, puede asignar color por variable. Por ejemplo,

covid_s %>% 
  filter(unidad_de_medida_de_edad == 1) %>%
  ggplot(aes(x = edad, y = tiempo_recuperacion, colour = sexo)) + 
  geom_point() +
  facet_wrap(~sexo)
## Warning: Removed 1066 rows containing missing values (geom_point).

Si bien hay diferentes colores, esta es un atributo global, es decir, que aplicará a todas las geometrías. Si quiere dar el atributo a una geometría específica tiene que poner el atributo dentro de la geometría. Por ejemplo,

covid_s %>% 
  filter(tiempo_recuperacion >= 50, unidad_de_medida_de_edad == 1) %>%
  ggplot(aes(x = edad, y = tiempo_recuperacion)) + 
  geom_point(colour = "red") + 
  geom_smooth(colour = "blue") +
  facet_wrap(~sexo)
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

Tipos y atributos basicos de visualizacion (Aesthetics)

Gráficos con una sola variable

Los gráficos pueden hacerse con una o más variables. A continuación se muestran algunos ejemplos.

Una variable continua

Haga un gráfico de densidad con la edad. ¿Con que otra variable podría hacerlo?

covid_s %>% filter(unidad_de_medida_de_edad == 1) %>% 
  ggplot(aes(edad)) +
  geom_density()

Ahora realice un histograma con la edad.

covid_s %>% filter(unidad_de_medida_de_edad == 1) %>% 
  ggplot(aes(edad)) +
  geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

El histograma toma una variable continua en el eje x, le asigna divisiones y crea rangos del mismo ancho automáticamente. Si quiere asignar el ancho puede usar el argumento bin dentro de histogram.

covid_s %>% filter(unidad_de_medida_de_edad == 1) %>% 
  ggplot(aes(edad)) +
  geom_histogram(binwidth = 2)

O si por lo contrario quiere escoger el número de divisiones puede usar el argumento bins dentro de histogram.

covid_s %>% filter(unidad_de_medida_de_edad == 1) %>% 
  ggplot(aes(edad)) +
  geom_histogram(bins = 5)

Apesar de que histogram haga discreta una variable continua no puede ser usar para variables discretas, en ese sentido puede usar la geomatría geom_bar.

covid_s %>% 
  ggplot() + 
  geom_bar(aes(sexo))

O se puede asignar divisiones a una variable continua. Por ejemplo,

covid_s %>% 
  mutate(rangos_edad = cut(edad, breaks = c(0, 30, 60, 90, 120))) %>%
  ggplot() + geom_bar(aes(rangos_edad))

Es posible dar nombres a estos cortes, dentro de la función cut, emplee el argumento ``

covid_s %>% 
  mutate(rangos_edad = 
           cut(edad, breaks = c(0, 30, 60, 90, 120), 
               labels = c("0 a 30 años", 
                          "30 a 60 años", 
                          "60 a 90 años", 
                          "90 a 120 años"))) %>%
  ggplot() + geom_bar(aes(rangos_edad))

Además, es posible cambiar los nombres de los ejes con xlab para el eje x y con ylab para el eje y.

covid_s %>% 
  mutate(rangos_edad = 
           cut(edad, breaks = c(0, 30, 60, 90, 120), 
               labels = c("0 a 30 años", 
                          "30 a 60 años", 
                          "60 a 90 años", 
                          "90 a 120 años"))) %>%
  ggplot() + 
  geom_bar(aes(rangos_edad)) +
  xlab("Rangos de edad") +
  ylab("Conteo")

Para agregar más características puede agregar la capa labs. En esta puede agregar los argumentos: título title, subtítulo subtitle, leyenda caption.

covid_s %>% 
  mutate(rangos_edad = 
           cut(edad, breaks = c(0, 30, 60, 90, 120), 
               labels = c("0 a 30 años", 
                          "30 a 60 años", 
                          "60 a 90 años", 
                          "90 a 120 años"))) %>%
  ggplot() + 
  geom_bar(aes(rangos_edad)) +
  xlab("Rangos de edad") +
  ylab("Conteo") +
  labs(title = "Gráfico de barras", 
       subtitle = "Rangos de edad",
       caption = "Tomado de: Taller ggplot") 

Ejercicio

Con la variable continua edad realice una gráfica de barras, dividala por grupo etario, agreguele un título, dividala por sexo y asignele color por estado.

Para la división de grupos etarios podría usar “Primera infancia” (0 a 5),“Infancia” (6 a 11),“Adolescencia” (12 a 18),“Juventud” (19 a 26),“Adultez” (27 a 59),“Adulto mayor” (60 a 71),“Viejo Viejo” (72 en adelante)


Además, pueden asignarse diferentes atributos a las geometrías.

covid_s %>% 
  filter(tiempo_recuperacion >= 50, unidad_de_medida_de_edad == 1) %>%
  ggplot(aes(x = edad, y = tiempo_recuperacion)) + 
  geom_point(color = "red", shape = 3) 

Pruebe cambiar el shape ¿Qué resultados obtiene?

covid_s %>% 
  filter(tiempo_recuperacion >= 50, unidad_de_medida_de_edad == 1) %>%
  ggplot(aes(x = edad, y = tiempo_recuperacion)) + 
  geom_line(color = "blue", linetype = 1) +
  geom_abline(intercept = 200, slope = 0, color = "red")  

Pruebe cambiar el linetype ¿Qué resultados obtiene?

Sobre este documento

Contribuciones

  • José M. Velasco-España: Versión inicial
  • Zulma Cucunubá: Correcciones

Asuntos legales

Licencia: CC-BY Copyright: José M. Velasco-España, 2022


  1. 1↩︎