Mapas bivariados

Gabriel Massaine Moulatlet

Instituto de Ecología, A.C.

Mapas bivariados

Paquetes

Vamos a utilizar los siguientes paquetes en R

  • bivariate
  • ggplot2

Biscale

  • Paquete para producir mapas bivariados (i.e. dos variables en el mismo layout)
    • Sirve para producir leyendas bivariadas
    • Herramientas para classificación de datos en categorías usando diferentes técnicas
    • Documentación

Según la wikipedia..

  • Mapas bivariados también son conocidos por Mapa coropleto o Mapa de coropletas

Es un tipo de mapa temático en el que las áreas se sombrean de distintos colores, frecuentemente de la misma gama cromática, que representan distintos valores de una variable estadística característica.

Dos o más variables…

  • Mapas bivariados son útiles para graficar dos variables
  • Ajuste de colores, transparencias y formas

Son bastante comunes para reportar resultados de elecciones

También usados para reportar indicadores socio-económicos

{fig-align=“center fig-size=”82%““}

Hay otros ejemplos: colores y marcas

Hay otros ejemplos: colores y area

Leyendas triangulares

Formatos complejos

Sabatini et al. 2022

Mapas RGB

Leyendas rectangulares con varias categorias

Peixoto et al. 2017

Pero lo más importante es que la información esté clara

  • ¿Cuál de los dos mapas transmite mejor la información?

Producir mapas bivariados

Teoría:

  • La idea central es buscar una manera de como combinar estas dos variables
  • Escalas diferentes, número diferente de categorias etc…
  • Mapas bivariados constan de dos pasos:
    1. Categorización de las variables según alguna estadística
    2. Preparación de una leyenda con base en una “paleta” de colores

1. Categorización de variables

Pasos:

  • Clasificar los datos en conteos o proporciones
  • las funciones cut() y summary() de R base pueden ser útiles
  • vamos usar la base de datos iris
summary(iris$Sepal.Length)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  4.300   5.100   5.800   5.843   6.400   7.900 

library(janitor)

# Categorizar de acuerdo a los quantiles
ci = cut(iris$Sepal.Length,breaks = c(4.3,5.1,5.8,6.4, max(iris$Sepal.Length)))

# Explorar los resultados
tabyl(ci)
        ci  n     percent valid_percent
 (4.3,5.1] 40 0.266666667     0.2684564
 (5.1,5.8] 39 0.260000000     0.2617450
 (5.8,6.4] 35 0.233333333     0.2348993
 (6.4,7.9] 35 0.233333333     0.2348993
      <NA>  1 0.006666667            NA

la función classIntervals()

  • Permite categorizar los datos usando varios tipos de categorización
  • quantile, jenkins, equal para mencionar algunas
  • hay que definir el numero de clases (parámetro n)
library(classInt)

classInt::classIntervals(iris$Sepal.Length,style="quantile",n=4)
style: quantile
  one of 5,984 possible partitions of this variable into 4 classes
[4.3,5.1) [5.1,5.8) [5.8,6.4) [6.4,7.9] 
       32        41        35        42 

  • Luego de categorizar el vector de interés, se puede cortar con la función cut()
  • Tambien se puede generar un vector con las categorías y juntarlo a los datos originales usando la función findCols()
breaks = classInt::classIntervals(iris$Sepal.Length,style="quantile",n=4)$brks

cc = cut(iris$Sepal.Length, breaks = breaks)
tabyl(cc)
        cc  n     percent valid_percent
 (4.3,5.1] 40 0.266666667     0.2684564
 (5.1,5.8] 39 0.260000000     0.2617450
 (5.8,6.4] 35 0.233333333     0.2348993
 (6.4,7.9] 35 0.233333333     0.2348993
      <NA>  1 0.006666667            NA

la función findCols()

# Generar un vector que se pueda juntar a la tabla de datos originales

fc = findCols(classInt::classIntervals(iris$Sepal.Length,style="quantile",n=4))
head(fc)
[1] 2 1 1 1 1 2

usando el paquete biscale

  • Se utliza la función bi_class() para generar las categorías
  • Una de las ventajas de usar la función bi_class() es que hace la categorización de las dos variables elejidas de una sola vez
library(biscale)

data <- bi_class(iris, x = Sepal.Length, y = Petal.Length, style = "quantile", dim = 3)
head(data$bi_class)
[1] "1-1" "1-1" "1-1" "1-1" "1-1" "1-1"

2. Preparación de leyenda bivariada

Preparación de una leyenda

La función bi_legend()

  • Para ver las paletas disponibles aquí
bi_legend(pal = "GrPink",
                    dim = 3,
                    xlab = "Sepal.Length",
                    ylab = "Petal.Lenght",
                    size = 12)

El mapa bivariado

  1. Vamos a ver el ejemplo del vignette
  • Son datos sobre el porcentaje de “brancos” y la ganancia en los EUA.
  • Vamos usar las columnas pctWhite y medInc para hacer el mapa.
  • Vamos usar 3 dimensiones y categorizar los datos usando quantiles

Manos a la obra!

  • El mapa se construye usando ggplot
  • Determinamos el geom como geom_sf y como argumento estético fill = bi_class
  • El bi_class debe ser la categorización que hemos visto anteriormente con usando la justamente a función bi_class()
  • Una de las capas del ggplot debe ser bi_scale_fill, donde van a poner el argumento pal - que es la paleta de colores y dim - que es el numero de categorías utilizadas para categorizar los datos.

library(ggplot2)
library(sf)

data <- bi_class(stl_race_income, x = pctWhite, y = medInc, style = "quantile", dim = 3)

map <- ggplot() +
  geom_sf(data = data, mapping = aes(fill = bi_class), color = "white", size = 0.1, show.legend = FALSE) +
  bi_scale_fill(pal = "GrPink", dim = 3)

  • Después de preparar el mapa, hay que preparar la leyenda
legend <- bi_legend(pal = "GrPink",
                    dim = 3,
                    xlab = "Higher % White ",
                    ylab = "Higher Income ",
                    size = 8)
  • Por fin, ponerlos lado a lado usando el paquete patchwork
library(patchwork)

map + legend

Se juede jugar con el layout final usando la función inset

p1 + inset_element(p2, 0.6, 0.6, 1, 1) # left, top, right, bottom

Como hacer mapas bivariados sin usar el paquete biscale

  • El tutorial de Len Kiefer
  • Usar el paquete classInt para categorizar los datos
  • Usar el esquema de colores de la leyenda para preparar el mapa

  • La leyenda se hace con la función expand_grid() del paquete tidyr
library(tidyr)

d=expand.grid(x=1:3,y=1:3)
d
  x y
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2
6 3 2
7 1 3
8 2 3
9 3 3

library(ggplot2)
ggplot(d, aes(x,y))+
  geom_tile(aes(alpha=x+y,fill=atan(y/x)))+
  scale_fill_viridis_c()+
  theme(legend.position="none",
        axis.text.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks = element_blank(),
        panel.grid.minor = element_blank(),
        panel.grid.major = element_blank())+
  coord_equal()

  • Lo importante aqui es usar el geom geom_tile
  • Permite usar varios colores
  • Vamos jugar con los valores de alpha (transparencia) y fill

ggplot(d, aes(x,y))+
  geom_tile(aes(fill=atan(y/x)))+
  scale_fill_viridis_c()+
  theme(legend.position="none",
        axis.text.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks = element_blank(),
        panel.grid.minor = element_blank(),
        panel.grid.major = element_blank())+
  coord_equal()

ggplot(d, aes(x,y))+
  geom_tile(aes(fill=atan(y/x),alpha=x+y))+
  scale_fill_viridis_c()+
  theme(legend.position="none",
        axis.text.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks = element_blank(),
        panel.grid.minor = element_blank(),
        panel.grid.major = element_blank())+
  coord_equal()

Categorizar los datos

  • vamos a usar las funciones classInt() y findCols()
 x=classInt::classIntervals(stl_race_income$pctWhite,4,style = "quantile")
 y=classInt::classIntervals(stl_race_income$medInc,4,style = "quantile")
 
 x
style: quantile
  one of 182,104 possible partitions of this variable into 4 classes
       [0,3.140384) [3.140384,37.30553) [37.30553,69.86624) [69.86624,96.73367] 
                 27                  26                  26                  27 

  • Agregar los valores calculados a la tabla stl_race_income
stl_race_income$x = classInt::findCols(x)
stl_race_income$y = classInt::findCols(y)

Crar un objeto para el alpha y otro para el fill

stl_race_income$alpha = as.character(stl_race_income$x + stl_race_income$y)
stl_race_income$color = as.character(atan(stl_race_income$y/stl_race_income$x))

Graficar el mapa

map = ggplot()+
  geom_sf(data = stl_race_income,aes(fill=color,alpha=alpha),shape=15, size=11,show.legend = FALSE)+
  scale_fill_viridis_d()+
  theme_void()

map

Graficar la leyenda

leg = ggplot(d, aes(x,y))+
  geom_tile(aes(fill=atan(y/x),alpha=x+y))+
  scale_fill_viridis_c()+
  theme(legend.position="none",
        axis.text.y = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks = element_blank(),
        panel.grid.minor = element_blank(),
        panel.grid.major = element_blank())+
  coord_equal()

leg

Juntar los dos

Se parecen?