483 106 33MB
Spanish Pages [288] Year 2019
INTRODUCCIÓN A LOS SIG CON R Dominic Royé y Roberto Serrano Notivoli
PRENSAS DE LA UNIVERSIDAD DE ZARAGOZA
1 Breve introducción al Lenguaje R R es un lenguaje de programación pensando para su uso en análisis estadístico. No es el lenguaje más potente (rápido en cálculo) que existe, pero sí es uno de los que incluye un mayor número de paquetes de funciones con operaciones predefinidas sobre estadística básica y avanzada. Su filosofía open source permite que todas las herramientas, scripts y funciones desarrolladas por los usuarios puedan ser compartidas de manera gratuita y se pueda acceder hasta la última línea de código para consultarla. Esto enriquece enormemente la evolución del lenguaje de programación y a la comunidad de usuarios. En este capítulo introductorio veremos la estructura y funcionamiento básicos del lenguaje R. Trabajaremos directamente sobre RStudio, que dispone de una interfaz intuitiva con accesos directos a algunos de los comandos de uso más común.
1.1 ¿Qué es R y por qué debemos aprender a usarlo? El uso de lenguaje R tiene varias ventajas: • • •
•
• •
•
• •
Su carácter abierto (open source) hace que sea gratuito, lo cual supone un avance primordial respecto a sus competidores de pago. Es multiplataforma, así que puede funcionar en Windows, Mac y Linux indistintamente. Puede gestionar grandes cantidades de información: ya no hay límite en la cantidad de datos a analizar. El único límite lo pone nuestro hardware (fundamentalmente, memoria RAM y capacidad de almacenamiento). Es más que una aplicación de estadística: actualmente en R pueden ejecutarse funciones en otros lenguajes, como C, Phyton o Java. También puede acceder directamente a la terminal del sistema operativo y ejecutar tareas de sistema. Tiene una amplia comunidad de usuarios: este es uno de sus puntos fuertes. Miles de usuarios crean y actualizan paquetes de funciones para todo tipo de análisis estadístico y visualización. Es fácil de aprender en relación con otros lenguajes de programación: a nivel de usuario principiante, la curva de aprendizaje tiene una pendiente mucho mayor al inicio frente a otros programas de estadística con funciones predefinidas y una interfaz más intuitiva. Esta curva es mucho menos pendiente si lo comparamos con otros lenguajes. Sin embargo, una vez se supera la fase inicial, la aportación del conocimiento de R sobre otros programas es mucho mayor en la obtención de resultados de aprendizaje. Se pueden crear gráficos de calidad profesional: los gráficos son una manera primordial de compartir los resultados obtenidos a través de las funciones en R. Se pueden crear desde los más básicos hasta los más complejos mediante el uso de diferentes paquetes de funciones disponibles. Además, se pueden exportar a prácticamente todos los formatos de imagen, vectorial y ráster. Hay una función para eso: existen miles de paquetes disponibles en el repositorio oficial de CRAN (Comprehensive R Archive Network) (https//cran.r-project.org). Permite trabajar con todo tipo de datos: no hay nada que R no puede leer: desde los tipos de información más básicos, como los binarios hasta los más complejos, como cualquier tipo de
1
•
•
texto formateado en un programa de edición, existen funciones específicas para leer cualquier conjunto de datos. Puede aprovechar todo el potencial del hardware: En la actualidad R ya se utiliza como lenguaje para HPC (High Performance Computing) a todos los niveles. A menor escala, existen paquetes con funciones de aplicación muy sencilla que nos permiten utilizar, por ejemplo, todos los nodos de computación (procesadores) de nuestro ordenador personal, lo que hace posible disminuir significativamente el tiempo de cálculo en tareas recursivas. Permite incluso escribir y maquetar documentos: Utilizando código embebido rmarkdown (https://rmardown.rstudio.com) podemos crear documentos e informes tanto en pdf como en html, permitiendo su publicación en internet, así como aplicaciones web interactivas a partir de los datos analizados (shiny https://shiny.rstudio.com).
1.2 Instalación de R e interfaz de RStudio Para comenzar con R es necesario instalar el motor básico (R Core), que incluye todas las librerías necesarias y una interfaz muy sencilla para empezar a trabajar. Existen instaladores para casi todos los sistemas operativos y pueden descargarse del repositorio oficial CRAN: https://cran.rproject.com Sin embargo, la interfaz gráfica de R Core es poco intuitiva y no invita a aprender. A pesar de que su funcionamiento es correcto, no dispone de algunos elementos de ayuda que pueden ser muy útiles en las primeras sesiones, como el resaltado de la sintaxis o la visualización directa de los objetos en memoria. Existen varios programas que permiten ejecutar el código de R, pero en los últimos años RStudio ha ganado mucha popularidad por su facilidad de manejo. Es gratuito y puede obtenerse de https://www.rstudio.com. Una vez descargado e instalado en el sistema, al abrirlo por primera vez vemos una ventana dividida en tres partes. A la izquierda encontramos la consola, donde aparecerá siempre al abrir el programa la información básica sobre la versión de R que estamos trabajando y alguna ayuda adicional. Es aquí donde ejecutaremos todo nuestro código. En la parte superior derecha aparece un conjunto de dos pestañas. La que se denomina Environment es nuestro entorno de trabajo. Aquí podremos ver todos los objetos y funciones que tenemos almacenados en la memoria, y también hay algunos comandos para abrir y guardar toda esta información. Es importante saber que absolutamente todo lo que podemos hacer con RStudio a través de sus comandos y botones podemos hacerlo también escribiéndolo en la línea de comandos. La segunda pestaña es History y muestra el historial de líneas de código que hemos ido ejecutando. Es útil si en algún momento queremos volver atrás para ejecutar un código que ya hemos borrado. El historial también está accesible en la propia consola con las flechas arriba y abajo, que nos permiten recuperar códigos ejecutados previamente.
2
En la parte inferior derecha aparecen cinco pestañas, todas ellas de gran importancia para el uso habitual del programa. La pestaña files es el explorador de archivos. Nos muestra el árbol de archivos sobre el que podemos navegar directamente y aplicar algunas funciones básicas, como crear una carpeta, borrar un archivo o renombrarlo. Aquí es muy importante el comando More, ya que nos abre una serie de opciones de sistema de las que hay una que se utiliza muy a menudo: Set As Working Directory. Esta función establece el directorio de trabajo sobre el que se leerán y escribirán todos los archivos (si es necesario en nuestro código) La función en la consola o en un script tiene la forma setwd(), en la que también podemos definir el directorio de trabajo. Nota: Las rutas de archivos y directorios en R siempre se definen con la barra oblicua (/), independientemente de que en Windows se use por defecto la contrabarra (\). Si queremos definir como directorio de trabajo en Windows la ruta C:\user\analisis\, tendremos que escribir setwd("C:/user/analisis/"). La pestaña Plots se activará automáticamente cada vez que ejecutemos una línea de código para crear un gráfico. La pestaña Packages contiene un listado de todos los paquetes de funciones que tenemos instalados en nuestro ordenador, así como aquellos que están cargados en ese momento (si tienen marcada la casilla correspondiente). El comando Install en esta pestaña nos permite instalar nuevos paquetes desde internet (o localmente) de una manera muy sencilla. La pestaña Help contiene la ayuda de todas y cada una de las funciones contenidas en los paquetes (se explica más adelante en este capítulo). Finalmente, la pestaña Viewer nos permite ver el contenido interactivo, principalmente de gráficos y mapas.
1.3 Crear proyectos Una alternativa a la función setwd() es la creación de un proyecto. Podemos crear un nuevo proyecto de dos maneras: 1) entrando en el menú Files y escogiendo New Project o 2) usando el símbolo de proyecto que aparece en la barra de herramientas. RStudio nos permite elegir entre 3
varias opciones: 1) New directory, 2) Existing directory o 3) Version control. Lo más habitual es definir un proyecto con referencia a un directorio existente.
Una vez creado el proyecto, RStudio reinicia la sesión y en el directorio aparecerá un nuevo archivo con el nombre del directorio y la extensión .Rproj. Este archivo permite abrir el proyecto posteriormente sin necesidad de definir el directorio de trabajo. Incluso cuando cambiamos la carpeta de ubicación, sigue reconociendo la ruta del directorio de trabajo. Si hacemos clic sobre el archivo a través de la ventana Files, nos abre una ventana con opciones del proyecto. Nota: Es remendable usar un proyecto de RStudio por cada proyecto de análisis de datos. Además, se recomienda usar carpetas individuales para los datos y los resultados, así como enumerar de manera secuencial los diferentes scripts con los pasos del análisis (p. ej.: 00_download.R, 01_explore.R, etc.). No uses rutas absolutas, sino siempre relativas.
1.4 Primeros pasos: operaciones básicas Para comenzar, podemos introducir algunas operaciones básicas directamente en la consola de RStudio:
4
Ya vemos que R se comporta básicamente como una calculadora. Además, tiene algunas otras ventajas que permiten hacer cálculos sobre secuencias numéricas. Podemos concatenar series de cualquier longitud de varias maneras con el mismo resultado:
Todas ellas proporcionan la misma secuencia de 1 a 10, ya sea utilizando la función de concatenación (c()), separando el primer y último número con dos puntos (:) o definiendo que se trata de una secuencia con seq() especificando el primer número, el último y el intervalo. Todas secuencias pueden utilizarse para operar con otros números, por lo que el resultado tendrá una longitud igual al de mayor tamaño.
1.5 Tipo de datos y operaciones aritméticas En R podemos operar, entre otros, con cinco tipos básicos de datos: lógico, entero, numérico, completo y carácter. El resultado de cada una de esas operaciones dependerá del tipo que sean los elementos que componen la operación. Los datos lógicos solamente pueden ser TRUE (verdadero) o FALSE (falso), y cuando los tratamos en una operación como un número adoptan los valores de 1 y 0, respectivamente, Se pueden abreviar con T y F.
5
Cuando escribimos un número en la consola, por defecto es reconocido como numérico, que a su vez puede ser entero o flotante. Sin embargo, podemos forzar que un número sea entero escribiendo a continuación de él el carácter L.
Finalmente, podemos trabajar con cadenas de texto escribiéndolas entre comillas dobles o simples.
Existen algunos valores especiales que, si los combinamos en operaciones con cualquier otro tipo de objetos, darán como resultado ese mismo valor. Se trata de los valores faltantes NA (Not Available), valores no numéricos NaN (Not a Number) y valores infinitos Inf (Infinite).
Podemos aplicar operaciones aritméticas con todos estos tipos de datos utilizando el operador correspondiente.
6
1.6 Objetos: modos y clases Los resultados de las operaciones se pueden almacenar en un objeto de manera muy sencilla. Esto nos permitirá volver a usar ese resultado en el futuro tantas veces como queramos sin necesidad de escribir toda la operación de nuevo. Los objetos se crean con el asignador % directamente a ggplot().
90
Para simplificar, creamos un nuevo objeto con únicamente los datos de la temperatura media.
91
Una alternativa a un histograma es un gráfico de densidad que se basa en la función de densidad de probabilidad. La integral de toda el área bajo la curva es 1, lo que equivale a una probabilidad del 100%.
¿Cómo podemos crear diferentes curvas de densidad para cada año? Únicamente debemos especificar los dos argumentos colour = year y group = year. Además, modificamos con el argumento alpha = 0.3 el grado de transparencia del color. Para cambiar los 92
colores de una variable continua hacemos uso de la función scale_gradientn(), que permite definir colores de forma manual. Nota: Existen variantes de la misma función anterior, por ejemplo, scale_color_gradient2(), que tiene argumentos para definir el color del valor más bajo, más alto y el color del valor medio.
Nota: R puede entender números entre 0 y 1 sin el 0 antes de la coma, como .1 o .8. Aquí introducimos el operador %in%, que nos permite filtrar varios valores en un conjunto. Además, en lugar de dibujar las curvas de densidad por el color de las mismas, cambiamos al relleno (fill) del área de las curvas.
93
3.2.9 Gráficos de líneas ggplot tiene funciones especiales para series temporales que nos permiten hacer cambios en los ejes con clase de Date o POSIXct, por ejemplo scale_x_date() o scale_x_datetime(). Los argumentos que se usan difieren de los habituales: date_breaks y data_labels. Los intervalos se definen en la misma forma, como si fuese una secuencia de fechas, por ejemplo 'year' (cada año) o '2 month' (cada dos meses). La unidad temporal sin número indica un intervalo de 1. El formato de las etiquetas se especifica en la forma de la función strftime(). Todos los elementos temporales y sus formatos (mes, año, hora, etc.) tienen códigos que empiezan por % (%Y para el año con cuatro cifras 1950).
Algunos de los más importantes son (más en la ayuda ?strftime):
94
Un primer gráfico de líneas.
95
Si quisiéramos cambiar el tipo de línea, únicamente deberíamos usar el argumento linetype de la misma forma como definimos el color o el tamaño. Los diferentes estilos son los del siguiente gráfico:
96
Cambiamos el tipo de línea a discontinua (dashed).
Recordemos que nuestros datos contienen algunas variables meteorológicas en formato de tabla larga. En el siguiente gráfico se hace visible la importancia de una tabla larga y de tener como clase factor las variables. Haremos facetas de todas las variables a partir del año 2000. Cuando usamos la función facet_grid(), por defecto ajusta el eje y a todas las facetas con el mismo rango de valores. Este comportamiento es esencial cuando queremos comparar variables; no obstante, con variables climáticas con unidades tan diversas (temperatura (°C), dirección de viento (°), etc.) no sería aconsejable. Por eso usamos el argumento scales = 'free_y', que hace que cada faceta tenga su propia escala en el eje de ordenadas. Con la función theme() y el argumento strip.text.y cambiaremos el ángulo de las etiquetas de cada faceta de 90 a 0°, lo cual facilitará la lectura, ya que los nombres son muy largos.
97
3.2.10 Boxplot x Para conseguir un gráfico de boxplot mensual es necesario crear la variable del mes. Esto solamente funciona cuando la variable tiene clase factor o character, por eso indicamos con el argumento label = TRUE que queremos etiquetas de los meses.
98
3.2.11 Gráficos de barras Los gráficos de barras son útiles para muchos tipos de datos. Intentamos responder a la pregunta: ¿cuántos días con 25°C o más se observan cada año? Para ello, filtramos los datos de aquellos días que tengan una temperatura igual o superior ante de pasar este subset a ggplot(). La función geom_bar() por defecto hace un conteo de la variable indicada.
99
Asignamos el resultado del filtro y el conteo a un nuevo objeto para usarlo después. En el gráfico anterior sumó el número de días de cada año, pero, si ya tenemos calculado el número de días como en el siguiente ejemplo, la solución es más fácil: únicamente debemos indicar en la función con el argumento stat = "identity" que debe usar n tal como está dado. En el siguiente gráfico incluimos también la línea de tendencia con la función stat_smooth() o geom_smooth(), indicando con el argumento method = 'lm' que lo haga a través de una regresión lineal.
100
La geometría geom_bar() nos permite hacer más modificaciones habitualmente usadas para representar datos (barras apiladas, agrupadas, etc.). Usando el dataset de diamonds del paquete ggplot2 podemos ver algunos ejemplos de uso:
101
102
103
104
En este ejemplo haremos un gráfico de columnas apiladas más avanzado. Para ello usaremos datos extraídos de la base de datos emdat (https://www.emdat.be/) sobre desastres naturales a nivel global desde 1900 hasta hoy. Primero importamos los datos y realizamos algunas modificaciones para su visualización. Para ello es necesario calcular el total de ocurrencia de los desastres en cada categoría y año.
105
Ahora podemos construir el gráfico de columnas apiladas.
106
3.2.12 Gráficos de áreas Para crear un gráfico de áreas apiladas usamos la función geom_area() con el mismo argumento que en el ejemplo anterior fill = subgr. No obstante, existen combinaciones ausentes entre categoría y año; o sea, son años en los que no hubo desastres en ciertas categorías. Si lo visualizamos directamente, el área apilada se muestra en estos años con huecos, ya que son valores NA, lo que hace el gráfico poco atractivo. Para resolver este problema completaremos todas las combinaciones con la función complete() y rellenaremos estos casos ausentes asignando a n un valor 0.
107
3.2.13 Heatmaps x Los heatmaps son gráficos extremadamente útiles para representar, por ejemplo, tres variables. Vamos a usar los registros de rayos en la región de Galicia en 2017 y lo representaremos por mes y hora. R permite importar y cargar funciones u otros scripts con la función source(). Cargamos un script con varias líneas de código que permiten descargar los registros de rayos del servicio meteorológico Meteogalicia (https://github.com/dominicroye/meteogalicia). 108
Hacemos algunas transformaciones: 1) debemos convertir las columnas 1 y 3 a 5 en numérico, y horaUTC en carácter, y 2) combinamos la hora y la fecha en un formato conjunto y extraemos la hora y el mes. Nota: Cuando usamos directamente as.numeric() sobre un factor lo convertimos en la codificación de los diferentes niveles. Por eso, se debe usar primero as.character().
109
Nota: Como vemos en el ejemplo, podemos usar la función count() directamente sin agrupar los datos antes.
3.3 Etiquetas de texto superpuestas ggplot es extremadamente versátil y dispone de multitud de opciones adicionales para mejorar todos los tipos de gráficos que hemos visto en las secciones anteriores. A continuación se muestran algunas de las opciones más interesantes.
3.3.1 Etiquetas de texto superpuestas La extensión de ggplot2 con el paquete de ggrepel permite añadir etiquetas a puntos sin solapamiento, lo que también es muy útil en la creación de mapas. Para incluir texto o etiquetas solamente debemos usar las funciones geom_text_repel() o geom_label_repel(). Volvemos a usar los datos de esperanza de vida. Antes de crear el gráfico, filtramos los datos excluyendo todos los registros que no son países. Este paso es posible debido a que los países están en minúsculas. Además, escogemos un número máximo de 50 países con la función slice(), usando la función sample(), que nos devuelve una muestra aleatoria.
110
Nota: Para añadir etiquetas a otras geometrías es necesario usar otro paquete de funciones: directlabels (http://directlabels.r-forge.r-project.org/).
3.3.2 Mosaico de gráficos Cuando queremos unir varios gráficos independientes, uno de los paquetes que se emplea actualmente es cowplot. La función principal de cowplot es plot_grid(), que ayuda a combinar diferentes gráficos. También está disponible la función ggdraw(), que configura la capa básica del gráfico. Las funciones que están destinadas a operar en esta capa comienzan con draw_*. Usaremos dos diferentes gráficos del dataset de la ocurrencia de desastres.
111
112
3.3.3 Exportación de gráficos La función ggsave() permite exportar los gráficos de ggplot a formatos comunes como png, jpeg, pdf, tif, etc. Esta función solo permite especificar el nombre del archivo y el tipo y, automáticamente, ggplot guarda el último gráfico creado en la ventana de plotting con las mismas dimensiones. Podemos encontrar más formatos en la ayuda de ?ggsave. También se puede indicar height y width en las unidades in, cm y mm, especificándolo en el parámetro units = 'cm'.
113
Nota: En el caso del paquete cowplot la función para exportar es save_plot(). Si no se desea exportar el último gráfico creado, se puede exportar un ggplot asignado previamente a un objeto.
114
4 Consideraciones iniciales sobre análisis espacial 4.1 Formatos de datos R es capaz de gestionar prácticamente todos los formatos de datos geoespaciales, tanto vectoriales (puntos, líneas y polígonos) como ráster (datos en rejilla). Otras veces, los datos geoespaciales incluyen información adicional almacenada en múltiples dimensiones. A pesar de que el manual utiliza los formatos más comunes en el mundo de los Sistemas de Información Geográfica (SIG), este tipo de datos está cada vez más presente en los análisis. Hoy en día la disponibilidad de información de cualquier tipo es cada vez más sencilla y más accesible y, por tanto, disponemos de volúmenes de información tan grandes que hace unos pocos años hubiera sido imposible gestionar. En esta era del Big Data hemos necesitado adaptar los formatos de los archivos y crear otros nuevos para que sean capaces de almacenar de una manera eficiente cantidades enormes de información. El problema no solo reside en cómo comprimir toda esa información en un archivo de tamaño asumible, sino en que es más importante hasta qué punto es sencillo acceder a cada parte de la información que contiene. En este sentido, R ha evolucionado para facilitar el acceso a recursos muy potentes con los que gestionar toda la información, desde formatos de archivos propios (p. ej.: .RData) hasta la posibilidad del aprovechamiento de toda la capacidad de computación del hardware, lo cual hace aprovechable este lenguaje en supercomputadores. No obstante, para la mayoría del trabajo de análisis espacial no es necesario tener conocimientos avanzados de programación. De hecho, los paquetes de funciones más actuales ponen a disposición del usuario sencillas funciones que trabajan internamente a un nivel computacional muy intenso. La ventaja es que, para cualquier nivel de programación, los formatos de archivos son los mismos. Algunos de los más comunes son: Vectorial: Shapefile de Esri: es el más utilizado con una gran diferencia. Todo software de análisis espacial que se precie debe poder leer/escribir este tipo de archivos. Se compone, como mínimo, de tres archivos: .shp (geometría de los datos), .shx (índices de los objetos que componen la capa) y .dbf (atributos), aunque pueden acompañarlos varios más con información adicional (proyección, metadatos, etc.). En R las funciones de lectura leen el archivo .shp, que carga automáticamente el resto. geodatabase: es una colección de datasets geográficos de varios tipos contenida en una carpeta de sistema de archivos común o una base de datos relacional multiusuario. CSV / GeoCSV: los clásicos archivos separados por comas (CSV) tienen una variación reciente que les otorga una opción adicional con información sobre su geometría, convirtiéndolos en archivos GeoCSV. La novedad es un campo denominado WKT, que almacena como una cadena de texto las coordenadas del punto al que corresponde cada línea (p.ej: POINT(-1.2353 35.8753)). Al leer el archivo, este campo convierte automáticamente los datos en un objeto espacial.
115
GPX: es un formato de intercambio muy común de información captada por un GPS. Representa los waypoints, tracks o la rutas, entre otros. KML / KMZ: formato por defecto de información espacial en Google Earth. GML / XML: GML es la extensión de XML que permite la inclusión de coordenadas geográficas, guardándolas como cadenas de texto. Se puede usar cualquier editor de texto para modificar estos archivos. GeoJSON: es el formato más común para la representación geográfica vía web. Guarda las coordenadas como texto en JavaScript Object Notation (JSON), pudiendo almacenar información puntual, lineal o de polígonos. Al estar basado en JavaScript, es muy popular para publicar geoinformación en internet a través de geoportales o servidores de mapas. OpenStreetMap: la filosofía colaborativa de creación de información geográfica define a este tipo de archivos. Están basados en XML y su crecimiento y uso es imparable. Representan la información geográfica del futuro: colaborativa, de acceso abierto e interoperable. Ráster: Esri grid: es el formato propietario de Esri para ráster. No tiene una extensión de archivo concreta, ya que se compone de varios archivos dependiendo del tipo de información. Puede contener una tabla de atributos igual que los archivos vectoriales. No es el formato de intercambio en ráster más práctico, aunque existen maneras en R de leer este tipo de archivos. GeoTiff: se trata del formato ráster de referencia en interoperabilidad. Pueden acompañarle varios archivos complementarios que aportan información sobre metadatos, geolocalización, proyección, etc. (.tfw, .aux, .xml …). Es sin duda el formato más usado para información asociada a imágenes de satélite y productos derivados. ASCII: aunque es de los formatos más antiguos, sigue usándose por su sencillez y escaso tamaño de archivos. Es, simplemente, texto plano con una cabecera que aporta la información espacial y la resolución. Lo puede leer cualquier SIG. IMD: es el formato propietario de ERDAS, muy utilizado para almacenar información multibanda en imágenes de satélite. Puede incluir, además de los propios datos asociados a cada banda, información sobre la proyección, atributos, etc. LiDAR: LiDAR: este formato define el tipo de datos Light Detection and Ranging (LiDAR). Se trata de nubes de puntos con información asociada a cada uno de ellos. De su densidad depende la resolución de la información. En función de si los datos están comprimidos o no, cambia el tipo de archivo (.las, .laz). Multidimensionales: NetCDF: se trata del formato de intercambio más popular para los tipos de datos multidimensionales. Se utiliza mucho, por ejemplo, con información climática, permitiendo almacenar en un solo archivo información de miles de localizaciones (latitud y longitud) en varios 116
momentos temporales (p. ej.: meses) y de muchas variables (p. ej.: precipitación, temperatura, viento, presión atmosférica, etc.). Es muy útil para gestionar volúmenes enormes de información geoespacial y R tiene herramientas muy potentes para ello.
4.2 Proyecciones Todos los objetos espaciales tanto en R como en cualquier SIG necesitan un sistema de coordenadas de referencia (Coordinate Reference System – CRS) que defina cómo se relaciona la información que contienen con la superficie de la Tierra. Esta relación, que en R es definida por el parámetro CRS, puede ser de dos tipos: geográfica o proyectada.
4.2.1 Sistemas de coordenadas geográficos Los sistemas de coordenadas geográficos utilizan sistemas de medida angulares. La latitud y la longitud, que se miden en grados, no son más que distancias desde una referencia concreta (el ecuador y el meridiano de Greenwich, respectivamente). Dicha premisa implica que este sistema de coordenadas asume la esfericidad de la Tierra, aunque en realidad el modelo más ajustado es el de un elipsoide, donde el radio del centro de la Tierra al ecuador y a los polos es diferente. Los elipsoides son más adecuados como modelo general, ya que la Tierra no es perfectamente esférica, sino que el radio polar es algo menor. Cuando definimos el CRS de una proyección geográfica, trasladamos a R cuáles son los parámetros de ajuste de nuestros datos a ese modelo teórico de la superficie terrestre. Estos parámetros, codificados en formato proj4string (https://proj4.org/usage/projections.html), permiten definir 117
incluso cómo se han de tratar las pequeñas variaciones locales en áreas con orografía muy variada (p. ej.: áreas de montaña). Así para definir en formato proj4string el sistema de coordenadas WGS84, su CRS será +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs. En este caso solo se define la proyección, el elipsoide y el datum, pero, como sigue siendo difícil de recordar, podemos utilizar las abreviaturas definidas por European Petroleum Survey Group (EPSG). De esta manera, WGS84 podría definirse como CRS("+init=epsg:4326"). Aunque estas son las formas más comunes de definir las proyecciones en R, para un mismo sistema existen muchas más (http://spatialreference.org/ref/epsg/4326/).
4.2.2 Sistemas de coordenadas proyectados Estos sistemas de coordenadas asumen una superficie bidimensional basada en coordenadas cartesianas. Esto implica trasladar la información espacial de las coordenadas que originalmente se ubican en la pseudoesfera que es la Tierra a un plano de dos dimensiones. Sin entrar en aspectos más detallados, es inevitable asumir que esta implicación siempre va a generar una distorsión que, en parte, es paliada en función del tipo de proyección que elijamos para nuestro mapa. La definición de la proyección se hace igual que para las coordenadas geográficas usando el formato proj4string.
4.2.3 Transformaciones Si trabajamos con dos objetos espaciales con diferente sistema de coordenadas, las operaciones de análisis espacial que queramos aplicar sobre ellos serán inútiles, ya que, a efectos prácticos, no tienen coincidencia espacial. Para solucionarlo, hay que cambiar el sistema de coordenadas de uno de ellos para que tenga coincidencia con el otro, o bien cambiar el de los dos por uno común. Este cambio de sistema de coordenadas, sea cual sea, por otro supone aplicar una transformación geográfica que consiste en una serie de operaciones matemáticas para ajustar los parámetros de una proyección a otra. En R es una tarea muy sencilla que puede aplicarse con diversas funciones de los paquetes sp y sf, entre otros, que se detallan en capítulos posteriores. La aplicación solo requerirá del objeto espacial que queramos transformar, el sistema de coordenadas que tiene actualmente y el que queremos que tenga. Es importante que los sistemas de coordenadas se definan correctamente en formato proj4string.
4.3 Exportación de datos Una vez que hemos leído los archivos (de cualquier formato) y hemos incorporado la información a R como objeto espacial, podemos escribir los resultados de nuevo en un archivo para que vuelvan a ser editables en el futuro, o no. Algunas posibilidades para exportar la información espacial desde R son: Datos editables: incluye todo lo relativo a exportación de archivos gestionables por un SIG; por ejemplo, en cualquier formato de archivo que aparece detallado al inicio de este capítulo. Los paquetes de R con funciones para leer diferentes formatos de datos geoespaciales también incluyen funciones para escribirlos. 118
Imagen: se trata de una foto fija de la información temática que representamos en R. Exportamos la representación cartográfica. No es editable. R permite exportar tanto con los paquetes incluidos en la instalación original como con otros específicos, en formato vectorial (p. ej.: pdf, eps), editables posteriormente o en imagen de mapas de bits (p. ej. jpg, tif, png). Web: es un método de publicación que permite la consulta interactiva de la información geoespacial. Leaflet es, probablemente, el método más utilizado para generar este tipo de formato de salida. RMarkdown: es un lenguaje de programación que permite exportar la información geoespacial (y cualquier otra) a un formato de lectura (p. ej.: un informe) integrando al mismo tiempo, texto, código (ejecutable) e imágenes. Los documentos de salida pueden generarse en pdf o en html para su consulta vía web. Es muy útil para exportar la información geográfica directamente a un documento.
119
5 Datos espacio-temporales I: vectorial El formato vectorial representa la realidad a través de geometrías basadas en puntos, líneas y polígonos. De la misma manera que un SIG, R es capaz de gestionar este tipo de geometrías, ya sea a través de la lectura y escritura de prácticamente todos los formatos existentes (propietarios y libres), ya sea creando él mismo las formas mediante la introducción de las coordenadas que representan cada uno de los nodos. Todas las operaciones de análisis espacial sobre vectores se pueden llevar a cabo en R, desde la manipulación en el aspecto de las formas hasta la gestión de sus atributos. Una vez más, la gran ventaja de usar R en lugar de un SIG en este sentido es la posibilidad de automatizar procesos y leer conjuntos de datos difíciles o imposibles de gestionar en un SIG convencional. En general, para importar y manipular shapefiles (ESRI), geojsons, geodatabases, etc. con R podemos utilizar los siguientes paquetes:
La forma clásica para importar, exportar y manipular datos vectoriales se hace a través de sp y rgdal. No obstante, ya está disponible el nuevo paquete sf (Simple Features), que combina las funciones de las anteriores. Sin embargo, todavía se hace necesario conocer la manipulación clásica debido a que ciertas funciones y paquetes aún no han cambiado al nuevo formato sf. Es previsible que este paquete reemplace a los métodos actuales. ¿Qué ventajas tiene sf? 1) Simple features es una forma estándar (ISO 19125-1:2004) de gestión de datos que une datos espaciales con atributos no espaciales, 2) trabaja con una única clase para todos los tipos de datos vectoriales, 3) la estructura de los datos es de tipo data.frame, 4) se instala más fácilmente, y 5) es rápido y compatible con tidyverse.
5.1 Los paquetes sp y rgdal R dispone de multitud de paquetes de funciones para gestionar la información geoespacial: solamente hay que echar un vistazo a la Task View de análisis espacial (https://cran.rproject.org/web/views/Spatial.html) para ver que es un tema muy activo y en constante actualización. Concretamente, el paquete sp proporciona métodos y clases para trabajar con datos espaciales y, aunque está siendo sustituido por su versión más moderna, el paquete sf, sp todavía es ampliamente utilizado para la manipulación de datos espaciales. Con algunas de las funciones de este paquete podemos crear nuestros propios archivos de puntos con localizaciones y datos asociados. En este ejemplo creamos un data.frame con 100 120
coordenadas aleatorias que creamos con la función runif() entre -180 y +180 y entre -90 y +90, simulando 100 localizaciones sobre el planeta. Hacemos lo mismo para crear los correspondientes valores aleatorios. Después usaremos la función coordinates(), que transformará nuestro data.frame en un objeto espacial.
Si queremos comenzar a extraer información espacial de nuestro nuevo objeto de puntos, podemos usar bbox() para que nos devuelva los límites externos:
Y si queremos representarlo espacialmente, sp incluye sus propias funciones de representación, como spplot():
121
5.1.1 Importación Por otro lado, el paquete rgdal es la versión en R de la librería GDAL (Geospatial Data Abstraction Library, https://www.gdal.org) que utilizan prácticamente todos los SIG hoy en día. En R nosotros básicamente la utilizaremos para leer y escribir información geoespacial vectorial. La función readOGR() se utiliza para leer información vectorial, por ejemplo shapefile de ESRI, y carga la capa asignándole el tipo de datos de objeto espacial que le corresponde según se trate de puntos, líneas o polígonos (SpatialPointsDataFrame, SpatialLinesDataFrame o SpatialPolygonsDataFrame, respectivamente).
5.1.2 Visualización A pesar de que estamos trabajando con objetos espaciales (diferente clase que los data.frame, numeric o character, por ejemplo), podemos usar las funciones plot, lines y points para representar las capas que hemos cargado. Internamente, R reconoce que esos objetos son de clase espacial y llama a las funciones correspondientes para representarlos.
122
5.1.3 Proyecciones y coordenadas Como objetos espaciales, los puntos y polígonos que hemos cargado tienen asociado unos atributos extra, además de la información alfanumérica correspondiente. Podemos extraer la información espacial de, por ejemplo, las coordenadas de las ciudades con la función coordinates(). Si lo aplicásemos sobre los países, nos devolvería las coordenadas de los centroides de cada uno de los polígonos que están representados en el objeto.
123
Estas coordenadas están asociadas a un sistema de proyección concreto, que necesitamos conocer (o definir) en cada caso. La función proj4string() nos devuelve la proyección de un objeto espacial.
Vemos que lo que muestra es una cadena de texto con una secuencia de parámetros importantes para la definición de la proyección: se trata de un sistema de codificación particular denominado proj4. Podemos obtener una tabla con el código EPSG y el proj4string de todas las proyecciones disponibles con la función make_EPSG() del paquete rgdal. No obstante, hay una explicación más detallada en http://spatialreference.org/ref/epsg/.
124
Si queremos asignar una proyección a un objeto espacial que no tiene, debemos hacerlo con la función CRS() (Coordinate Reference System). Esto funciona tanto para objetos espaciales de clase vectorial (puntos, líneas y polígonos) como para ráster.
125
La mayoría de las veces no vamos a recordar la cadena de texto completa en formato proj4, o consultarla se puede volver tedioso. Para facilitarlo, se puede usar en su lugar el código EPSG, una abreviatura numérica para cada una de las proyecciones disponibles. La cadena de texto en este caso es +init=epsg:4326, siendo 4326 el código de la proyección que queremos asignar (en este caso, WGS84).
Ya sabemos extraer la proyección de un objeto espacial y definirla si no la tenía, pero ¿y si queremos cambiarla? En este caso hay que aplicar una transformación, que en R se hace con spTransform():
126
5.1.4 Acceso a las variables Las variables, o campos de información, están asociadas a todos los objetos espaciales. Para acceder a ellas podemos usar la arroba (@), con la que accedemos a los diferentes slots o almacenes de información. En nuestro caso, el objeto paises tiene cinco slots:
• • • • •
data: tabla de atributos de la capa (información temática). polygon: coordenadas de todos los vértices que componen cada uno de los polígonos de la capa (información espacial). plotOrder: orden en el que se dibujan los polígonos de la capa. bbox: coordenadas más externas del marco que componen todos los objetos de la capa. proj4string: tipo de proyección de la capa.
Si queremos acceder a los datos de la tabla de atributos, podemos hacerlo llamando a data usando la arroba (@) y después el nombre del campo que queremos recuperar, o bien escribiendo el nombre de la capa y acceder con el símbolo del dólar ($) al nombre del campo directamente.
También podemos añadir y eliminar atributos de una manera muy sencilla. Por ejemplo, para añadir un campo nuevo escribiremos el nombre que queramos después de $ y le asignamos. Si queremos, le asignamos el valor NULL.
5.1.5 Funciones de análisis espacial Los paquetes sp y rgdal permiten el mismo tipo de manipulación vectorial o análisis espacial que cualquier Sistema de Información Geográfico. En este capítulo veremos los más básicos, como unir, 127
separar o eliminar elementos dentro de una capa cargada en R. Se muestra, en cada caso, el tipo de análisis y entre paréntesis el nombre con el que se denomina en la mayoría de los SIG. 5.1.5.1
Unir tabla (Join)
La función merge() nos permite unir una tabla (en formato data.frame) a la capa que tenemos cargada; simplemente, necesitamos tener un campo en común entre ambas. Este campo no tiene por qué llamarse igual: podemos definir los diferentes nombres dentro de la función.
5.1.5.2
Filtrado (Select by attibutes) y Unión (Append)
Podemos separar elementos de una capa para crear otras nuevas y también unir varias capas en una sola. Es tan fácil como tratarlas como si fuesen data.frames. En el caso de la unión, todas ellas deben ser de tipo vector y tener la misma proyección. Para ello podemos utilizar funciones básicas como rbind().
128
5.1.5.3
Borrado (Erase)
Algunas funciones de análisis espacial básico requieren de otros paquetes de funciones. Por ejemplo, si queremos eliminar una parte de la extensión espacial de nuestra capa, podemos hacerlo con la función erase() del paquete raster. En este ejemplo, primero determinamos el área a recortar (también podría ser una geometría espacial cargada desde un archivo). Con la función extent() definimos los límites externos del área (los mismos que extraíamos con la función bbox() al principio de este capítulo). Como esto solo nos devuelve un objeto de clase extent, tenemos que convertirlo en un objeto espacial para poder operar con él, así que usamos la función as() para convertirlo en un polígono (‘SpatialPolygons’).
Comprobamos que coincide espacialmente:
129
Y usaremos erase() para hacer el recorte.
5.1.5.4
Intersección (Intersect, Clip)
Si utilizamos el mismo polígono para la situación inversa, es decir, seleccionar la parte común a los dos objetos espaciales, estaremos haciendo una intersección.
Tal y como aparece en el ejemplo, algunas funciones como intersect() requieren de la definición del paquete al que pertenece, dado que otros paquetes usan el mismo nombre como función (raster::intersect). Estos conflictos potenciales ya los explicamos en el capítulo sobre la colección de paquetes tidyverse. La función intersect() es equivalente a la función crop().
130
5.1.5.5
Diferencia (Difference)
Podemos extraer el resultado de la diferencia entre dos capas. En este caso el producto final será el espacio de la primera capa que no ocupe la segunda. Primero creamos un objeto espacial de ejemplo con la misma extensión que nuestro objeto espacial con las funciones extent() y as() igual que en el ejemplo de erase() y después definimos la proyección de este objeto (la misma que países, para que coincidan espacialmente).
131
Y ya podemos calcular la diferencia con la función symdif(), a la que pasamos los objetos espaciales que queremos restar.
5.2 El paquete sf El paquete sf es un nuevo estándar para la gestión y manipulación de datos espacio-temporales. Aunque dispone de las mismas funcionalidades de sp y rgdal, también incluye algunas otras nuevas, pero con una sintaxis diferente. sf requiere de una forma de escribir el código distinta, más intuitiva, utilizando estructuras de datos nativas de R (matrix, vector, list, etc.). Es esperable que sf sustituya a sp en el manejo de datos espaciales en R. Algunas características básicas de su sintaxis: •
•
• • • • •
Todos los objetos son data.frame o tibble con las coordenadas espaciales que le corresponden en una columna. Por tanto, el acceso a las variables es igual de simple que si fuese una tabla normal con una columna de geometría. Todas las funciones empiezan por st_*, haciendo referencia al carácter espacial de su aplicación, similar a PostGIS. Igualmente, y al mismo estilo que PostGIS, se usan verbos como nombres de función. Las funciones pueden ser combinadas con el operador pipe (%>%), igual que en tidyverse, que facilita la aplicación de una secuencia de funciones sobre un conjunto de datos. Las funciones también son fácilmente combinables con funciones de la colección tidyverse. Se puede encontrar una lista de funciones equivalentes entre sp y sf en https://github.com/r-spatial/sf/wiki/migrating. Se pueden importar bases de datos espaciales como PostGIS. sf está basado en Open Geospatial Consortium (OGC) y en el estándar ISO 19125, que específica un modelo de acceso y almacenamiento común de geometrías en su mayoría bidimensionales (punto, línea, polígono, multipunto, multilínea, etc.).
132
•
sf incorpora directamente las librerías esenciales como GDAL para importar y exportar datos, GEOS para operaciones geométricas y el paquete Proj.4 para transformación entre proyecciones.
De la misma manera que sp, sf permite crear un objeto espacial a partir de un conjunto de pares de coordenadas. Es tan fácil como crear o leer un data.frame con las coordenadas de la localizaciones a representar y los campos adicionales que sean necesarios:
Se convierte entonces en un objeto espacial con la función st_as_sf() identificando qué campos contienen las coordenadas y qué proyección queremos asignarle (definiendo con el código EPSG o el proj4string). Además de consultar el tipo de objeto con class(), sf permite consultar el tipo de geometría con st_geometry().
Nota: Algunas funciones y métodos requieren el paquete liblwgeom, por ejemplo st_make_valid(), así como en todas las métricas esféricas o elipsoidales (área, distancia, etc.).
133
5.2.1 Importación La lectura de archivos, igual que con rgal, es muy sencilla. Podemos importar un shapefile de ESRI o cualquier otro archivo de datos vectoriales con la función st_read(). El objeto cargado en memoria tendrá una estructura de datos en formato tabla con una columna indicando el tipo de geometría espacial. Así que es posible trabajar con él como si fuese un data.frame, pero con la ventaja de tener toda la información espacial necesaria.
134
Los metadatos de los objetos sf nos resumen toda la información relevante del objeto espacial. En la cabecera veremos el tipo de clase (simple feature collection), el número de filas (features), el número de columnas (fields), el tipo de geometría (geometry type), las dimensiones (XY), la extensión (bbox) y la proyección (epsg, proj4string). Cuando imprimimos un objeto sf, R también resume los atributos.
En el caso de una geodatabase es necesario indicar el nombre del layer como argumento. Por defecto, importa el primer layer y da aviso en caso de que exista más de uno. La función st_layers() nos permite conocer los layers de una geodatabase.
5.2.2 Visualización Para representar espacialmente el objeto que hemos importado, podemos usar directamente la función plot(), que, al detectar que se trata de un objeto sf lo tratará de una manera diferente a la que conocemos de la clase sp; si el objeto tienen más de una variable (más de un campo en la tabla de atributos) y no especificamos nada más en la definición de la función, plot() creará una figura con tantos mapas como variables (por defecto, las 10 primeras), representando una a una y asignándole los intervalos de clase y color que considere más adecuados en función del tipo de variable (discreta o continua) y de su rango.
135
Si, por el contrario, queremos representar únicamente una variable del objeto, solo tenemos que definirla seleccionándola mediante su nombre dentro de la función.
136
5.2.3 Proyecciones y coordenadas Las funciones fundamentales para proyectar, extraer las coordenadas o extraer el sistema de coordenadas son: st_coordinates(), st_crs() y st_transform(). Para asignar una proyección es suficiente con indicar el código EPSG.
137
5.2.4 Acceso, manipulación y selección de variables Como sf interpreta los objetos espaciales como un data.frame, el acceso a las variables se hace exactamente igual.
La manipulación de los atributos de la clase sf es igual a la que conocimos con la colección de paquetes tidyverse. Una lista de funciones compatibles la encontramos en https://rspatial.github.io/sf/reference/tidyverse.html (esta vez no usamos el sufijo .sf). En el siguiente ejemplo modificaciones los atributos (variables) del objeto paises para crear una columna con el área, otra con la población y otra con la densidad de población:
La función select() nos permite seleccionar y extraer las variables que queramos y, en combinación con slice(), podemos extraer también filas (unidades espaciales) concretas.
138
139
Nota: Cuando usamos select() para seleccionar columnas, la columna que contiene la geometría se mantiene sin necesidad de especificarla.
5.2.5 Funciones de análisis espacial Para obtener una lista de todas las funciones disponibles del paquete sf podemos usar la siguiente función. Esta forma también es útil para otros paquetes con clases propias.
140
5.2.5.1
Unir tabla (Join)
Unir un objeto sf con otra tabla con nuevos atributos es fácil. Se usan las mismas funciones que aplicamos en el capítulo tidyverse.
Nota: Si queremos hacer un spatial join, podemos usar la función st_join() o st_intersection(). 5.2.5.2
Filtrado (Select by attributes)
La separación de elementos se realiza con la función filter(), mediante la cual podemos hacer una (o varias) selección(es) por atributos.
141
En ocasiones nos puede interesar ordenar los atributos en función de una variable, para lo que utilizamos, en combinación con select(), la función arrange().
142
5.2.5.3
Unión (Dissolve y Append)
En algunos objetos espaciales, por ejemplo los formados por múltiples polígonos, se permiten operaciones adicionales sobre los atributos a través de la función group_by(), equivalente a disolver polígonos según una variable. En este ejemplo, las funciones st_area() y set_units() sirven para calcular el área en las unidades definidas, respectivamente. En secciones sucesivas se explican de manera más detallada.
La disolución (dissolve), a diferencia de la unión (append), crea un nuevo y único polígono a partir de todos los polígonos que lo componen. La función summarise() define qué variables y con qué datos agregados se obtendrán como resultado.
143
También se puede usar la combinación entre la función group_by() y summarise() sin que esta última tenga argumentos, lo que provocaría la disolución sin la creación de nuevas variables. Si queremos disolver todos los polígonos de nuestro objeto espacial, podemos usar la función st_union(). No obstante, esta disolución provoca que perdamos el formato data.frame y pasemos a una clase sfc, que contiene únicamente la geometría.
144
Para volver a añadir variables tendríamos que aplicar la función st_sf().
En el mismo sentido, pero sin disolver límites internos, se puede aplicar la función st_combine().
145
Para unir diferentes objetos espaciales manteniendo los polígonos originales (append) usamos simplemente la función rbind(). Si quisiéramos unir diferentes geometrías o atributos, tendríamos que usar la función st_union(), lo que provocaría en caso de distintos tipos de geometrías una GEOMETRYCOLLECTION. En el siguiente ejemplo generamos un objeto con todos los países de Europa excepto Rusia y otro con todos los países de África.
Con rbind(), simplemente los unimos en un objeto nuevo. Hay que tener en cuenta que deben tener la misma estructura y geometría.
146
5.2.5.4
Intersección (Intersect, Clip)
Algunas de las funciones aplicables con sp y rgdal también están disponibles en sf. Por ejemplo, podemos aplicar funciones de intersección con st_intersection():
En este ejemplo se han añadido al objeto ciudades los atributos del objeto paises (el nombre del país) en aquellas localizaciones en las que había coincidencia espacial. Como funcionalidad extra, también es posible crear una sparse matrix, que no es más que un listado indicando qué índice de 147
la primera capa coincide con qué índice(s) de la segunda. En este ejemplo creamos una lista con los índices de los países, conteniendo cada uno de ellos los índices de las ciudades con las que se intersecan.
O, por ejemplo, podemos extraer los índices que se intersecan con un solo polígono. Aquí extraemos todas las ciudades que intersectan con el polígono correspondiente a Indonesia (todas las que están dentro de su territorio).
148
5.2.5.5
Diferencia (Difference)
Otras funciones, como la de diferencia (st_difference()), son muy versátiles en sf. Por ejemplo, si queremos obtener la diferencia entre dos geometrías igual que hacíamos con la función symdif() del paquete raster, podemos hacerlo de la siguiente manera: primero creamos un polígono con la dimensión de, por ejemplo, Francia:
Y ya podemos calcular la diferencia entre las dos geometrías:
149
150
De manera inversa, se puede extraer la geometría de una capa a partir de la de otra. Es lo mismo que la función intersect() o crop().
5.2.5.6
Cálculo de métricas espaciales
Una de las ventajas de trabajar con sf es que, en combinación con el paquete units, se pueden obtener y manipular las métricas espaciales sin tener que hacer cálculos adicionales. De manera muy intuitiva, la función st_area() calcula el área de un polígono o conjunto de polígonos de un objeto espacial en las unidades de la proyección, la cual podemos reconvertir con la función set_units():
151
La distancia entre puntos de un objeto espacial se calcula con st_distance(), dando como resultado un objeto de la clase units que contiene una matriz de distancias con el mismo número de filas y columnas que el número de puntos y una serie de atributos espaciales que identifican las unidades de medida.
Además, podemos calcular la distancia entre un par de coordenadas y todos los puntos de un objeto espacial. Esto puede ser útil, como en el ejemplo, para calcular la distancia (en línea recta) entre un punto concreto y todas las ciudades de nuestro objeto espacial.
5.2.5.7
Áreas de influencia (Buffer)
También es posible calcular áreas de influencia (buffers) alrededor de una geometría espacial (utiliza las unidades del sistema de coordenadas del objeto espacial). Si queremos calcular un área de influencia de 10 000 metros alrededor de un polígono concreto del objeto países, usaremos la función st_buffer().
152
Si, por el contrario, queremos estimar un buffer interior, simplemente debemos indicar la distancia con número negativo.
153
Cuando se usa un sistema de coordenadas decimales se obtiene un aviso de que el cálculo puede ser menos exacto o correcto. Por eso, proyectamos en este caso a un sistema UTM con la función st_transform(). Por defecto, la unidad usada en la distancia aquí también es la del sistema de coordenadas. 5.2.5.8
Cambiar el tipo de geometría
En objetos vectoriales es muy fácil cambiar entre distintos tipos de geometría (polígonos a línea, línea a puntos, etc.) con st_cast(). Esta función, combinada con las de métricas espaciales, puede dar resultados interesantes para el análisis espacial.
Nota: Los tipos básicos de geometría son: POINT, LINESTRING, POLYGON, MULTIPOINT, MULTILINESTRING, MULTIPOLYGON y GEOMETRYCOLLECTION.
5.2.6 Transformación entre formatos: sp, sf, data.frame Es posible que en ocasiones nos haga falta convertir entre la clase de sp, sf o data.frame. Veamos algunos ejemplos: podemos eliminar la geometría original de nuestro objeto paises, que es de polígonos, lo cual lo convierte en un simple data.frame que ya no podemos tratar como un objeto espacial porque hemos perdido las coordenadas (lon, lat), así que este objeto es irreversible.
154
Sin embargo, podemos hacer esa conversación manteniendo las columnas de las coordenadas con la función as.data.frame().
Ahora podemos aplicar la conversión de formatos con st_as_sf(), siempre que primero convirtamos el data.frame que acabamos de crear en un objeto espacial con as_Spatial().
5.3 Exportación de datos Tanto con rgdal como con sf, las opciones para exportar datos vectoriales son muy amplias. En rgdal se utiliza la función writeOGR() para escribir en archivo en diferentes formatos, que vienen definidos por el parámetro driver. Dependiendo de la configuración local y de las posibilidades de ciertos formatos (algunos son de solo lectura), se pueden exportar a unos o a otros. La función ogrDrivers() muestra un listado con todos los tipos de archivos vectoriales que rgdal es capaz de leer y escribir.
155
Nota: Excluimos la columna area en la escritura con writeOGR(), ya que no maneja objetos con unidades. Una alternativa sería convertir la columna en numérica con as.numeric(). En sf se utiliza la función st_write() y los tipos de formatos posibles son los mismos. En este caso no hace falta definir el driver si añadimos la extensión que tendrá el archivo.
156
6 Datos espacio-temporales II: ráster La información geoespacial en formato ráster representa la realidad como una matriz de celdas o píxeles, donde cada píxel toma un valor que corresponde a la realidad que está representando. Los objetos o capas ráster pueden ser de naturaleza discreta, por ejemplo cuando el valor de un píxel representa una categoría de uso del suelo, o de naturaleza continua, por ejemplo cuando los valores son niveles digitales representando la reflectividad en una imagen de satélite. De la misma manera que con los geodatos vectoriales, R también es capaz de abordar cualquier análisis espacial en formato ráster. El paquete raster, sin duda, es el más popular y versátil de todos para esta tarea, aunque, de nuevo, sf viene a sustituir muchas de las funciones existentes y añade otras que pueden ser muy útiles en situaciones determinadas.
6.1 Creación de objetos ráster R interpreta a los objetos ráster como una matriz de n filas y n columnas a las que asigna los valores de latitud y longitud correspondientes y un sistema de coordenadas. Si queremos crear un objeto ráster vacío, por defecto el paquete raster compone una matriz con las dimensiones del mapa global (180 latitudes y 360 longitudes), le asigna las coordenadas (de -90 a 90 y de -180 a 180) y la proyección WGS84.
Para hacerlo más flexible, podemos introducir estos parámetros por nosotros mismos y comprobar, según lo que definamos, cuál es la resolución del ráster con la función res().
Si cambia la resolución, también cambiarán las dimensiones de nuestro ráster para adaptarse a ella. Además, podemos asignarle el sistema de coordenadas con la función projection() y los valores que consideramos.
157
La función plot() interpreta el objeto como ráster y lo representa junto a una leyenda con el rango de valores presentes en el mapa.
6.2 Importación Cargar en el entorno de trabajo un archivo ráster es muy sencillo con la función raster(), que crea un objeto RasterLayer leyendo sus dimensiones resolución, coordenadas exteriores, proyección e información sobre la ruta del archivo.
Nota: Es importante indicar que raster no importa los datos a la memoria, sino que se conecta a través de la ruta del archivo. Únicamente cuando manipulamos el ráster se convierte en un objeto 158
en memoria, lo que se indica en los metadatos con source: in memory. Cuando un ráster es demasiado grande, es posible usar la función getValues() indicando la fila para importar solo una parte. Para un primer análisis visual de los datos hay muchas opciones de visualización en pantalla, desde una simple gradación de colores basada en los valores (image()) hasta mapas más completos incluyendo leyendas con categorías y paletas de color personalizables (plot(), spplot()). También es posible crear mapas de contornos o isolíneas simples (contour()) o con colores de relleno sólidos (filledContour()).
159
En este caso, como nuestro ráster representa las temperaturas de la superficie del mar (SST) mundiales, es útil añadir los límites administrativos de los países para tener una referencia conocida. Para hacer esto, o bien podemos cargar una capa vectorial con esta información y añadirla al mapa en cuestión, o bien podemos usar el paquete rnaturalearth, que tiene límites administrativos de diferentes resoluciones y escalas. Este paquete descarga e importa automáticamente cartografía
160
digital de http://www.naturalearthdata.com con las funciones ne_countries(), ne_states() o ne_download().
161
El paquete raster también incluye función getData() para acceder directamente a diferentes datasets geográficos, espacialmente de tipo raster, como modelos digitales de terreno con 90 m de resolución (SRTM90), límites administrativos (GADM) o datos climáticos (Worldclim).
162
163
Si nuestro objeto ráster estuviese compuesto de varias capas (RasterStack), como en una imagen multibanda, podríamos representarlas todas de la misma manera. Otras veces tenemos una sola banda, pero nos interesa crear nuevas a partir de ella y almacenarlas en un solo objeto. Por ejemplo, podemos crear dos objetos ráster nuevos a partir de la SST original añadiendo 2 y 4 grados centígrados, respectivamente. Como R trata a los ráster como si fuesen matrices, las operaciones matemáticas se pueden aplicar de la misma manera; simplemente, sumamos los valores deseados:
Para unir los tres objetos en uno solo convertimos los RasterLayer originales en una RasterStack, es decir, en una superposición de capas:
Y podemos representar estas tres capas de un solo objeto al mismo tiempo. Esta vez creamos una leyenda más acorde a los datos, intentando que todos queden bien representados. Como en este caso queremos representar un objeto con tres capas, si queremos tener la referencia de los países, no es suficiente con usar la opción add = TRUE que habíamos empleado hasta ahora. Necesitamos crear una función que añada esos límites cada vez que se cree el gráfico de cada capa. Esa nueva función la añadiremos como argumento addfun en la función plot().
164
6.3 Funciones de análisis espacial 6.3.1 Álgebra ráster Cuando leemos un archivo ráster desde archivo o creamos uno nuevo, R lo interpreta como si fuese un array multidimensional con atributos. Esto quiere decir que podemos aplicar cualquier operación matricial que queramos. Ya hemos visto que podemos sumar directamente un número fijo a todos los valores tanto de cada uno de los ráster de manera independiente como de todo el RasterStack en conjunto. Además, podemos aplicar otras funciones predefinidas y usar funciones de reemplazo. En este caso, nuestro RasterStack tiene tres dimensiones (latitud, tiempo/variables/etc.), que se organizan como si de un array se tratase (x, y, z).
longitud,
165
Las funciones summary (min(), max(), mean(), prod(), sum(), median(), cv(), range(), any(), all()) siempre devuelven un objeto RasterLayer.
166
Usando cellStats() obtenemos el valor individual, en lugar de un valor por cada píxel, es decir, aplica la función deseada a todos los píxeles de cada capa del RasterStack.
6.3.2 Extraer información con objetos espaciales (Extract to geometry) En ocasiones, nos interesa extraer la información de los ráster a localizaciones concretas: esto podemos hacerlo con la función extract() del paquete raster, que nos permite extraer valores a puntos, polígonos o líneas. En los siguientes ejemplos vamos a ver cómo extraer los valores del ráster a diferentes geometrías: 1) Extraemos la temperatura máxima de enero para las ciudades del mundo: la función extract() hace todo el trabajo y nos devuelve un vector con la información extraída para cada punto.
167
2) Extraemos para Portugal y España los valores de temperatura máxima: en esta ocasión el procedimiento es diferente, ya que el tipo de resultados también puede ser diferente. En el primer caso, la función extract() aplicada sin opciones adicionales devuelve una lista de dos elementos (España y Portugal), con el listado de valores que corresponden a los píxeles del Rasterlayer que cubre.
Podemos aplicar una función para calcular una estadística sobre los resultados de esa lista:
Hasta ahora hemos extraído solamente los datos de la primera capa (primer mes) del objeto wctmx de temperaturas máximas. Pero ¿cómo extraemos la información de todas las capas? El procedimiento es exactamente igual excepto que esta vez no definimos la primera capa, ponemos el nombre del objeto sin más. El resultado ahora será una lista de matrices, cada una de ellas corresponderá a un país y las columnas coincidirán con las capas (los meses).
168
6.3.3 Modificando el aspecto del ráster Podemos cambiar el tamaño del ráster que queremos mostrar. Por ejemplo, con la función crop() podemos recortar un ráster existente en función de otro raster o de cualquier objeto de la clase Spatial del paquete sp.
La función crop() recorta toda la extensión del objeto que usamos como recorte. Si queremos recortar el ráster en función de una geometría vectorial podemos hacerlo con la función mask().
169
Con la función trim() se eliminan las filas y columnas externas que contengan NAs, al contrario que con extent(), que nos sirve, precisamente, para añadir el número de filas y columnas con NA que queramos. Con la función merge() podemos unir dos o más ráster en un nuevo objeto. El único requisito es que los objetos de entrada deben tener la misma resolución y origen, es decir, que sus celdas han de encajar una con otras.
6.3.4 Funciones locales Las funciones focales funcionan solo con Rasterlayers (una sola banda/capa). Utiliza las celdas vecinas para aplicar una función focal. El usuario tiene que definir una matriz de pesos.
170
171
También se puede utilizar la función boundaries() para detectar los bordes en un ráster. Esta función crea una matriz de pesos que enfatiza los valores de los bordes. Estos se dibujan siguiendo las celdas que tienen más de una clase en las direcciones (4 u 8) colindantes.
6.3.5 Cambio de resolución Cambiar la resolución de un ráster implica crear una matriz con diferente número de filas y columnas, y, por tanto, los valores asignados a estos nuevos píxeles serán también diferentes. La función aggregate() del paquete raster permite crear un nuevo objeto espacial ráster agrupando áreas (rectangulares) para crear celdas/píxeles de mayor tamaño. El argumento fact indicará el número de celdas que se agregarán en cada dirección, mientras que fun determinará la función que se aplicará sobre los valores de los píxeles agregados (por defecto, el promedio).
También podemos aumentar la resolución con la función dissagregate(), que actúa de manera inversa. Esta vez los valores de los nuevos píxeles creados con el parámetro fact serán exactamente los mismos que los originales, excepto si especificamos method = "bilinear", en cuyo caso utilizará una interpolación bilineal.
172
6.3.6 Reclasificación La reclasificación es muy útil cuando trabajamos con un ráster cuyos valores son de naturaleza continua y queremos hacer agregados espaciales en función de rangos de valores predefinidos. Podemos aplicar un método sencillo de reclasificación mediante la función reclassify(). Tan solo tenemos que crear un vector con al menos tres elementos, que corresponderán al valor mínimo y máximo del rango de valores que queremos reclasificar, y el valor por el que se va a sustituir respectivamente. En el siguiente ejemplo usamos el producto MOD13Q1, que representa el NDVI calculado por MODIS a una resolución espacial de 250 metros para toda España.
173
Para reclasificar debemos crear un vector que sea convertible a una matriz de tres columnas, siendo el significado de cada una el siguiente: desde, hasta y nuevo valor. La matriz se crea por fila, lo que significa que en el vector creado los primeros tres elementos son la primera fila de la matriz.
Ahora solo hace falta aplicar la función reclassify() con el ráster y el vector de la reclasificación.
174
6.3.7 Variables topográficas Las variables topográficas suelen ser muy habituales cuando disponemos de un Modelo Digital de Elevaciones (MDE), es decir, un ráster cuyos píxeles representan altitudes respecto al nivel del mar. De estas variables, las más comunes son la pendiente y la orientación. Si tenemos información de nuestra área de estudio pero nos falta el MDE correspondiente, podemos obtenerlo del paquete elevatr con la función get_elev_raster(). Esta función necesita que le proporcionemos como entrada las coordenadas de un rectángulo o bbox, o bien una geometría ráster. Internamente se conecta Amazon Web Services (AWS) para descargar la tesela de MDE que corresponda a las coordenadas que le pasamos.
Tanto el cálculo de las pendientes como de las orientaciones se hace con la función terrain(), incluida en el paquete raster. Entre ambas tan solo cambia la opción slope o aspect. La función también permite personalizar las unidades de salida del cálculo y el número de vecinos (número de píxeles circundantes) que utilizará para hacer el cálculo.
175
6.3.8 Otras funciones Desde un ráster en R podemos crear también otro tipo de objetos espaciales, como puntos, líneas o polígonos. Por ejemplo, es interesante crear un mapa de isolíneas a partir de los valores originales usando la función rasterToContour().
176
Podemos transformar ráster en puntos con la función rasterToPoints(), que genera una matriz con las coordenadas de cada celda y el valor del píxel correspondiente, o bien con la función as.data.frame() con el parámetro xy = TRUE, que devolverá exactamente lo mismo, pero esta vez en forma de data.frame.
177
En ocasiones puede ser interesante convertir el ráster en un objeto espacial vectorial en forma de polígonos. En el siguiente ejemplo vamos a reclasificar (con la función reclassify()) nuestro mapa de la temperatura máxima del norte de Sudamérica en tres categoría: menos de 25°C, entre 25 y 30°C y más de 30°C. A continuación utilizamos la función rasterToPolygons() para crear una geometría vectorial de polígonos definiendo el argumento dissolve = TRUE con el fin de que una en un solo polígono todas las celdas con el mismo valor.
Para conocer más sobre otras funciones disponibles puede consultarse la vignette del paquete raster: https://cran.r-project.org/web/packages/raster/vignettes/Raster.pdf.
6.3.9 Reproyección del ráster En ocasiones nos interesa reproyectar el objeto ráster con el que estamos trabajando, bien para que encaje con otros objetos ráster, bien porque nos interesa otro tipo de representación. La función projectRaster() se encarga de transformar la información de la proyección de un objeto ráster en otra que nosotros definamos. Para asegurarnos de que estamos haciendo bien el proceso, tenemos que utilizar las definiciones oficiales de las proyecciones a través de la función CRS() del paquete rgdal(). En el siguiente ejemplo leeremos de nuevo nuestro dataset de temperaturas superficiales del mar y le asignaremos la proyección de Mollweide (https://es.wikipedia.org/wiki/Proyeccion_de_Mollweide), que intenta representar la superficie terrestre de la manera más proporcional posible. Haremos lo mismo con los límites vectoriales de los países vectoriales de los países que habíamos extraído del paquete rnaturalearth al principio 178
de este capítulo. Como se trata de un objeto vectorial, tendremos que usar la función spTransform().
Nota: A veces encontramos datos ráster globales donde la longitud se extiende desde 0 a 360°, en lugar de -180 – 180°. Para lidiar con ello en R, se puede usar la función ratate() para transformar un ráster en -180 – 180°.
179
6.4 Exportación de datos La función writeRaster() nos permite exportar nuestro objeto ráster a varios formatos dependiendo de nuestras necesidades y del software posterior en el que haremos la visualización.
180
7 Visualización de datos espaciales 7.1 Representación cartográfica con ggplot2 En capítulos anteriores hemos visto las posibilidades y funcionalidad del paquete ggplot2. Ahora ampliaremos los aspectos relacionados con la representación cartográfica utilizando algunas de esas funciones y otras nuevas. La combinación de la gramática de ggplot2 con la gestión de la información espacial que hace sf produce un lenguaje de visualización muy intuitivo y escalable (podemos añadir funciones de representación sin modificar lo anterior). Esta interacción se lleva a todos los tipos de geometrías en el paquete de ggplot2. Si decidimos trabajar con datos espaciales de clase sp, ggplot los tratará de forma diferente, ya que no tienen la estructura de un data.frame per se, y tenemos que hacer algo de trabajo extra. Para ilustrarlo con un ejemplo sencillo, cargamos los paquetes tidyverse, sp y sf y leemos un dataset que contiene información sobre los husos horarios.
181
Cuando visualizamos la geometría en formato sf solo tenemos que indicarlo con la función geom_sf() pero, si utilizamos sp, tenemos que definir las coordenadas y el tipo de representación y agrupamiento.
182
Nota: En los gráficos y también aquí con los mapas, ggplot amplía por defecto el área del gráfico. Este comportamiento no es habitualmente un problema, pero, cuando visualizamos datos globlaes, sí lo es. Para un mapa de todo el mundo no tiene sentido ir más allá de los ±180° o ±90°. De ahí el uso del argumento de expand = FALSE es la función coord._sf(). Para objetos de la clase sp la creación es más compleja. geom_sf() proyecta correctamente de forma automática, mientras que en sp es necesario añadir coord._map() o coord._quickmap() para que mantenga la proyección adecuada.
183
Como la función ggplot necesita procesar los datos en formato data.frame, lo que hace cuando recibe un objeto sp es usar la función fortify() para convertir los polígonos en este formato y así poder representarlos correctamente.
Esta función solo opera con polígonos o líneas y tiene el inconveniente de no incluir los atributos del objeto espacial original. Si los queremos, tendríamos que unir la tabla de atributos con la nueva tabla que hemos creado fortify() a través de la columna id. En el caso de las geometría se puntos, simplemente convertimos el objeto sp con la función as.data.frame() usando el argumento xy = TRUE para obtener un data.frame con las coordenadas.
7.1.1 Ejemplo: Mapa de accesibilidad media por carretera Vistas las ventajas de geom_sf(), usaremos esta función en los siguientes ejemplos. En este caso importamos una geometría vectorial con las provincias de España, que contienen datos sobre la accesibilidad a los núcleos de población en 2015. Estos datos representan, en minutos, el promedio y la varianza de los tiempos de recorrido por carretera entre los núcleos de población (> 1500 habitantes por km2) de cada provincia.
184
Para cambiar el color de los límites provinciales a blanco definimos, dentro de la función geom_sf(), el parámetro colour = "White".
185
Y para cambiar la gama de colores de la variable usamos el paquete RColorBrewer, que contiene escalas de color predefinidas ampliamente utilizadas en cartografía (ver colorbrewer2.org). La función brewer.pal permite seleccionar el número de colores y la escala. Ponemos la leyenda en la parte inferior del gráfico con el parámetro legend.position = "bottom": consulta la ayuda de la función theme() y verás que tiene decenas de parámetros para modificar el aspecto del gráfico.
En ggplot también existe la posibilidad de modificar la leyenda con la función guides(). En ese caso tendríamos que usar los parámetros de aes() (fill, size, colour, shape, etc.) para configurar la leyenda con datos continuos guide_colourbar() o con datos discretos guide_legend(). En la función guide_colourbar() se especifican varios elementos de estilo, desde la posición de las etiquetas hasta la anchura de la barra.
186
Al usar la clase sf no solo podemos emplear la función de geometría geom_sf(), sino también coord._sf(), que nos sirve para definir la proyección o limitar el área de visualización. Es decir, que es posible ajustar la proyección deseada en el proceso de la visualización sin tener que modificar los objetos espaciales originales.
187
Por ejemplo, podríamos proyectar, en el proceso de visualización, un mapa global a la proyección eurocéntrica LAEA (ETRS89 Lambert Azimuthal Equal-Area).
188
7.1.2 Ejemplo: Mapas de nubosidad en Galicia En este capítulo crearemos dos mapas con la nubosidad media de marzo de 2018 y el promedio de marzo en el periodo 2001-2018. Primero leemos la geometría vectorial con los límites de la región de Galicia (España).
El polígono importado es multipolígono de tipo XYM. Existen dos tipos de multipolígonos con una tercera dimensión XYM y XYZ. Los primeros hacen referencia a coordenadas con una tercera medición en cualquier unidad, mientras que los segundos siempre se refieren a coordenadas con altitud. Como estos formatos no pueden procesarlos todas las funciones que vamos a utilizar, usamos st_zm() para transformarlos en XY, eliminando la tercera dimensión. Por otro lado, el sistema de coordenadas de nuestra geometría vectorial es UTM, pero, como los ráster que usaremos a continuación están en WGS84, reproyectamos los límites con la función que ya conocemos st_transform().
Usamos el límite de Galicia para hacer una máscara de los ráster que contienen la nubosidad de toda la península ibérica. Como los ráster originales contienen más de 3 millones de puntos, el proceso es más lento y requiere algunos minutos. Es importante recordar que la función crop() recorta a la extensión requerida (coordenadas mínimas y máximas) y mask() convierte todos los valores fuera de una máscara (límite) en valores NA.
189
Para trabajar en ggplot2 con una geometría ráster debemos convertirla, igual que con el resto de formatos, en un data.frame con las columnas x, y, z. Para ello usamos la función as.data.frame() con el argumento xy = TRUE. Si queremos excluir los valores NA para aligerar el tamaño del objeto resultante, podemos indicarlo con na.rm = TRUE. Un ráster contiene por defecto muchos valores NA que sirven para rellenar el grid regular de la extensión geográfica total. Debemos tener cuidado al excluir estos valores, ya que también podría tratarse de valores ausentes.
190
Para representar el ráster con ggplot2 utilizamos la función geom_tile(). Nota: En ggplot2 existe una función geom_raster(), que es un caso especial de geom_tile(). La diferencia entre ambas es que geom_raster() asume píxeles del mismo tamaño y un grid regular completo.
Respecto a coord_map(), la función puede resultar lenta, por eso es recomendable usar coord_quickmap() cuando se pretende obtener un resultado rápido. En el mapa anterior usamos 191
una escala continua; no obstante, sería mejor categorizar la fracción de nubosidad para obtener una mejor diferenciación visual. Para ello aplicamos la función ClassIntervals() del paquete ClassInt, que nos permite crear un número determinado de clases a partir de una variable continua con diferente método de estimación (kmeans, jenks, equal, etc.). En este ejemplo creamos 12 clases con el método K-Means:
Creamos dos paletas de color, una de grises (seis colores de gama negro/blanco) y otra de azules (seis colores de gama azul/blanco), que combinamos al construir nuestro mapa con ggplot.
192
Nota: con scale_fill_manual() definimos los colores para las 12 clases de nubosidad (seis de colores blanco-azul y seis blanco-negro). El orden de la gama de Brewer es de tonos claros a oscuros, por eso, revertimos los azules para que comiencen por los oscuros. Si queremos añadir el límite de la región de Galicia, tenemos que cambiar la forma de escribir la función anterior. La función aes(), que antes habíamos incluido dentro de ggplot(), la cambiamos ahora a geom_tile(). Además, como necesitamos usar geom_sf() para los límites, tenemos que sustituir la función coord_quickmap() por coord._sf().
193
También tenemos la opción de añadir algunos elementos extra propios de una cartografía: norte y una escala. Para ello utilizamos el paquete ggsn, que contiene las funciones north y scalebar con multitud de parámetros, desde el tipo de símbolo para el norte hasta las unidades y sistema de proyección para la escala.
194
Si quisiéramos crear un gráfico múltiple con nuestros dos datasets de nubosidad, podríamos hacerlo, pero nos haría falta una nueva columna que identificase a cada mapa y que sirviese para unir los dos data.frames. En nuestro caso la denominamos map y contendrá en ambos supuestos (2018 y promedio 2001 – 2018) los datos de nubosidad.
Ahora ya podemos unir los dos data.frame con la función bind_rows().
195
Y usamos la función classIntervals() para crear doce clases con las que categorizar la nubosidad, igual que lo hemos hecho antes.
Ya podemos representar ambos mapas:
196
Es importante tener en cuenta cómo se categoriza o compara una variable con otra para representarla correctamente en un mapa. En función del objetivo puede ser útil aplicar diferentes métodos: https://beta.observablehq.com/@hbostock/methods-of-comparison-compared.
7.1.3 El paquete ggspatial El paquete ggspatial es muy útil a la hora de trabajar con datos espaciales en ggplot2. En un único paquete podemos encontrar funciones para cartografiar objetos de clase sp, sf y raster. Además, tenemos a nuestra disposición funciones para añadir la escala, el norte, o incluso mapas de fondo en teselas. La función general para todos los objetos espaciales es layer_spatial(), en la que definimos los argumentos como habitualmente lo hacemos en ggplot. 7.1.3.1
Imágenes RGB
Para representar una imagen RGB con ggplot2, primero importaremos nuestro ráster multibanda con la función stack() (el dataset contiene tres capas para Red, Green y Blue, respectivamente). En este ejemplo usamos datos de MODIS correspondientes al 14 de abril de 2019, exportados desde la página web: worldview.earthdata.nasa.gov. La función plotRGB() del paquete ráster hace una primera visualización de nuestro dataset.
197
Cargamos en nuestro espacio de trabajo los límites regionales y los usamos como apoyo en ggplot. Utilizamos layer_spatial() tanto para la geometría vectorial como para el ráster.
198
7.1.3.2
Escala y norte
En lugar de usar las funciones del paquete ggsn, es posible añadir el norte y la escala con annotation_north_arrow() y annotation_scale() de ggspatial. Emplearemos el objeto creado anteriormente con la nubosidad media de Galicia.
199
7.1.3.3
Mapas de fondo en teselas
ggspatial incluye la función annotation_map_tile(), que permite completar el mapa con fondos provenientes de servidores de mapas en teselas. La función usa estilos de mapas de Open Street Maps que podemos ver usando la función rosm::osm.types().
200
7.1.3.4
Ráster
El manejo de datos ráster es más fácil con ggspatial, ya que no es necesario pasar el ráster al formato x, y, z. No obstante, en la actualidad no permite categorizar el ráster a través de la misma función.
201
7.1.4 El paquete ggmap El paquete ggmap tiene funcionalidades muy valiosas cuando queremos usar mapas de fondos en teselas. No solo tenemos acceso a mapas con diferentes estilos de Open Street Maps o Stamen Maps, sino que también podemos hacer uso de funciones para conectarnos con servicios de Google. Este último supone una pequeña limitación, ya que es necesario tener una clave para acceder a los diferentes API. Para obtener esta clave se pueden consultar unas sencillas instrucciones en el repositorio de Github de ggmap: https://github.com/dkahle/ggmap. En el siguiente ejemplo definimos la extensión o bbox de EE.UU. en la forma de un vector c(left, bottom, right, top) y descargamos de internet el mapa de base que corresponde al interior de esas coordenadas. La función get_stamenmap() permite descargar el mapa de Stamen Map. Debemos indicar al menos la extensión (que definimos con el bbox), pero además es posible especificar el nivel de zoom (0: global hasta 18: local) y el estilo del mapa. Cualquier mapa de fondo en teselas se visualiza con la función ggmap() sustituyendo a ggplot().
202
Las funciones geocode() (del paquete ggmap) y geocode_OSM() (del paquete tmaptools) (servicio de Google y OSM) permiten obtener las coordenadas para lugares o direcciones, lo cual es muy útil si no disponemos de ellas.
203
Ejemplo: Contaminación urbana En este ejemplo utilizamos las coordenadas de tres estaciones de contaminación de la ciudad de Madrid. Haremos un mapa de localización de estas estaciones con un fondo de terreno. Primero creamos un data.frame con las coordenadas y el nombre de la estación de contaminación. Después lo convertimos en un objeto de clase sf.
En el segundo paso, descargamos del mapa de fondo la bbox indicaba como vector con el nivel de zoom 12.
Para visualizar el mapa usamos la función ggmap() con el objeto map_base que acabamos de descargar. La función layer_spatial() nos ayudará a añadir las estaciones, pero debemos usar como argumento inherit.aes = FALSE para que los datos vectoriales sobreescriban el sistema de coordenadas del mapa de base. Con geom_spatial_label_repel() (del paquete ggrepel) etiquetaremos los puntos con los nombres que hemos definido previamente. Hoy día, la función para añadir etiquetas no maneja objetos de clase sf, por eso tenemos que definir el data.frame original. Por último, el argumento box.padding define la distancia entre el punto y la etiqueta.
204
7.2 El paquete tmap El paquete tmap es una interesante alternativa a ggplot2. Se trata de un paquete de funciones especializadas en crear mapas temáticos. La filosofía del paquete sigue la de ggplot2, creando múltiples capas con diferentes funciones que siempre empiezan con tm_* y se combinan con +.
7.2.1 Ejemplo: Presas según tipo de uso Para el siguiente ejemplo utilizamos datos de resourcewatch: https://resourcewatch.org/data/explore/Global-Reservoir-and-Dam-GRanD. Se trata de un dataset de presas a nivel global con múltiples características. La variable que investigamos es el tipo de uso principal que tiene cada presa.
205
Importamos el dataset y hacemos una primera inspección visual de los datos.
206
Creamos un gráfico con el número de presas por tipo de uso, para lo que contamos el número de presas excluyendo NAs.
207
Y hacemos un gráfico de barras, que parece ser el más adecuado para visualizar el ranking de usos más comunes.
208
Para hacer el mapa de las presas por tipo de uso combinamos dos mapas previos: una representación de los países del mundo y sus límites y el mapa temático de las presas por tipo de uso principal. Para el primero usamos los límites que ya hemos visto previamente del paquete rnaturalearth.
209
Para el segundo usamos tm_shape() para incluir el dataset de las presas, cuya geometría modificaremos con tm_dots(), y representarlo con las propiedades temáticas que queremos. La función tm_layout() nos servirá para definir la posición de la leyenda y la ausencia de un marco envolvente.
Ahora solo falta unir ambos mapas:
Treemaps Los treemaps no son mapas en sí, pero resultan muy útiles como visualización de datos espaciales jerárquicos y anidados. Vamos a ver un ejemplo con los datos del mapa anterior, pero restringidos a las preas de Europa. Primero seleccionamos los límites correspondientes: los países del continente europeo sin incluir a Rusia, ya que su tamaño descompensaría el mapa final.
210
st_intersection() servirá para seleccionar los puntos únicamente dentro de los límites elegidos.
Para crear el treemap tenemos que agrupar los datos por país y tipo de uso.
Usamos la función geom_treemap() del paquete treemapify, que nos va a permitir crear este tipo de visualización. Más funcionalidades en: https://github.com/wilkox/treemapify.
211
El gráfico muestra un rectángulo para cada país cuyo tamaño depende del número de presas que contiene. A su vez, estos rectángulos están subdivididos en otros que representan el número de presas por tipo de uso para cada país.
7.2.2 Ejemplo: Representación del estrés hídrico Vamos a ver un ejemplo de representación del estrés hídrico o déficit de agua a diferentes escalas espaciales. Los datos provienen de nuevo de resourcewatch (https://resourcewatch.org/data/explore/wat001-Baseline-Water-Stress). Se trata de un dataset sobre estrés hídrico a nivel global con múltiples características. Leemos los datos y hacemos un primer análisis exploratorio visual:
212
213
El mapa representa el nivel de estrés hídrico global categorizado desde 1 (bajo) hasta 5 (extremadamente alto). Incluye datos faltantes (No data). Limitamos los datos a la península ibérica usando st_intersection().
214
El objetivo es obtener el área total de cada nivel de estrés para la península ibérica. Para ello: 1) seleccionamos únicamente la columna que nos interesa (BWS_cat), 2) estimamos el área de cada nivel de estrés, 3) cambiamos las unidades de m2 a km2 y 4) agrupamos por el nivel de estrés y área.
215
El gráfico muestra una clara dominancia del nivel 4, seguido del 5 y el 3, lo que supone que nuestra área de estudio está bajo un estrés hídrico de medio a extremadamente alto. Pero vamos a ver los resultados en forma de mapa. Usaremos la proyección Robinson. Para poder limitar el área debemos conocer las coordenadas en metros de esa proyección. Lo más fácil en este caso es definir dos puntos que definan el área (p. ej.: esquina abajo-izquierda arriba-derecha) en el sistema WSG84 y convertirlo en un objeto de sf. Después, simplemente lo reproyectamos y obtenemos las coordenadas.
En los próximos pasos, únicamente nos hace falta: 1) obtener el mapa de fondo, 2) definir los colores para las clases y 3) crear el mapa en dos partes, de las que la primera parte será el mapa en sí con 216
la proyección Robinson y los límites del área de visualización y la segunda será los cambios de elementos de estilo y la agregación de la escala y el norte.
217
7.2.3 Ráster en tmap tmap tiene una clara ventaja a la hora de visualizar objetos de clase ráster. No solo disponemos de la función tm_raster() para añadir una capa de esta clase, sino que esta misma función nos permite categorizar directamente los datos indicando el número de grupos y el método.
En este otro ejemplo usamos datos de un modelo digital de terreno descargado con la función getData() del paquete raster. Esta función descarga la tesela correspondiente a la ubicación del par de coordenadas que proporcionamos.
218
219
Nota: Para cambiar el separador o el número de decimales debemos usar el argumento legend.format = list(text.separator = "a", digits = 0) dentro de la función tm_loyout().
7.2.4 Exportación con tmap Para exportar un mapa realizado con el paquete tmap, simplemente debemos indicar el objeto en el que habíamos introducido el mapa hecho en tmap y la ruta donde queremos escribirlo.
7.3 Mapas interactivos 7.3.1 El paquete mapview El paquete mapview, que se basa en la librería leaflet de Javascript, es una herramienta muy potente para visualizar de forma rápida y dinámica un ráster o datos vectoriales en R. Es muy útil para inspeccionar de manera interactiva datos espaciales.
Después de cargar una geometría sf, usamos directamente la función mapview para hacer nuestro mapa interactivo.
220
Que también funciona con datasets ráster:
Nota: El paquete tiene más opciones y funcionalidades que pueden ser consultadas en https://rspatial.github.io/mapview/index.html. 221
7.3.2 Leaflet x Leaflet es una biblioteca de código abierto de JavaScript muy popular para crear, entre otros, mapas interactivos. Es utilizado por sitios web como The New York Times, pero también por especialistas en SIG como Open Street Map, Mapbox y CartoDB. El paquete correspondiente en R permite, sin experiencia previa en Javascript, crear un mapa interactivo de forma sencilla. La construcción empieza por la función leaflet(), a la que añadimos por capas más elementos como por ejemplo addTiles(), que incluye el fondo de un mapa. La combinación de todos los elementos se realiza por el uso del ya conocido pipe (%>%). En RStudio los resultados aparecen en la ventana Viewer.
Es posible añadir diferentes proveedores de mapas con la función addProviderTiles() indicando el nombre de estilo. La función setView() fija el área visual del mapa mediante la coordenada central y un nivel de zoom predefinido.
222
Existen otros muchos ejemplos de ProviderTiles en https://leaflet-extras.github.io/leafletproviders/preview/. Añadir datos espaciales de clase sf, sp o raster también es muy sencillo. Podemos importarlos o crearlos, como en el siguiente caso, en el que generamos seis puntos correspondientes a seis ciudades españolas. La función addTiles() añade el mapa de fondo, que usa por defecto Open Street Maps. Si pasamos el cursor sobre las localizaciones, aparecerán los nombres de las ciudades como etiquetas emergentes.
La enorme versatilidad de leaflet nos permite también añadir elementos de control o panel de control, desde el que controlar algunas propiedades del mapa, como la visualización de diferentes capas temáticas de fondo u objetos espaciales presentes en el mapa. Por ejemplo, podemos añadir todas las capas de proveedores de estilos que queramos y usamos la función addLayersControl() para indicar el grupo de control de mapas base y el control sobre la capa de ciudades.
También podemos crear mapas dinámicos, por ejemplo, para visualizar la varianza en la accesibilidad por provincias, tomando los datos de un ejemplo anterior en este capítulo. Para construir el mapa: 1) importantes los datos en formato shapefile de ESRI, 2) creamos una función que defina los colores y clases, usando percentiles y, finalmente, 3) creamos el mapa empleando la función addPolygons(), donde definimos la transparencia, el color, la variable y la etiqueta. La función addLegend() nos permite añadir la leyenda, que únicamente requiere la información de la variable y los colores.
223
Nota: También podemos incluir datos de ráster con la función addRasterImage(). El paquete tmap tiene una función específica, tm_leaflet(), para convertir un mapa creado con el mismo paquete en un mapa dinámico de leaflet. También es posible crear clusters dinámicos de puntos. Se trata de agrupaciones espaciales de puntos donde, cuando interactuamos con ellas, se amplía el área espacial visualizada y cambia la agrupación. Simplemente, en la función addMarkers() añadimos el argumento clusterOptions = markerClustersOptions(). Veamos un ejemplo sencillo con la capa de ciudades del mundo que utilizamos en el capítulo de análisis vectorial.
224
7.3.3 Exportación de mapas dinámicos A pesar de que no lo hemos visto directamente, leaflet crea en un archivo html que utiliza para visualizar en la ventana Viewer de RStudio. Existen dos opciones para exportar un mapa de estas características. 1) RStudio nos da la posibilidad de publicar en internet los resultados obtenidos como un gráfico estático o como un sistema dinámico. En la ventana de Viewer encontramos la opción Publish, que abrirá una ventana para elegir entre RPubs http://rpubs.com/ (gratuito) o RStudio Connect https://www.rstudio.com/products/connect/ (de pago). Por ejemplo, http://rpubs.com/Xeo81/ej_leaflet. 2) Podemos usar el paquete htmwidgets para exportar el mapa como html. Una vez exportado, podemos abrirlo en cualquier navegador web o guardarlo en un servidor de nuestra elección y hacerlo accesible a cualquier persona.
Nota: Un paquete interesante que amplía las funcionalidades básicas de leaflet es el paquete leaflet.extras (github.com/bhaskarvk/leaflet.extras). Actualmente se encuentran en desarrollo multitud de paquetes para poder visualizar grandes datasets espaciales.
225
8 Casos prácticos 8.1 Visualización del crecimiento urbano La Dirección General del Catastro de España dispone de información espacial muy precisa. La implantación de INSPIRE (https://inspire.ec.europa.eu/), la Infraestructura de Información Espacial en Europa, ha proporcionado acceso, entre otros, a datos sobre la edificación de todos los municipios en España (a excepción de País Vasco y Navarra, que tienen catastros propios). Toda la información utilizada en este caso práctico la podemos encontrar en http://www.catastro.meh.es/webinspire/index.html. Utilizaremos los enlaces (urls) en formato ATOM, que es un formato de redifusión de tipo RSS, permitiéndonos obtener el enlace de descarga del municipio requerido. Aunque necesitamos más de uno, el único paquete nuevo que introducimos aquí es feedeR. Nos permitirá importar la información de un feed, un medio de redifusión de contenido web.
8.1.1 Importación de datos La primera url nos dará acceso a un listado de provincias con nuevos enlaces RSS los cuales incluyen los enlaces finales de descarga para cada municipio. Descargaremos el edificado de Santiago de Compostela, Lérida, Granada y Santander. 226
Accedemos y descargamos los datos de Santiago de Compostela, en la provincia de La Coruña:
227
Accedemos y descargamos los datos de la ciudad de Lleida, en la provincia del mismo nombre:
Accedemos y descargamos los datos de Santander, en la provincia de Cantabria:
Accedemos y descargamos los datos de la ciudad de Granada, en la provincia del mismo nombre:
228
Para la descarga de todos los datos, crearemos primero una lista de enlaces sobre la que aplicaremos la función de descarga. Esta se realiza con la función download.file(), que únicamente tiene dos argumentos principales, el enlace de descarga y la ruta con el nombre del archivo. En este caso hacemos uso de la función tempfile(), que nos es útil para crear archivos temporales, es decir, archivos que únicamente existen en la memoria RAM por un tiempo determinado. El archivo que descargamos tiene extensión *.zip, por lo que debemos descomprimir con otra función (unzip()), que requiere el nombre del archivo y el nombre dela carpeta donde lo queremos descomprimir. Los procesos de descarga y descompresión los incluiremos en una función con el objetivo de aplicarla a todos los enlaces. Al final, la aplicaremos con la función map() del paquete purrr (colección tidyverse). Por último, la función URLencode() codifica una dirección URL que contiene caracteres especiales de tal forma que sea legible en cualquier sistema.
229
Para importar los datos utilizamos la función dir_ls() del paquete fs, que ya hemos usado otras veces y que nos permite obtener los archivos y carpetas de una ruta concreta al mismo tiempo que filtramos por un patrón de texto (regexp: expresión regular). Aplicamos la función st_read() del paquete sf (en modo silencioso, por eso quite = TRUE) a cada archivo espacial del formato Geography Markup Language (GML).
8.1.2 Preparación de los datos El primer paso es reproyectar todos los datos espaciales al mismo sistema de coordenadas y asignar a la lista los nombres de las ciudades. La proyección usada aquí es EPSG:25030 (ETRS89/UTM zone 30N). Cuando aplicamos una función con map() o también con lapply() es posible otros argumentos requeridos después de la función.
En el segundo paso, unimos todos los edificios en una única tabla espacial. Como se trata de una lista, aquí es necesario usar la función do.call(), que reduce una lista de tablas con una función dada, en este caso rbind(). Con la reducción, la función empleada crea como identificador de los diferentes datos un nombre de fila del dataset seguido por un número, por ejemplo, Santiago.20505. Debemos convertir este identificador de fila en una columna propia. Para ello, la función row.names() extrae los nombres de filas. Lo único que quedaría después es suprimir los números (de las filas) empleando la función str_replace() del paquete stringr.
230
El último paso consiste en añadir nuevas columnas y convertir la columna de la edad del edificio (beginning) en clase Date. La columna de la fecha contiene algunas fechas en formato –01-01 lo que no corresponde a ninguna fecha reconocible. Por eso, reemplazamos el primer – por 0000.
8.1.3 Análisis exploratorio Antes de crear un gráfico de múltiples mapas de la edad del edificado, lo que reflejará el crecimiento urbano, haremos un gráfico de distribución de la edad de los edificios en cada ciudad. Podremos identificar claramente períodos de expansión urbana. Usaremos el paquete ggplot2 con la geometría de geom_density() para este objetivo. La función font_add_google() del paquete sysfonts nos permite descargar e incluir familias de fuentes desde Google.
231
8.1.4 Análisis cartográfico Para poder visualizar bien la distribución del crecimiento, limitamos los mapas en todas las ciudades a un radio de 2,5 km desde el centro de la ciudad. Usamos la función geocode_OSM() del paquete tmaptools para obtener las coordenadas de las ciudades en clase sf. Después proyectamos los puntos al sistema que usamos para edificado (EPSG:25830). Como último paso creamos un buffer con 2500 m para cada ciudad y la intersección con nuestros datos de los edificios.
Para poder visualizar bien las diferentes épocas de crecimiento, categorizamos el año en 15 grupos empleando cuartiles.
232
Creamos las facetas de mapas con la función tm_facets() del paquete tmap, en la que únicamente indicamos la variable por la que queremos obtener múltiples mapas. Cuando necesitamos más valores del máximo permitido por RColorBrewer podemos pasar los colores a la función colorRampPalette(). Esta función interpola para un mayor número más colores de la gama.
233
8.1.5 Mapa dinámico en leaflet Una ventaja muy interesante es la función tmpa_leaflet() del paquete tmap para pasar de forma sencilla un mapa creado en el mismo marco a leaflet.
234
8.2 Análisis del gasto en I+D. Datos de Eurostat
En este caso de estudio analizaremos, de forma gráfica mediante un mapa final, el gasto en I+D por países en la Unión Europea. Utilizaremos para ello los datos oficiales de Eurostat, la oficina Europea de Estadística.
8.2.1 Importación de datos Tenemos dos opciones para acceder a un dataset de Eurostat: 1) a través de la búsqueda o 2) con el código identificador. Podemos ver un listado completo de todos los disponibles con get_eurostat_toc().
235
La descarga de datos se hace efectiva con la función get_eurostat() indicando el código del dataset.
La alternativa es conectar de antemano el código identificador. Por ejemplo, desde la página web de Eurostat (https://ec.europea.eu/eurostat/en/data/database) identificamos el dataset que nos interese. Para este caso, usaremos el dataset R&D expenditure, que tiene el código rd_e_gerdtot. En función de los datos, los nombres de las columnas del dataset pueden variar, pero hay algunas comunes, como unit (unidad de la variable), geo (código del NUTS), time (fecha del registro) y values (valor de la variable). 236
Con la función label_eurostat() convertimos las columnas con sus codificaciones en etiquetas. Este paso nos facilitará después la identificación e interpretación de los resultados.
237
8.2.2 Análisis exploratorio Primero creamos un ranking del gasto en I+D del año 2017 para todos los sectores (euros por habitante).
Fijamos el orden, según el gasto, con la función fct_reorder() y creamos un gráfico de barras horizontales con los países ordenados según el gasto en I+D.
238
8.2.3 Análisis cartográfico Para ayudarnos a distinguir las unidades espaciales, descargamos los límites administrativos de los países de Europa. Para ello usamos la función get_eurostat_geospatial(), que descarga los límites de los países en formato sf (por defecto) a diferentes resoluciones espaciales. Además, nos permite filtrar el nivel NUTS que necesitemos (0: países, 1: regiones socioeconómicas, 2: comunidad autónoma de España y 3: provincias de España). Nosotros usaremos los datos a nivel de país.
El siguiente paso es unir nuestros datos con los límites de los países de Europa con ayuda de la columna geo. No obstante, debemos usar la columna geo con los códigos de países y no las etiqueta, ya que, si no, no coincidirán. Filtramos nuevamente, esta vez del dataset original, que es el que contiene los códigos de los países, y unimos los datos con la función left_join(), que ya conocemos.
239
Ahora solo nos hace falta crear el mapa por capas: 1) aportamos nuestros datos indicando la variable que queremos representar y 2) añadimos algunos ajustes de estética.
El mapa muestra el gasto, en euros por habitante, en I+D en Europa.
8.3 Accesibilidad por carretera en España En la actualidad las sociedades están cada vez mejor conectadas; no obstante, la facilidad con la que las personas acceden a los servicios y las instituciones determina el éxito socioeconómico, la salud humana o el bienestar. Los datos usados aquí representan la accesibilidad, en minutos, entre 240
ciudades de España en 2015. Veremos que existe una gran variabilidad en un mismo territorio. Analizaremos la accesibilidad por provincias. Los datos provienen de https://map.ox.ac.uk/research-project/accessibility_to_cities/ (Weiss et al., 2018), “A global map of travel time to cities to access inequalities in accessibility in 2015”, Nature. Doi: 10.1038/nature25181). Todos los paquetes que usaremos son conocidos de los capítulos anteriores. El paquete eurostat lo empleamos únicamente para acceder a los límites provinciales y viridis es un paquete de gamas de colores.
8.3.1 Importación de datos Primero conectaremos con el ráster de accesibilidad. Los datos tienen una resolución de 0,0083° (aprox. 1 km).
241
A continuación, cargamos los límites provinciales de España a 10 metros de resolución espacial (nivel NUTS-3).
Nota: Una alternativa a get_eurostat_geospatial() es el uso de la función ne_countries() del paquete rnaturalearth, que ya hemos visto en capítulos anteriores.
242
Cuando extraemos valores por NUTS-3, la función nos devuelve una lista de vectores para cada provincia en el orden de la geometría espacial.
Nota: Recuerda que la clase list puede contener diferentes objetos con clases diferentes como vector, data.frames, matrix, array o list. Para acceder a listas se usa la estructura: nombre[[indice]] o nombre[inicio:fin]. La segunda forma mantiene la clase list.
8.3.2 Análisis exploratorio El objetivo en este paso es crear un data.frame con una columna que contenga el valor medio y otra con la varianza por cada provincia de España. Observamos que los datos contienen valores imposibles (-9999), que debemos reemplazar por NA. Después, únicamente queda por estimar las dos métricas estadísticas. En este caso, creamos una función propia que aplica todos estos pasos. La función creada extract_acces() la aplicamos con la función lapply() a todos los elementos de nuestra lista con los valores extraídos del ráster.
243
Nota: En la función bind_rows() es necesario indicar con el argumento .id = "prov" el nombre de la columna en la que aparecerán los nombres de las provincias, así nos es posible diferenciar las métricas después de la unión. En la primera exploración creamos dos gráficos de tipo ranking en los que se visualizará la accesibilidad en minutos por provincia, de mayor a menor. Para fijar el orden de las provincias aplicamos la función fct_reorder() del paquete forcats (colección de tidyverse), que ayuda a ordenar un factor según otra variable, en nuestro caso el promedio o la varianza. Este cambio lo haremos directamente sobre la variable en las definiciones de aes().
244
245
Nota: La función coord._flip() no implica el cambio de los ejes, es decir, el eje de coordenadas sigue siéndolo aunque estén transpuestos. Antes de crear un mapa con los valores extraídos, visualizamos la distribución de la accesibilidad en cada provincia. Para ello, usamos el paquete ggbeeswarm, una extensión para ggplot2 que incluye geometrías de dispersión de violín. Primero, debemos convertir los vectores de cada provincia en un data.frame, lo que se hace aquí con una función propia (creada por nosotros). Asignamos cada vector de cada provincia a una columna acc dentro del data.frame.
Después unimos todas las tablas incluyendo una columna indicativa de la provincia. Después, reemplazamos los valores imposibles (-9999) por NA. Además, excluimos valores de 0 min y varias
246
provincias, dado que todos sus valores son superiores a 100 min. Lo último se hace para mejorar la visualización de las distribuciones en las provincias, reduciendo los valores extremos.
Ahora, únicamente quedaría: 1) definir la gama de colores, 2) fijar el orden de las provincias y limitar el rango de valores a 100 minutos, 3) calcular la mediana por provincia y 4) crear el gráfico.
247
8.3.3 Análisis cartográfico 8.3.3.1
Mapa de los datos ráster
Utilizando los datos ráster y con ayuda del paquete tmap hacemos el primer mapa de accesibilidad. Tomamos un mapa de fondo y los límites de España del paquete rnaturalearth, para extraer por máscara el ráster de accesibilidad que leíamos al inicio del caso. Reemplazamos los valores -9999 por NA.
248
Creamos el mapa añadiendo las capas correspondientes y obtenemos el mapa accesibilidad, en minutos, de las principales localidades españolas.
8.3.3.2
Mapa de la varianza por provincias
Para representar la varianza en la accesibilidad por provincias solo tenemos que unir la tabla que contiene la información estadística por provincias con los datos espaciales:
249
Nota: Recuerda que la función palette_explorer() del paquete tmaptools sirve para obtener gamas de colores.
8.4 Acceso a Open Street Maps desde R La base de datos de Open Street Maps (OSM) no solo consiste en una colección de geometrías de carreteras, sino que también incluye, entre otros, una amplia gama de puntos de interés (PDI). Esta información nos puede ser útil a la hora de usar un mapa, como por ejemplo las ubicaciones de hospitales o gasolineras. La información disponible es muy extensa. Para evitar la descarga de todo el OSM y extraer únicamente la información que nos interesa, se puede hacer uso de una overpass API, que nos permite hacer consultas a la base de datos de OSM con nuestros propios criterios. Una forma fácil de acceder a una overpass API es a través de https://overpass-turbo.eu, que incluso incluye un asistente para construir la consulta y mostrar los resultados sobre un mapa interactivo. Podemos encontrar una explicación detallada de la página en la wiki de OSM (https://wiki.openstreetmap.org/wiki/ES:Overpass_turbo). Además, en R tenemos a nuestra disposición del paquete osmdata que nos permite crear y hacer las consultas directamente desde el entorno de trabajo. Aun así, el uso de la overpass-turbo.eu puede ser útil cuando no estamos seguros de lo que buscamos o cuando tenemos alguna dificultad para construir la consulta.
8.4.1 Acceso a la overpass API desde R y consultas El primer paso que debemos dar es instalar los siguientes paquetes, en el caso de que no los tengamos disponibles:
Antes de crear una consulta, debemos conocer qué podemos filtrar. La función available_features() nos devuelve un listado amplio de las características disponibles en OMS, 250
que a su vez tienen diferentes categorías (tags). Más detalles en la wiki de OSM: https://wiki.openstreetmaps.org/wiki/ES:Caracter%C3%ADsticas_del:mapa. Por ejemplo, la característica shop contiene como categoría, entre otros, supermarket, fishing, books, etc.; solamente tenemos que seleccionar la que más se adecúe a nuestras necesidades.
8.4.2 Ejemplo: Búsqueda de cines de Madrid Para construir nuestra consulta usamos el pipe operator %>%, que ayuda a encadenar varias funciones sin asignar el resultado a un nuevo objeto. En la primera parte de la consulta debemos indicar el lugar (la localización) de donde queremos extraer la información. En este caso, la función getbb() crea un área rectangular de selección para un lugar dado mediante la búsqueda del nombre. La función principal es opq(), que construye la consulta final. Añadimos nuestros criterios de filtro con la función add_osm_feature(). En esta primera consulta buscaremos cines en Madrid, por eso usamos como clave amenity y como categoría cinema.
Podemos obtener el resultado de la consulta en varios formatos diferentes. La función osmdata_*() envía la consulta al servidor y, según el sufijo (sf/sp/xml), nos devuelve el formato simple feature, spatial o XML.
251
Vemos que el resultado es una lista de distintos objetos espaciales. En nuestro caso únicamente nos interesaría osm_points. ¿Cómo podemos visualizar estos puntos? La función get_map() del paquete ggmap descarga el mapa para un lugar dado, lo que nos dará un contexto adecuado para nuestras localizaciones. El lugar puede ser una dirección, latitud/longitud o un rectángulo de selección. El argumento maptype nos permite indicar el estilo o tipo de mapa. Podemos consultar más detalles en la ayuda de la función ?get_map. Ya podemos hacer el mapa. Cuando construimos un gráfico, habitualmente empezamos con ggplot(), pero en este caso comenzamos con ggmap(), que incluye el objeto con nuestro mapa de fondo. Después añadimos con geom_sf() las localizaciones de los cines en Madrid. Es importante definir el argumento inherit.aes = FALSE, que debe usar aesthetic mappings del objeto espacial osm_points. Además, indicamos el color (colour, fill), transparencia (alpha), tipo (shape) y tamaño (size) del círculo.
252
8.4.3 Ejemplo: Búsqueda de supermercados En lugar de obtener un rectángulo de selección con la función getbb(), podemos construir el nuestro propio. Para ello, creamos un vector con los argumentos xmin, ymin, xmax, ymax, lo que equivale a Oeste/Sur/Este/Norte, respectivamente. En la consulta usamos dos características: name y shop para poder filtrar supermercados que sean de una empresa concreta. En función del área o bien del volumen que tenga la consulta, es necesario ampliar el tiempo de espera. Por defecto, son 25 segundo (timeout). Para este caso de estudio creamos una consulta que buscará en toda España, en la categoría supermercados, todos los que sean de la empresa Mercadona.
253
El mapa que creamos en este caso se basa únicamente en las localizaciones de supermercados, por eso usamos la gramática habitual añadiendo la geometría geom_sf(). La función theme_void() elimina todos los elementos de estilo con excepción de los puntos.
8.5 Cálculo de distancia al mar basado en ráster y vectorial La distancia al mar es una variable fundamental especialmente relevante a la hora de modelizar. Por ejemplo, en interpolaciones de la temperatura del aire, habitualmente se hace uso de la distancia al mar como variable predictora, ya que existe una relación causal entre ambas que explica la variación espacial. R dispone de varias formas de estimar la distancia a la costa desde cualquier punto. En este caso, nos centraremos únicamente en la distancia euclídea (en línea recta).
254
8.5.1 La costa de Islandia como ejemplo Al ser Islandia un territorio insular, facilitará el ensayo y, de este modo, será posible mostrar el proceso de forma sencilla. Con la función ne_countries() importamos los límites de Islandia. En este caso, indicamos con el argumento scale la resolución, con country el país concreto de interés y con returnclass determinamos qué clase de objeto obtendremos (sf o sp).
255
Vemos en la información del objeto sf que la proyección es WGS84 con grados decimales (código EPSG:4326). Para el cálculo de distancias es más conveniente usar metros, en lugar de grados. Debido a ello, lo primero que hacemos es transformar el mapa de Islandia en UTM Zona 27 (código EPSG:3055), que es el sistema de coordenadas proyectado más adecuado para el país. Con ese objetivo, usamos la función st_transform(), indicando simplemente el objeto espacial y el código EPSG.
8.5.2 Creación de una red de puntos Todavía necesitamos los puntos (localizaciones) desde donde queremos conocer la distancia. En nuestro caso será una red regular de puntos (una malla) en Islandia con una resolución 5x5 km. Esa tarea la hacemos con la función st_make_grid(), indicando con el argumento cellsize la resolución en las unidades del sistema de coordenadas actual (metros en nuestro caso) y qué geometría nos gustaría crear what (polígonos, centroides o esquinas).
256
Como la malla que hemos creado es un rectángulo que abarca más superficie que la que nos interesa, extraemos, como si fuese una máscara, solo aquellos puntos que correspondan con la superficie del país.
8.5.3 Cálculo de la distancia Para estimar la distancia usamos la función st_distance(), que nos devuelve un vector de distancias para todos los puntos de nuestra red. Pero antes es necesario transformar la geometría de nuestro objeto espacial de Islandia de polígono (MULTIPOLYGON) a línea (MULTILINESTRING) para calcular la distancia desde todos los puntos a cada nodo que constituye la línea de costa de la isla.
8.5.4 Visualización de la distancia calculada Una vez obtenida la distancia para nuestros puntos, podemos combinarlos con las coordenadas y plotearlos con ggplot2. Para ello, creamos un data.frame con el campo dist, que, originalmente, es una matriz de una sola columna, así que hay que convertirla en un vector con la función as.vector(). Además, dividamos entre 1000 para convertir la distancia de metros a kilómetros. Usaremos la función st_coordinates() para extraer las coordenadas de nuestros puntos.
257
8.5.5 Exportar de la distancia como ráster Para poder exportar la distancia con respecto al mar de Islandia usaremos la función rasterize() del paquete raster, que convierte en este formato cualquier objeto espacial de carácter vectorial. Primero es necesario crear un ráster vacío donde definiremos la resolución que necesitamos (en nuestro caso es de 500 m), la proyección y la extensión espacial del ráster. La proyección podemos extraerla de la información del objeto espacial de Islandia y la extensión podemos conseguirla de los puntos grid con la función extent(). No obstante, está última función solo trabaja con tipo de objteto sp, para lo que transformaremos previamente el objeto grid en sp usando la función as_Spatial().
258
El data.frame que hemos creado hay que convertirlo en objeto de clase sf. Para ello, aplicamos la función st_as_sf() con el argumento coords indicando los nombres de las coordenadas. Adicionalmente, también definimos el sistema de coordenadas que ya conocemos.
Finalmente, creamos el ráster usando la definición geométrica anterior y el data.frame con los valores de las distancias.
La función rasterize() está pensada para crear ráster a partir de un grid irregular. Si tenemos un grid regular, como es nuestro caso, también podemos usar una alternativa más fácil. La función rasterFromXYZ() convierte un data.frame con longitud, latitud y la variable Z es un ráster. Es importante que el orden sea longitudinal, latitud, variables.
8.6 Análisis zonal ráster sobre geometrías vectoriales 8.6.1 Importación y preparación de los datos En este ejemplo vamos a utilizar algunos de los objetos espaciales ya usados en otras partes del libro. El objetivo es calcular una serie de estadísticas zonales de temperatura del aire en julio por provincias en la península ibérica. Los datos de temperatura provienen del dataset de WorldClim y 259
los obtenemos con la función get_data() del paquete raster. En este caso los descargamos a la máxima resolución espacial posible (res = 0.5) indicando el tile o tesela seleccionado mediante un par de coordenadas que le especificamos a la función. Como la superficie de la península ibérica abarca dos teselas de WorldClim, las descargamos por separado y después las unimos con la función merge() en un solo ráster.
Ahora necesitamos obtener los límites de las regiones del interior de la península ibérica. Utilizamos la función get_eurostat_geospatial() que ya usamos antes en este capítulo del paquete Eurostat. Esta vez establecemos el parámetro nuts_level = 3 para descargar a nivel de provincias. Filtramos para seleccionar únicamente las regiones de España y Portugal a través del código de país CNTR_CODE y eliminamos con la función slice() las filas que corresponden a las Islas Canarias, Azores y Madeira, con el propósito de mostrar con más detalle el mapa final en este ejemplo. Además, necesitamos crear una columna con un identificador común a las estadísticas que calcularemos a continuación, lo que hacemos con mutate().
Como los cálculos zonales (por regiones) los haremos sobre el ráster de temperaturas, preparamos los datos para que coincidan espacialmente y con la misma geometría. Primero recortamos los píxeles de la temperatura de julio que corresponden a la geometría vectorial de las provincias para trabajar con un objeto más ligero a la hora de hacer cálculos. A continuación convertimos las provincias en ráster con la función rasterize(), usando la geometría de las temperaturas como base. Esto hará que los píxeles del nuevo ráster de provincias coincidan exactamente con los de temperatura.
260
8.6.2 Cálculos zonales Ya podemos calcular las estadísticas por regiones, para lo cual utilizamos la función zonal(). Esta función solo necesita el ráster de temperaturas, el de las regiones sobre las que se harán los cálculos y la función que se aplicará. Vamos a calcular la media, máxima, mínima y desviación estándar (mean, max, min y sd, respectivamente). Las unimos en una matriz a la que añadiremos los atributos originales de las regiones.
8.6.3 Análisis cartográfico Para cartografiar los resultados necesitamos unir (con left_join()) a la geometría vectorial de provincias los resultados calculados para cada una de las provincias. Usaremos tm_shape() para representar cada una de las variables, que almacenaremos en objetos diferentes. La función tmap_arrange() nos permitirá representar, en un único layout, los cuatro mapas.
261
262
9 Interoperabilidad y exportación 9.1 SAGA-GIS 9.1.1 Introducción A lo largo de los capítulos anteriores hemos comprobado la clara interoperabilidad entre el entorno R y otros programas SIG. De hecho, veíamos que todo lo que puede hacer este tipo de software, también puede hacerlo R de una manera u otra. No obstante, siguen existiendo situaciones en las que nos puede interesar trabajar con un SIG. Hay que tener en cuenta que, en función de nuestro objetivo, la elección de un sistema u otro puede presentar ventajas que jueguen a nuestro favor ofreciéndonos herramientas de fácil manejo o desventajas que ralenticen nuestro flujo de trabajo. Entre las ventajas de R, es evidente que siempre podemos exportar resultados en el formato adecuado (tiff, shp, csv, etc.) para procesar analizar o visualizar en otro software, lo que ya de por sí es muy útil. Por otro lado, también existe la posibilidad de ampliar algunos softwares SIG con extensiones de R. Un ejemplo de ello es QGIS, que tiene la opción en ejecutar scripts internamente. Además, otra forma potente y eficaz de resolver los problemas es usar paquetes de R con los que incorporar herramientas de otros softwares en nuestro entorno de trabajo. Por ejemplo, para el caso de QGIS podemos utilizar la librería RQGIS, que, a través de Python QGIS API, permite usar el entorno conocido de R. RQGIS incluye una larga lista de geoalgoritmos ampliamente conocidos. Se puede encontrar más información en https://jannes-m.github.io/RQGIS/inex.html. SAGA-GIS es un potente SIG de código abierto disponible en http://www.saga-gis.org/. Se trata de un Sistema para el Análisis Geocientífico Automatizado, especialmente relevante en el tratamiento de datos ráster y nubes de puntos.
9.1.2 Definir work environment SAGA-GIS Tras la instalación de SAGA-GIS (disponible en su página web), en R es necesario instalar el paquete RSAGA. Lo primero que debemos hacer es definir los directorios donde se encuentran el software instalado y las herramientas del programa.
263
9.1.3 Consultar módulos y funciones de SAGA-GIS Las siguientes funciones sirven para obtener la lista de módulos de SAGA-GIS y las herramientas en cada uno, además de los argumentos:
264
265
9.1.4 Calcular el Sky View Factor En este ejemplo estimamos el llamado Sky View Factor, un índice que representa la relación en un punto en el espacio entre el cielo visible y un hemisférico centrado sobre la ubicación analizada. • • • •
•
Importamos el archivo LiDAR con extensión *.las y lo conertimos en archivo pointcloud (*.sgpts). En SAGA-GIS GUI este paso solo consiste en importar, el resto es invisible para el usuario. Convertimos la pointcloud en GRID con la extensión *.sgrd. Usamos una función para interpolar espacios vacíos. Solo nos queda por calcular el Sky View Factor. Es posible el número de núcleos de computación a utilizar (muy útil para datasets grandes). En este caso usamos cinco núcleos para procesar los datos. Si no se especifica, SAGA-GIS utiliza únicamente uno. Por norma general es conveniente usar n-1 núcleos (argumento cores). Por último, exportamos el GRID a geotiff. 266
Nota: En el último punto explicamos cómo obtener datos LiDAR y convertir el archivo original .laz en .las.
267
268
269
270
9.1.5 Visualización de los resultados La visualización de los resultados podemos hacerla con cualquiera de los métodos que hemos explicado en capítulos anteriores. En este caso importamos el ráster, lo convertimos en un data.frame y visualizamos con ggplot.
271
272
9.1.6 El paquete lidR El paquete lidR permite la visualización y manipulación de datos Airbone LiDAR (Light Detection and Ranging). Para cambiar del formato comprimido .laz al formato .las (el que requiere SAGAGIS) podemos usar las funciones readLAS() y writeLAS() (https://cran.rproject.org/web/packages/lidR/index.html). El paquete tiene muchas funcionalidades con las que podemos calcular métricas, filtrar nubes de puntos, hacer una reducción artificial de puntos, clasificaciones a partir de datos geográficos, normalización, segmentación de árboles individuales y muchas otras manipulaciones. Los datos usados en este ejemplo provienen del centro de descarga del Instituto Geográfico Nacional.
273
9.2 rmarkdown x rmarkdown es un lenguaje markup de edición y maquetación de textos que permite crear, de manera muy sencilla, documentos de texto de carácter profesional y científico. Puede incluir figuras, texto, gráficos creados en R (y otros lenguajes), así como partes de código de forma literal. A pesar de que está basado en el lenguaje de maquetación LaTeX, la sintaxis es mucho más simple y permite evaluar (ejecutar) el código insertado y mostrar los resultados del mismo. Todos el código original y el texto se implementan en un único documento que puede ser fácilmente compilado para crear un manuscrito ordenado y con un formato predefinido.
Con rmarkdown seremos capaces de crear documentos incluyendo texto, imágenes y trozos de código de varios lenguajes de programación diferentes utilizando la interfaz de RStudio. Los documentos se pueden exportar en tres formatos diferentes: 1. html: para mostrar en navegador. El resultado suele ser una página web o una presentación de diapositivas en formato html. Además, RStudio implementa un módulo con muchas opciones para crear páginas web completas basadas en rmarkdown. 2. doc: para editar con un procesador de textos como MS Word o LibreOffice. 3. pdf: es la opción más común. Para compilar el documento con esta opción es necesario tener instalada en la máquina una versión de LaTEX (MikTex en Windows, MacTex en Mac o TexLive en Linux). Para conseguir un documento final combinando texto, imágenes y código de R, necesitamos utilizar una sintaxis propia. rmarkdown es una implementación del lenguaje markdown desarrollado por John Gruber del equipo de RStudio utilizando pandoc, un convertidor de formatos de documento universal. Para implementar el lenguaje markdown en R con pandoc, necesitamos el paquete knitr, que internamente ejecuta el código. Sin embargo, no tenemos que preocuparnos por el funcionamiento interno de rmarkdown. De hecho, solo necesitamos escribir el texto, adaptar las marcas y compilar el documento haciendo clic en un solo botón en la interfaz de RStudio. Cuando hacemos clic en knit, generamos un documento que incluye tanto el contenido que hemos añadido como el output de cualquier código de R embebido en el documento. En este capítulo se explica el funcionamiento básico de la creación de documentos en pdf. Tras una simple explicación acerca de cómo crear un nuevo documento, se muestran los comandos básicos de la sintaxis de rmarkdown.
9.2.1 Primeros pasos Para crear un documento rmarkdown solo necesitamos crear un nuevo archivo de este tipo. Se creará una plantilla en blanco con la información que le habíamos proporcionado: título, autor, fecha y algunos ejemplos de uso.
274
La plantilla por defecto incluye tres tipos de contenido: 1. Una cabecera encerrada entre ---. 2. Trozos de código de R encerrados entre comillas invertidas ` `. 3. Texto simple mezclado con texto formateado. El YAML (YANL Ain’t Markup Language) es el lugar para ubicar las opciones del documento, desde el autor o el título hasta la tabla de contenidos (índice), el tamaño de la fuente o el tipo de resaltado de la sintaxis para los trozos de código insertados. Los trozos de código o code chunks contienen el código de R a ejecutar. Dependiendo de las opciones que escribamos en su cabecera, el código y/o los resultados se mostrarán o no. También se pueden establecer aquí opciones para las figuras y las tablas. El texto formateado es el texto que se mostrará en el documento final. rmarkdown tiene varias opciones para hacer más fácil la edición del formato. Sin embargo, también acepta sintaxis HTML y algo de código de LaTeX si se escribe entre "$".
275
El paquete rmarkdown tiene que instalarse antes del primer uso.
La forma de generar el archivo de salida mediante código es cargando el paquete y usando la función render().
Sin embargo, es más fácil usar el botón knit directamente para compilar el documento.
9.2.2 Opciones globales Al inicio del documento podemos establecer las opciones globales para aplicar al resto del texto. Aquí la indentación es obligatoria. Las opciones no funcionarán si no están ubicadas en la posición correcta. Además del título, autor y fecha, las opciones para el output son útiles y extremadamente variadas. Lo primero, tenemos que establecer aquí pdf_document para especificar que el output será compilado en un documento pdf. 9.2.2.1
Tabla de contenidos (índice)
Si queremos que muestre automáticamente una tabla de contenidos, podemos hacerlo utilizando toc:true. También podemos especificar el número de niveles por mostrar con toc_depth. Si queremos que las secciones estén numeradas (numeración automática sucesiva), podemos establecerlo con number_sections:true.
276
9.2.2.2
Resaltado de sintaxis
El resaltado de sintaxis es importante porque muestra el código que será evaluado. Podemos elegir entre diferentes estilos: default, tango, pygments, kate, monochrome, espresso, zenburn, haddock, NULL (sin resaltado de sintaxis).
9.2.2.3
Opciones de las figuras
Podemos establecer la altura y anchura de las figuras por defecto para todo el documento (excepto si esas opciones se cambian después en los code chunks) con fig_height y fig_width (por defecto son 6x4,5 respectivamente). Con fig_caption tenemos la posibilidad de incluir un pie de figura, lo cual es muy útil para documentos científicos como manuscritos o informes.
9.2.2.4
Opciones de data.frame
rmarkdown es capaz de mostrar una representación mejorada de tablas (matrix y data.frame) usando diferentes opciones. El comando df_print se ejecuta internamente para imprimir en nuestro documento final la tabla, y tiene diferentes opciones:
1. default: usa el método normal print.data.frame (https://rdrr.io/r/base/print.dataframe.html). 2. kable: llama al método knitr::kable para crear tablas con una apariencia mejorada (https://www.rdocumentation.org/packages/knitr/versions/1.19/topics/kable). 3. tibble: usa el método tibble::print.tbl_df (https://www.rdocumentation.org/packages/tibble/versions/1.2/topics/print.tbl_df).
9.2.2.5
Otras opciones
También podemos variar el tamaño de la fuente (solo de 10 a 12 puntos) o definir si queremos que aparezca un resumen (abstract) al inicio. Estas opciones necesitan estar al mismo nivel de indentación que el título y el output.
277
9.2.3 Escribir documentos 9.2.3.1
Cabecera
Podemos escribir los nombres de las secciones después de uno o más símbolos de almohadilla (#). Cuántas más almohadillas, menor será el nivel de la sección.
Si en el YAML establecimos la opción number_sections:true dentro de pdf_document, las secciones se numerarán automáticamente, y, si establecimos que se crease una tabla de contenidos al inicio, también estarán numeradas allí. 9.2.3.2
Formato entre líneas
Una de las características clave de remarkdown frente a LaTeX es que no hay que aprender complejos códigos para formatear el texto. El texto en negrita se escribe entre dos asteriscos (**negrita**) y el texto en cursiva entre uno solo (*cursiva*). Para escribir un texto en superíndice como 10-4, el texto debe estar rodeado del símbolo del acento circunflejo ^ (10^-4^). Asimismo, los subíndices como H2O se muestran entre el símbolo ~ (H~2~O). También se pueden incluir enlaces fácilmente de diferentes maneras. Por ejemplo, si queremos asociar un enlace a un texto, solo tenemos que escribir el texto que queremos mostrar entre corchetes seguido de la dirección web entre paréntesis:
Por otra parte, podemos insertar directamente un enlace a un sitio web sin añadir nada de sintaxis:
La sintaxis HTML es válida para mejorar algunas características de los textos que no son soportadas por rmarkdown. Por ejemplo, podemos usar texto en versalitas en un texto con una línea de código algo más larga:
Desgraciadamente, otras funciones básicas requieren un esfuerzo extra para ser resueltas. Por ejemplo, si queremos cambiar el color del texto, tendremos que instalar y cargar el paquete kableExtra y establecer una opción específica:
278
Entonces podremos escribir cualquier texto, pero incluyendo código extra dentro de la línea de texto:
Las notas a pie de página se escriben después de un acento circunflejo y entre corchetes ^[] (^[Esto es una nota al pie]). 9.2.3.3
Listas
Las listas son muy fáciles de editar con rmarkdown. Hay de dos tipos: Listas no ordenadas: Los ítems van precedidos por un asterisco *, un signo positivo + o negativo -. La indentación (de al menos cuatro espacios) permite anidar los ítems.
Listas ordenadas: siguiendo las reglas del tipo anterior, los ítems empiezan aquí con un número:
9.2.3.4
Expresiones matemáticas
Las expresiones matemáticas son comunes en documentos científicos. rmarkdown ofrece la opción de escribirlas de una forma muy simple con una maquetación final muy profesional. A pesar de que la sintaxis es muy similar a la de LaTeX en este sentido, las capacidades de rmarkdown son mucho menores. Sin embargo, pueden ser más que suficientes en la mayoría de las situaciones. Para escribir expresiones matemáticas entre el texto se deben incluir entre el signo del dólar como $\pi r^2$ (πr2). También podemos escribir expresiones separadas en párrafo independiente si las incluimos entre \[y\], como en:
Todos los símbolos matemáticos son compartidos con LaTeX.
279
9.2.3.5
Referencias en el texto
Referenciar el texto es especialmente útil en documentos largos donde queremos hacer remisiones a localizaciones concretas dentro de nuestro documento, como secciones, figuras o tablas. Podemos referenciar una sección directamente escribiendo su nombre entre corchetes [Referencias en el texto]. Si preferimos renombrar el título de una sección y enlazarlo, tendremos que escribir el nuevo texto entre corchetes seguido del identificador de la sección entre paréntesis. Este identificador lo hemos tenido que escribir previamente a continuación del título de esta debería ser: Referencias en el texto {#tr}, y, si queremos escribir un texto que enlace al inicio de la sección, tendremos que hacerlo así: [esta sección] (#tr). Esto también funciona para figuras y tablas. Sin embargo, el tipo de elemento a referenciar tiene que ser obligatoriamente el indicado en el código de R.
El código se referencia como
9.2.3.6
Código de R
Una de las características más interesantes de rmarkdown es la posibilidad de añadir trozos de código (code chunks) de una manera sencilla muy sencilla. Estos trozos pueden ser evaluados para mostrar los resultados de cualquier operación incluida dentro. Para insertar código de R solamente tenemos que escribirlo precedido de tres comillas simples invertidas y {r}, y seguido de otras tres comillas invertidas para cerrarlo.
También podemos añadir varias opciones a la cabecera de este code chunk para modificar el comportamiento del código. Algunas de las más importantes son: echo = FALSE: el código se ejecuta y los resultados se muestran, pero las líneas de código no se muestran. Es útil cuando, por ejemplo, queremos mostrar figuras sin enseñar el código para crearlas. eval = FALSE: el código se muestras, pero no se ejecuta. include = FALSE: el código se ejecuta, pero no aparece en el documento. Es útil para ejecutar código que genera resultados que usaremos posteriormente en otros code chunks. message = FALSE: no muestra los mensajes generados por el código. warning = FALSE: no muestra los avisos generados por el código. fig_cap: "caption": añade un pie de figura a los plots.
280
tidy:TRUE: re-formatea el código en un formato más limpio. cache:TRUE: guarda los resultados para futuras renderizaciones del archivo. Es útil si el tiempo de computación es muy largo. rmarkdown no solo es capaz de ejecutar código en R. El paquete knitr también evalúa otros lenguajes de programación como Python, SQL, Rcpp, Bash, JavaScript, Stan, CSS … (ver https://yihui.name/knitr/demo/engines/).
La sintaxis es exactamente la misma que para lenguaje R:
9.2.3.7
Figuras y plots
Para mostrar un gráfico solo necesitamos escribir el código dentro de un chunk:
Por defecto, el pie de figura no está incluido, pero podemos usar la opción fig_cap="caption" en la cabecera del chunk para mostrarlo y automáticamente se numerará.
281
Si queremos cambiar el tamaño de la salida, podemos usar fig.width (seis por defecto) y fig.height (cuatro por defecto).
También podemos cambiar el tipo de alineación con fig.align (left, right o center).
282
Se pueden incluir en el documento figuras guardadas en un directorio con la función knitr::include_graphics(). En esta función podemos usar una opción más simple para reducir el tamaño de la figura: out.width = "50%".
9.2.3.8
Tablas
Es muy fácil crear tablas elegantes y sofisticadas usando la función kable del paquete knitr.
Si preferimos una representación más simple de la tabla, podemos usar el paquete pander.
283
9.2.4 Creación de documentos desde múltiples archivos Si planeas crear un documento muy largo, puedes construirlo desde varios archivos Rmd independientes llamándolos desde otro que actúe de compilador de todos los demás con child = name_of_the_file.Rmd.
284