Visualización de Mapas con R

Visualización de Mapas con R

Introducción

La visualización de datos pretende representar información en formato gráfico para comunicar de manera eficiente grandes volúmenes de datos, que de otra forma serían difíciles de interpretar. Una de las formas más adecuadas de mostrar información sobre una ciudad es usando la visualización sobre mapas. Los SIG (Sistemas de Información Geográfica) se han concebido para esto. Pero más allá de un SIG, existen otras herramientas que permiten mapificar esta información. A través del Blog de Dominic Roye hemos descubierto una manera sencilla de visualizar el crecimiento urbano de cualquier ciudad de España. Además propone hacerlo de una forma algo artísitca, lo que nos aporta ese conocimeinto que buscamos sobre el crecimiento urbanos y una representación colorida de nuestra ciudad. Los datos usados de origen son los de Catastro.

Pero antes de mostrar el caso práctico, no está de más recordar la pirámide de Conocimiento (o DIKW, por las siglas en ingleś).

Jerarquía de Conocimiento

La Pirámide del Conocimiento o D-I-K-W, viene a establecer una jerarquía entre datos, información, conocimiento y sabiduría, colocando los datos en su parte más baja y la sabiduría en la más alta, o de más valor.

Un dato es una representación simbólica, característica o atributo de algo; no tiene valor en sí mismo por estar descontextualizado, pero es susceptible de ser procesado adecuadamente para obtener información. Los datos son una colección de hechos en forma desorganizada, como números o caracteres.

La información, es ese conjunto organizado y procesado de datos que adquieren dun sentido. Se trata de datos que se han “limpiado” de errores y se han procesado adicionalmente de manera que sea más fácil de medir, visualizar y analizar para un propósito específico. Queremos contestar a ‘quien’, que’, ‘cuando’, ‘donde’, etc.,

El uso de la información para la consecución de determinados objetivos, su aplicación a la solución de problemas y a la toma de decisiones, es lo que conforma el conocimiento. ‘Cómo’ es la información, derivada de los datos recopilados, relevante para nuestros objetivos? “¿Cómo” se conectan las piezas de esta información con otras piezas para agregar más significado y valor? Y, quizás lo más importante, “¿cómo” podemos aplicar la información para lograr nuestro objetivo?

En lo alto de la pirámide nos encontramos con la sabiduría. U Incluye elementos tales como saber qué es lo apropiado, discernir cuándo los objetivos son alcanzados de manera suficiente o identificar y aceptar limitaciones inevitables.

La sabiduría es la cima de la jerarquía y para llegar allí, debemos responder preguntas como “por qué hacer algo” y “qué es lo mejor”. En otras palabras, la sabiduría es conocimiento aplicado en acción.

También podemos decir que, si los datos y la información son como una mirada al pasado, el conocimiento y la sabiduría están asociados con lo que hacemos ahora y lo que queremos lograr en el futuro.

El pequeño ejercicio práctico que presentamos intenta escalar en la pirámide, a partir de datos que estructuramos y organizamos para generar información y a partir de ahí, visualizarlos para aportar conocimiento sobre cómo ha sido el crecimiento urbano de la ciudad de Valls.

Entorno de trabajo

Para desarrollar el proyecto hemos utilizado un entorno Debian 10, con todo lo necesario para desarrollar con R R Project. R es un lenguaje y entorno de trabajo para cálculo estadístico y gráficos. Proporciona un conjunto de herramientas de cálculo estadístico (clasificación, clustering, modelado linear, no lineal, análisis temporal…) y herramientas gráficas para la visualización científica.

Para instalar el entorno usaremos el gestor de paquetes apt

$ apt-get install r-base
$ apt-get install r-base-dev
$ R

R version 3.5.2 (2018-12-20) -- "Eggshell Igloo"
Copyright (C) 2018 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R es un software libre y viene sin GARANTIA ALGUNA.
Usted puede redistribuirlo bajo ciertas circunstancias.
Escriba 'license()' o 'licence()' para detalles de distribucion.

R es un proyecto colaborativo con muchos contribuyentes.
Escriba 'contributors()' para obtener más información y
'citation()' para saber cómo citar R o paquetes de R en publicaciones.

Escriba 'demo()' para demostraciones, 'help()' para el sistema on-line de ayuda,
o 'help.start()' para abrir el sistema de ayuda HTML con su navegador.
Escriba 'q()' para salir de R.
>

Con esto es suficiente para trabajar con R, pero para una mejor gestión, sobre todo de la parte visual, proponemos usar R-StudioR Studio

$ wget https://download1.rstudio.org/desktop/bionic/amd64/rstudio-1.4.1106-amd64.deb  # Descarrgamos la última versión disponible
$ dpkg -i rstudio-1.4.1106-amd64.deb    # Desempaquetamos y instalamos
$ rstudio # lanzamos el entorno

RStudio IDE

Desarrollo

Como hemos comentado al principio, hemos seguido el ejemplo que propone el Blog de Dominic Roye. Hemos seguido paso a paso su propuesta, ajustándola al caso de Valls.

La Dirección General del Catastro de España tiene información espacial sobre las contrucciones del Estado. Por cada municipio de España, se puede descargar la información, que está enmarcada dentro de la implementación de INSPIRE, la infraestructura europea d’información geográfica.

Preparación de librerías

if(!require("tidyverse")) install.packages("tidyverse")
if(!require("feedeR")) install.packages("feedeR")
if(!require("fs")) install.packages("fs")
if(!require("lubridate")) install.packages("lubridate")
if(!require("fs")) install.packages("fs")
if(!require("tmap")) install.packages("tmap")
if(!require("classInt")) install.packages("classInt")
if(!require("showtext")) install.packages("showtext")
if(!require("sysfonts")) install.packages("sysfonts")

# load packages
library(feedeR)
library(sf) 
library(fs)
library(tidyverse)
library(lubridate)
library(classInt)
library(tmap)

En nuestro caso hemos necesitado un poco de tiempo para compilar las librerías necesarias. En función del entorno de trabajo y desarrollo este proceso será más o menos largo. Indicar que en alguna librería ha sido necesario utilizar la herramienta apt-get para instalar librerías de sistema.

Obtención de los datos

url <- "http://www.catastro.minhap.es/INSPIRE/buildings/ES.SDGC.bu.atom.xml"

#en este XML, agrupado por Provincias, tenemos el listado de los datos de cada ciudad

# importamos los enlaces de las provincia 
prov_enlaces <- feed.extract(url)
str(prov_enlaces) # object is a list
#List of 4
#$ title  : chr "Download service of Buildings. Territorial Office"
#$ link   : chr "http://www.catastro.minhap.es/INSPIRE/buildings/ES.SDGC.BU.atom.xml"
#$ updated: POSIXct[1:1], format: "2021-03-04"
#$ items  : tibble [52 × 5] (S3: tbl_df/tbl/data.frame)
#..$ title      : chr [1:52] "Territorial office 02 Albacete" "Territorial office 03 Alicante" "Territorial office 04 Almería" "Territorial office 05 Avila" ...
#..$ date       : POSIXct[1:52], format: "2021-03-04" "2021-03-04" "2021-03-04" "2021-03-04" ...
#..$ link       : chr [1:52] "http://www.catastro.minhap.es/INSPIRE/buildings/02/ES.SDGC.bu.atom_02.xml" "http://www.catastro.minhap.es/INSPIRE/buildings/03/ES.SDGC.bu.atom_03.xml" "http://www.catastro.minhap.es/INSPIRE/buildings/04/ES.SDGC.bu.atom_04.xml" "http://www.catastro.minhap.es/INSPIRE/buildings/05/ES.SDGC.bu.atom_05.xml" ...
#..$ description: chr [1:52] "\n\t\t  " "\n\t\t  " "\n\t\t  " "\n\t\t  " ...
#..$ hash       : chr [1:52] "d21ebb7975e59937" "bdba5e149f09e9d8" "03bcbcc7c5be2e17" "8a154202dd778143" ...

prov_enlaces_tab <- as_tibble(prov_enlaces$items)
prov_enlaces_tab

#1 "Territorial office 02 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  d21ebb7975e…
# 2 "Territorial office 03 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  bdba5e149f0…
#3 "Territorial office 04 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  03bcbcc7c5b…
# 4 "Territorial office 05 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  8a154202dd7…
#5 "Territorial office 06 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  7d3fd37631f…
# 6 "Territorial office 07 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  9c08741f1c5…
#7 "Territorial office 08 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  ff722b15e11…
# 8 "Territorial office 09 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  b431aa61bd3…
#9 "Territorial office 10 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  f79c6562d93…
#10 "Territorial office 11 … 2021-03-04 00:00:00 http://www.catastro.minhap.es/INSPIRE/buildings/… "\n\t\t  "  d702a6a8c58…


# Filtramos la provincia y obtenemos el link RSS
val_atom <- filter(prov_enlaces_tab, str_detect(title, "Tarragona")) %>% pull(link)

# importamos el RSS
val_enlaces <- feed.extract(val_atom)

# Obtenemos una tabla con los enlaces de descarga
val_enlaces_tab <- val_enlaces$items

#  filtramos la entrada que corresponde con nuestra ciudad, VALLS. PAra otros ejemplos en Tarragona, cambiamos el nombre de la ciudad por otro: REUS, TARRAGONA ...
val_link <- filter(val_enlaces_tab, str_detect(title, "VALLS")) %>% pull(link)
val_link
## [1] "http://www.catastro.minhap.es/INSPIRE/Buildings/43/43163-VALLS/A.ES.SDGC.BU.43163.zip"

# creamos un fichero temporal
temp <- tempfile()

# descargamos los datos
download.file(URLencode(val_link), temp)

# lo descomprimimos en una carpeta llamada buildings_valls
unzip(temp, exdir = "buildings_valls")

# Obtenemos el fichero con los datos
file_val <- dir_ls("buildings_valls", regexp = "building.gml")


# importamos los datos

buildings_val <- st_read(file_val)
#Reading layer `Building' from data source `/home/XXXXXXX/devel/r/buildings_valls/A.ES.SDGC.BU.43163.building.gml' using driver `GML'
#Simple feature collection with 6748 features and 24 fields
#Geometry type: MULTIPOLYGON
#Dimension:     XY
#Bounding box:  xmin: 348762.1 ymin: 4567959 xmax: 356719.3 ymax: 4577808
#CRS:           25831  Importante este valor, es el EPSG que necesitamos para gestionar la proyección de las coordenadas   


Filtramos datos para solventar algún error de formato.

buildings_val <- mutate(buildings_val, 
                        end = str_replace(end, "^-", "0000") %>% 
                          ymd_hms() %>% as_date()
                )

buildings_val <- mutate(buildings_val, 
                        beginning = str_replace(beginning, "^-", "0000") %>% 
                          ymd_hms() %>% as_date()
)
##Warning message:
#Problem with `mutate()` column `beginning`.
#ℹ `beginning = str_replace(beginning, "^-", "0000") %>% ymd_hms() %>% as_date()`.
#ℹ  3 failed to parse.

Primera gráfica: Evolución del número de inmuebles por año. En este caso, indicamos des de 1-1-1815, agrupando de 20 en 20 años


#font download
sysfonts::font_add_google("Montserrat", "Montserrat")

#use showtext for fonts
showtext::showtext_auto() 
# limit the period after 1815
filter(buildings_val, beginning >= "1815-01-01") %>%
  ggplot(aes(beginning)) + 
  geom_density(fill = "#2166ac", alpha = 0.7) +
  scale_x_date(date_breaks = "20 year", 
               date_labels = "%Y") +
  #scale_y_date()
  theme_minimal() +
  theme(title = element_text(family = "Montserrat"),
        axis.text = element_text(family = "Montserrat")) +
  labs(y = "",x = "", title = "Evolution of urban development")

Segunda gráfica: Obtenemos la coordenada de Valls, proyectamos el EPGS y mostramos un radio de 2000m del punto central Podemos jugar con la llamada geocode_OSM para centrar el mapa en un punto o otro., así como el radio de estudio Para revisar qué consulta se hace, podemos obtener el resultado desde OpenStreetMaps


#coordenadas de Valls
ciudad_point <- tmaptools::geocode_OSM('Valls', 
                                       as.sf = TRUE)

#  Proyectamos los putos con el EPGS del fichero de Cadastro 
ciudad_point <- st_transform(ciudad_point, 25831)

# creamos un buffer de 2km (2 km)
point_bf <- st_buffer(ciudad_point, 2000)


# Realizamos la intersección entre el buffer y los datos de inmuebles.
buildings_val25 <- st_intersection(buildings_val, point_bf)
## Warning: attribute variables are assumed to be spatially constant
## throughout all geometries


# Filtramos errores
buildings_val25 <- subset(buildings_val25,beginning!='0-01-01')

Ahora agrupamos los inmuebles por año. Realizamos los intervalos, 13, usando kmeans. Podríamos usar otros algoritmos de clasificación

r <- classIntervals(year(buildings_val25$beginning), n=13, style="kmeans", dataPrecision=0)

# creamos las etiquetas
lab <- names(print(br, under = "<", over = ">", cutlabels = FALSE))
## style: kmeans
##one of 3.172597e+16 possible partitions of this variable into 13 classes
##< 1873 1873 - 1908 1908 - 1925 1925 - 1937 1937 - 1948 1948 - 1956 1956 - 1962 1962 - 1970 1970 - 1978 1978 - 1987 
#22        1525          75          41          79         168         132         597         643         573 
##1987 - 1997 1997 - 2006      > 2006 
##653         542         191

# categorizamos el año
buildings_val25 <- mutate(buildings_val25, 
                          yr_cl = cut(year(beginning), br$brks, labels = lab, include.lowest = TRUE))

En este momento podemos usar la función ggplot parar dibujar el mapa


# colores
col_spec <- RColorBrewer::brewer.pal(11, "Spectral")

# funcion rampa de colores
col_spec_fun <- colorRampPalette(col_spec)

#crear el mapa
ggplot(buildings_val25) +
  geom_sf(aes(fill = yr_cl), colour = "transparent") +
  scale_fill_manual(values = col_spec_fun(13)) + # adapta al número clases
labs(title = "VALLS", fill = "") +
  guides(fill = guide_legend(keywidth = .7, keyheight = 2.7)) +
  theme_void(base_family = "Montserrat") +
  theme(panel.background = element_rect(fill = "black"),
        plot.background = element_rect(fill = "black"),
       legend.justification = .5,
    legend.text = element_text(colour = "white", size = 12),
     plot.title = element_text(colour = "white", hjust = .5, size = 60,
                              margin = margin(t = 30)),
  plot.caption = element_text(colour = "white",
                               margin = margin(b = 20), hjust = .5, size = 16),
 plot.margin = margin(r = 40, l = 40))

Tercera gráfica: Mapa dinámico con leaflet

m <-   tm_shape(buildings_val25) +
  tm_polygons("yr_cl", 
              border.col = "transparent",
              palette = col_spec_fun(13), # adapta al número clases
              textNA = "Without data",
              title = "")
tmap_leaflet(m)

Resultados

A partir de este ejemplo hemos conseguido una serie de resultados que mostramos a continuación (Haced click en la imagen para más detalle)

Por otro lado, mostramos también la evolución de construcciones en Valls, a lo largo del tiempo: Evolución

Y si quereis ver en detalle el mapa del crecimiento urbanístico de Valls aquí os dejo el visor realizado con r-studio usando Leaflet. Pulsa en la imagen para verlo.

Crecimiento Urbano de Valls

Bonus track

Este mismo ejercicio realizado con R se puede realizar con QGIS. En este artículo se muestra el detalle, el mismo concepto pero con diferentes herramientas. Aquí lo tenéis

Compariendo este ejercicio con mi compañero en el Ajuntament de Valls, Xavi Borrell, me ha regalado una pequeña animación que ha realizado utilizando QGIS y el trabajo de estudio de crecimiento urbano. #WeLoveData!

Crecimiento

Si queréis descargar las imágenes en pdf:

OpenData  devel  GIS  R  DataViz 

See also