0% encontró este documento útil (0 votos)
286 vistas288 páginas

Dominic Royé and Roberto Serrano - Introducción A Los SIG Con R-Universidad de Zaragoza (2019)

Este documento introduce el lenguaje de programación R. Explica que R es un lenguaje orientado al análisis estadístico que es gratuito, multiplataforma y cuenta con una amplia comunidad de usuarios. También describe cómo instalar R e interfaz de RStudio, la cual proporciona una interfaz gráfica más intuitiva para ejecutar código de R. Finalmente, presenta algunas operaciones básicas en R como suma, resta, multiplicación y división.

Cargado por

MarcoJuan
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
286 vistas288 páginas

Dominic Royé and Roberto Serrano - Introducción A Los SIG Con R-Universidad de Zaragoza (2019)

Este documento introduce el lenguaje de programación R. Explica que R es un lenguaje orientado al análisis estadístico que es gratuito, multiplataforma y cuenta con una amplia comunidad de usuarios. También describe cómo instalar R e interfaz de RStudio, la cual proporciona una interfaz gráfica más intuitiva para ejecutar código de R. Finalmente, presenta algunas operaciones básicas en R como suma, resta, multiplicación y división.

Cargado por

MarcoJuan
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 288

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.r-
project.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 <- o con el signo igual
(=), pero este último puede crear algunos conflictos en situaciones de uso más avanzadas, así que
es mejor que nos acostumbremos al asignador (<-).

Todos los objetos pertenecen a una clase, que nos habla de la naturaleza de la información
almacenada. Además, como propiedad inherente a cada clase, todos los objetos tienen una longitud
determinada. Ambos tipos de información: la clase y la longitud, podemos consultarlas fácilmente.

Toda la información almacenada en R es un objeto, desde los datos brutos hasta los resultados de
los análisis más complejos. ¡Incluso las funciones son objetos!

Cada vez que creamos un objeto; esto es, asignamos información a un elemento, este se almacena
en la memoria (RAM). Cuanto mayor sea la cantidad de información que tenga el objeto, más grande
será este y más memoria requerirá de nuestra máquina. Si queremos consultar un listado de los
objetos que tenemos en memoria, podemos usar el comando ls(). También podemos acceder al
listado de objetos en la ventana Environment de RStudio.

Para eliminar los objetos que ya no necesitamos, podemos usar el comando rm(); (p. ej.: rm(x)), e
incluso eliminar todos los objetos de entorno del trabajo con una sola orden (rm(list = ls()).

1.6.1 Vectores
Los vectores son secuencias de elementos del mismo tipo, ya sean caracteres o numéricos.

7
Podemos crear vectores vacíos indicando su longitud, que luego podemos rellenar con tantos
elementos como hayamos definido.

Además, podemos seleccionar elementos concretos de este vector indicando el valor del índice
(posición del elemento dentro del objeto) entre corchetes a continuación del nombre del objeto:
objeto[índice].

Existen algunas funciones para ordenar los elementos o extraer el rango y la posición que ocupan
dentro del objeto:

8
También podemos extraer los valores extremos:

O buscar la posición de elementos concretos dentro del vector:

A veces nos interesa hacer un muestreo aleatorio; es decir, extraer un número concreto de valores
de nuestro vector, pero sin intervención humana:

Los vectores se pueden combinar fácilmente entre sí: solo necesitamos usar la función de
concatenación c(). Sin embargo, si queremos alguna opción algo más avanzada, tenemos muchas
opciones.

9
1.6.2 Factores
Los factores son vectores de variables categóricas que representan una clasificación discreta de los
elementos de otro vector del mismo tamaño. Además de los valores, contienen los diferentes
niveles posibles del factor.

Por ejemplo, imaginemos que el siguiente vector representa el sexo de un grupo de 30 personas:

Si convertimos el objeto sexo en un factor con la función factor(), el objeto pasará a tener,
además de los valores, unos niveles correspondientes a cada sexo único. Hemos asignado a cada
uno de los sexos una categoría discreta.

1.6.3 Matrices
Las matrices son el equivalente a una tabla en cualquier otro software. Se trata de un tipo de
almacenamiento bidimensional organizado en filas y columnas. A diferencia de los data.frame, las
matrices solo pueden almacenar datos de un tipo; es decir, o todo numérico, o todo carácter, etc.
Se crean fácilmente definiendo los datos que queremos introducir, el número de filas y el número
de columnas.

Los array son matrices de más de dos dimensiones. Por ejemplo, un array de 3 dimensiones sería
el equivalente a una "superposición de matrices". En el ejemplo siguiente se muestra la estructura
de una matriz de 7 filas y 3 columnas "repetida" dos veces. La ventaja es que permite almacenar
gran cantidad de datos en un solo objeto.

10
Podemos extraer elementos concretos de una matriz llamándolos mediante indexación del objeto
(nombrando la posición que ocupan en cada una de sus dimensiones). A diferencia de otros
lenguajes de programación (como Python), la posición del primer elemento es 1 y no 0. El acceso a
los datos se hace escribiendo el nombre del objeto y a continuación entre corchetes [*fila*,
*columna*] el índice (posición) de la fila (antes de la coma) y de la columna (después de la coma)
del dato (o datos) al que queremos acceder.

11
A veces es útil transponer la matriz:

O unirla a otras matrices mediante las funciones de concatenación de columnas cbind() (column
bind) o filas rbind() (row bind).

12
1.6.4 Data.frames
Los data.frame son similares a las matrices, pero pueden contener datos de distintos tipos
(numérico, carácter, factor, etc.).

En los data.frame podemos acceder a todos los datos de una columna utilizando el símbolo del
dólar $ y a continuación el nombre de la columna. Si queremos uno o más datos concretos de una
columna, podemos escribir a continuación entre corchetes el índice o índices de ellos. También
funciona el mismo método de acceso que en las matrices.

1.6.5 Series temporales


Las series temporales son similares a las hojas de datos, pero tienen además atributos que definen
el inicio y final de la serie, así como la frecuencia de los datos. Para crear una serie temporal
utilizamos la función ts y a continuación indicamos el conjunto de datos al que queremos aplicar
un valor temporal, el momento de inicio de la serie y la frecuencia entre dato y dato.

13
Existen muchas otras maneras de crear series temporales, pero esta es la más básica.
Posteriormente veremos funciones más específicas y útiles de acuerdo con el tipo de datos con el
que trabajemos.

1.6.6 Listas
Las listas pueden contener cualquier tipo de objeto (incluso otras listas). Los objetos no tienen por
qué ser del mismo tipo ni da la misma longitud.

En esta lista hemos incluido objetos de varios tipos, a los que hemos dado un nombre.

14
1.6.7 Conversión entre objetos
Es posible convertir un objeto de algunas clases en otras. Es lo que se conoce como forzado
(cohertion).

Hay funciones que convierten diferentes clases de objetos: as.numeric(), as.logical(),


as.character(), as.matrix(), as.data.frame(), etc. Conviene revisar en la ayuda las reglas
de conversión de unas clases y otras. Recuerda que es posible convertir valores lógicos en numérico
(TRUE: 1, FALSE: 0). En el caso de un factor también es posible, dado que está codificado.

15
1.6.8 Resumen de clases de objetos

1.7 Funciones
Las funciones son operadores que se aplican sobre objetos (normalmente conjunto de datos) que
se pasan como argumentos, dando como resultado otros objetos que contienen información nueva.
Muchas funciones se distribuyen con la versión básica de R (la que instalamos la primera vez), pero
hay muchos paquetes que añaden nuevas funciones.

Todas las funciones se usan con su nombre y paréntesis en la siguiente forma:

No es necesario usar los nombres de los argumentos, siempre y cuando el orden sea acorde a la
definición original de la función.

En R también podemos crear nuestras propias funciones para automatizar procesos que no
encontramos ya programados. Crear funciones en R es muy fácil, incluso podemos integrar todo o
parte del código de funciones preexistentes. Además, ¡gran parte de las funciones de R están
programada en R!

Definición de funciones:

Llamada a funciones:

Las funciones son objetos, de la clase función, claro ..., y, como objetos, podemos acceder a ellos
una vez definidos.

16
Algunas reglas sobre el uso de funciones:

• Se pueden utilizar casi cualquier nombre al definir una función y sus argumentos, aunque
conviene no utilizar nombres de otras funciones existentes o constantes.
• Se pueden asignar valores por defecto a los argumentos en la definición de la función (p.ej.:
arg1 = 1:10).
• Las instrucciones que realizan las operaciones de la función deben encerrarse entre llaves
({,}).
• Las variables creadas dentro de una función existen solo dentro de dicha función y no son; por
lo tanto, accesibles para operaciones fuera de la función. Igualmente, una función solo tendrá
acceso a las variables creadas dentro de la función o a las que se le hayan pasado como
argumentos.

Los métodos son funciones genéricas que pueden aplicarse a objetos de distintas clases, dando
resultados que pueden ser ligeramente distintos. Muchos métodos ya los hemos visto:

17
1.7.1 Ayuda sobre las funciones
R dispone de un sistema de ayuda bien organizado y completo para cada una de las funciones. Para
acceder a la ayuda de una función escribimos el nombre de la función a continuación del signo de
interrogación (p.ej.: ?cor). Si no estamos seguros del nombre completo de una función, podemos
usar dos interrogantes (p. ej.: ??cor) y se mostrará un listado de funciones, vignettes y code
demostrations en los que se nombre la palabra que hemos escrito.

La página de ayuda de una función siempre tiene la misma estructura: Descripción, forma de uso,
argumentos posibles, detalles explicativos, valor que devuelve y ejemplo(s) de uso. En algunos casos,
también aparecen descritas algunas notas adicionales para comprender alguna parte de su
funcionamiento, o funciones similares que puedan ser de interés para quien use la que está
buscando.

1.7.2 Paquetes de funciones


La comunidad de usuarios de R es especialmente productiva en la creación de paquetes de
funciones. Un paquete contiene un conjunto ilimitado de funciones para aplicar sobre nuestros
datos. Estas funciones, como ya hemos visto, pueden ser creadas directamente en R. Por esta razón,
cuando hemos trabajado sobre un análisis concreto y queremos compartir nuestras funciones
nuevas con otros colegas o incluso abrirlas a toda la comunidad de usuarios, podemos crear un
paquete en un solo archivo contendrá desde el código de las funciones hasta el manual de ayuda de
cómo utilizarlas.

Crear nuestros propios paquetes nos puede servir para almacenar funciones que vamos a usar
habitualmente, compartirlas con otros usuarios e incluso subirlas al repositorio oficial de CRAN. La
creación de paquetes puede hacerse (y de hecho se hace) mediante código en la consola de R. Sin
embargo, con RStudio es mucho más fácil: la interfaz gráfica ayuda mucho a completar los
elementos necesarios.

1.8 Conceptos básicos sobre lectura, escritura y almacenamiento


El formato más habitual en el que solemos encontrarnos los datos es en forma de tabla de texto. La
siguiente figura muestra un ejemplo con unos datos de localización de una serie de estaciones
meteorológicas:

18
Este tipo de datos se leen con la función read.table(). A continuación vamos a leer la tabla con
los datos de las estaciones y almacenaremos el resultado en un nuevo objeto de nombre est,
concretamente un objeto de clase data.frame:

En este caso nos devuelve un error debido a que la función read.table() espera un separador
entre columnas diferente al que tiene el archivo. Si no fijamos el separador, por defecto es sep="",
pero el archivo tiene separador tabular (\t). Además, la función por defecto define con el
argumento header=FALSE que la primera fila no es la cabecera, lo que en nuestro caso es diferente.
Por eso, debemos indicar estos argumentos con sus valores correctos para importar el archivo con
éxito.

Consulta la ayuda de la función y verás que existen multitud de parámetros que permiten configurar
la función read.table() para leer casi cualquier formato de texto. Además, hay funciones
específicas para otros casos comunes, como read.csv() o read.delim().

19
Podemos especificar en todas estas funciones si la tabla tiene o no una cabecera (header), el
carácter de separación de campos (sep), el separador de decimales (dec), el número de líneas
(nrows) y otros muchos aspectos.

La función write.table() nos permite exportar una tabla de datos de R a formato texto, y tiene
argumentos muy parecidos.

También existen otros modos de lectura y escritura de archivos. Por ejemplo, podemos utilizar la
función scan() para leer línea por línea un archivo de texto que no necesariamente debe tener la
extensión .txt:

Otras veces nos interesa leer archivos binarios: la potencia de R en este sentido es muy alta, ya que
es capaz de leer prácticamente todo (mientras luego sepamos trabajar con esos datos ...):

Además, R tiene su propio formato de datos, que resulta especialmente útil cuando trabajamos con
conjuntos de datos muy grandes, ya que los almacena comprimidos, ocupando muy poco espacio
en disco. Es el formato RData.

1.9 Funciones de estadística fundamental


En este apartado repasaremos de forma muy breve algunas funciones fundamentalmente de la
estadística básica. En este caso usamos airquality, que es uno de los datasets contenidos en el
paquete básico de R. Se puede consultar una lista de todos los datasets disponibles con
library(help = "datasets").

20
1.9.1 Promedio, mediana, varianza

1.9.2 Test
En R podemos realizar test estadísticos fácilmente (p.ej.: t.test o correlación de Pearson).

21
Cuando usamos la función cor() y alguno de nuestros datos es un valor faltante (NAs), debemos
indicar con el argumento use que emplee solo observaciones completas (use = "complete.obs").
La función cor() devuelve una matriz si los datos de entrada son una matriz. No obstante, para
obtener un test de correlación entre dos variables es necesario usar la función cor.test().

22
1.9.3 Regresión lineal
Para hacer una regresión lineal, simple o múltiple, se usa la función lm(). En la mayoría de ajustes
de modelos se usa el argumento formula para indicar la relación/expresión entre variables en el
modelo. La expresión más simple sería x ~ y, en la que se usa el operador ~ para indicar esta
relación, siendo x la variable dependiente e y la variable independiente. En el caso de la regresión
múltiple (aditiva) usaremos el operador + para añadir más variables independientes.

La función summary() es muy útil para obtener un resumen detallado del resultado del modelo.
Además, se puede usar la función plot() sobre el resultado de un modelo lineal para crear de
forma automática gráficos de diagnóstico estadístico.

23
24
1.10 Trabajando con scripts
Sin duda, uno de los aspectos más interesantes de R es la posibilidad de trabajar con scripts. Un
script de R no es más que un archivo de texto en el que guardamos secuencias de instrucciones en
lenguaje R.

En RStudio podemos crear un nuevo script y guardarlo con el nombre que queramos, por ejemplo:
intro.R. Cerramos el programa y abrimos una nueva sesión haciendo doble clic sobre el archivo
que acabamos de crear intro.R.

Algo de ayuda sobre el trabajo con scripts:

• El carácter # indica comentario: cualquier texto que siga será ignorando por el intérprete de R.
Permite ir poniendo notas al código.
• Podemos copiar líneas de código y pegarlas en la consola de R. Los entornos como RStudio nos
facilitan el ejecutar líneas de código mediante combinaciones de teclas: CTRL+R y CRTL+Enter
(Windows), CMD+Enter (Mac).

1.11 Algunos mensajes de error comunes


Los mensajes de error empezarán a ser comunes a medida que avancemos en el uso de R. Como la
búsqueda de soluciones puede consumir un tiempo muchas veces demasiado largo, añadimos
algunos de los más comunes a continuación:

could no find function

Este error aparece cuando R no puede encontrar la función que queremos aplicar. Se soluciona
cargando el paquete correspondiente. Si no sabemos a qué paquete pertenece, podemos
encontrarla escribiendo: ??nombre_de_la_función.

25
object no found

Estás intentando acceder a un objeto que no existe. Asegúrate de que lo has creado antes.

cannot open the connection

Las conexiones se realizan, por ejemplo, cuando queremos leer un archivo. Casi siempre se debe a
un error en la dirección (path) del archivo.

subscript out of bounds

Es uno de los errores más comunes. Se produce cuando queremos acceder a una posición que no
existe a un objeto. Por ejemplo: Si p <- matrix(rnorm(4), 2, 2), p[3,1] dará un error.

non-numeric argument to a binary operator

Este error se produce cuando queremos operar sobre un objeto o elemento que no es numérico.
Por ejemplo: "w" + 1

error in library(NOMBRE): there is no package calle 'NOMBRE'

Claramente, nos falta el paquete que queremos cargar con library: tendremos que instalarlo.

Cuando ejecutamos un comando incompleto (ausencia de un paréntesis, comas u otros elementos),


R espera con + en la consola para terminarlo y no ejecuta hasta que tenga todo. Para salir de estos
casos, o bien completamos la línea de código con los caracteres que falten, o bien usamos ESC.

1.12 Consejos de estilo en programación con R


En R no existe una guía de estilo definitiva que sea necesario seguir a la hora de escribir nuestros
scripts. No obstante, es recomendable trabajar de forma homogénea y clara al escribir. Esto
representará una ventaja cuando queramos compartir el código con otros usuarios y, sobre todo,
cuando queramos recuperar alguna parte de nuestro análisis en scripts interminables. En este libro
se sigue el estilo de tidyverse (https://style.tidyverse.org/), que coincide en gran parte con el
recomendado por Google (https://google.github.io/styleguide/Rguide.xml).

Es más práctico utilizar nombres de archivos compuestos por más de una palabra separados con un
guion bajo, en lugar de espacios o puntos. Por otra parte, evita nombrar tus archivos de una manera

26
genérica (analisis.R, funciones.R, etc.), ya que será más difícil encontrar después lo que buscas si
tienes varios archivos que se llaman igual. La extensión correcta para los scripts es .R.

De igual manera, hay que ser cuidadoso con los nombres de los objetos creados en el entorno de
trabajo. A pesar de que R permite definir un objeto con casi cualquier nombre, es preferible
mantener una homogeneidad constante a lo largo de todo el script.

Es aconsejable usar una correcta indentación para múltiples argumentos de una función o funciones
encadenadas por el operador pipe (%>%). Por ejemplo:

Evita usar más de 80 caracteres por línea; esto permite leer el código completo en casi todos los
sistemas sin usar el desplazamiento horizontal de la ventana.

Otros consejos:

• Usa siempre un espacio después de una coma, nunca antes.


• Los operadores (==, +, -, <-, %>%, etc.) deben tener un espacio antes y después.
• No hay espacio entre nombre de una función y primer paréntesis, ni entre el último argumento
y el paréntesis final de una función.
• Evita reutilizar nombres de funciones y variables comunes: c <- 5 vs. c()).
• Ordena el script separando las partes con la forma de comentario: # Importar datos ---.
• Se deben evitar acentos o símbolos especiales en nombres, archivos, rutas, etc.

27
2 Manipulación y gestión de datos con tidyverse
2.1 Introducción a la colección tidyverse
tidyverse es una colección de paquetes de R que fueron diseñados para la Ciencia de Datos. Todos
los paquetes siguen la misma filosofía, gramática y estructura de datos, lo que permite una alta
compatibilidad entre las funciones y una representación común de datos. La ventaja es que un único
paquete instala una colección muy potente de funciones que hacen posible gestionar, manipular y
visualizar datos. tidyverse tiene una página web propia con toda la información necesaria:
https://www.tidyverse.org.

La gramática sigue en todas las funciones una estructura común. Lo más esencial es que el primer
argumento es el objeto y después viene el resto de argumentos. Además, se proporcionan un
conjunto de verbos que facilita el uso de las funciones.

El núcleo de la colección lo constituyen los siguientes paquetes:

Podemos instalar la colección de paquetes tidyverse a través de la ventana Packages y el menú


Install, donde simplemente debemos buscar el nombre del paquete y proceder a instalar. Una
alternativa es usar la función install.packages() indicando el nombre como carácter.

Si el paquete ya está instalado, es aconsejable actualizar no solo este, sino todos los paquetes.
Recuerda también mantener actualizado R y RStudio.

Es posible que en R dos o más funciones tengan el mismo nombre, lo cual puede crear un conflicto
interno a la hora de usar una de ellas, ya que el software no tiene claro a cuál nos referimos. En
tidyverse, cuando se carga toda la colección de funciones, se indican automáticamente los
conflictos, pero también nos da la oportunidad de comprobarlo en cualquier otro momento:

28
Por ejemplo, la función filter() del paquete stats sirve para suavizar o filtrar series temporales,
y está incluida en la instalación por defecto de R. Cuando cargamos tidyverse, la función
filter() del paquete dplyr enmascara la anterior. La consecuencia es que con los argumentos
“incorrectos” para la función filter() de stats, obtendríamos un error.

Pero sí que funciona correctamente con los argumentos adecuados para filter() de dplyr:

29
¿Cómo evitamos estos conflictos?

Es muy fácil: si escribimos el nombre del paquete delante de la función que queremos usar,
separados por el símbolo de dos puntos escrito dos veces (package_name::function_name),
usaremos la función que corresponde a ese paquete.

En este libro veremos dicha forma en muchos casos. No solo podemos usarlo para evitar conflictos,
sino que también sirve para emplear funciones puntualmente sin cargar el paquete
correspondiente.

Además de los paquetes mencionados, usaremos en este capítulo lubridate para trabajar con
fechas y horas, y también readxl, que nos permitirá importar archivos en formato Excel.

2.2 Lectura y escritura


El paquete readr, incluido en la familia tidyverse, admite la lectura de múltiples formatos de
archivo usando funciones que comienzan por read_* o write_*:

30
Nota: En este apartado no se explica cómo usar las funciones correspondientes a la escritura
(exportación), pero siguen la misma estructura que la lectura de archivos.

¿Qué ventajas tiene el uso de estas funciones en comparación con las de R Base?

Por un lado, las funciones son más rápidas, y, por otro, los caracteres no se convierten en factores
por defecto. Además, las fechas y las horas son convertidas automáticamente, lo cual supone una
ventaja, ya que ahorramos algo de tiempo (y esfuerzo) si trabajamos con series temporales. Las
tablas importadas son de clase tibble (tbl_df), una “reinvención” moderna de data.frame del
paquete tibble.

31
Al importar datos, la función nos indica de qué clase es cada columna. En nuestro caso, el archivo
que importamos contiene la serie diaria de las horas de sol de la ciudad de Vigo (España).

En cambio, para importar datos desde Excel debemos usar las funciones read_xls() y
read_xlsx(). Aquí tendremos que indicar como segundo argumento el número de la hoja que
queremos importar, ya que este tipo de archivos suele contener más de una (por defecto importa
siempre la primera). Algunas veces, como en este caso, es útil saltarse filas e importar un número
máximo, en lugar de todas.

32
33
2.3 Manipulación de caracteres
Para trabajar con la manipulación de cadenas de texto usamos el paquete stringr, cuyas funciones
siempre empiezan por str_*, seguidas por un verbo y el primer argumento, que siempre es un
vector de caracteres. El paquete simplifica la gestión y manipulación de caracteres y es compatible
con todas las funciones del conjunto de tidyverse.

34
Para ejemplificar el uso de la manipulación de caracteres usamos la columna geo de los datos
importados. Creamos un objeto llamado “geo” con los nombres de los países/regiones de la tabla
emisiones, usando la función pull() del paquete dplyr.

La mayoría de las funciones str_* usan expresiones regulares, un lenguaje conciso para describir
patrones de texto. Por ejemplo, la expresión regular [aeiou] coincide con cualquier carácter único
que sea una vocal. Podemos encontrar más detalle y patrones en Cheat-Sheet de stringr:
https://github.com/rstudio/cheatsheets/raw/master/strings.pdf.

35
El uso de corchetes en este contexto [] corresponde aquí a clases de caracteres. Por ejemplo, [abc]
corresponde a cada letra independientemente de la posición. [a-z] o [A-Z] o [0-9] cada uno
entre a y z o 0 y 9. Y por último, [:punct:] puntuación, etc.

36
37
Con llaves {} podemos indicar el número del elemento anterior: {2} sería dos veces, {1,2} entre
una y dos, etc. En el Cheat-Sheet de stringr podemos encontrar más caracteres especiales que
usan para encontrar patrones.

Nota: Si quieres obtener un formato decimal 12.0 en lugar de 12, puedes usar la función format(),
por ejemplo format(12, nsmall = 1).

38
2.4 Manipulación de fechas y horas
Ya hemos visto en el capítulo introductorio la forma de trabajar con algunas series temporales. Sin
embargo, el paquete lubridate supone un avance importante en cuanto a facilidad de manejo
cuando necesitamos trabajar con fechas y horas.

Nos permite crear los objetos reconocidos por R con funciones (como ymd() o ymd_hms()) y hacer
cálculos o manipular series temporales.

Debemos conocer las siguientes abreviaturas:

• ymd: representa y: year, m:month, d:day


• hms: representa h: hour, m:minutes, s:seconds

¿Cómo podemos convertir este formato Año/Mes/Día en una fecha reconocible por R?

¿Qué hacemos con otros formatos?

Usamos funciones de lubridate diferentes a tenor del orden del año, mes y día. Estas pueden
reconocer automáticamente los formatos más habituales, que suelen ser los separados por “/”, “-
“ o incluso sin ningún separador.

39
¿Cómo podemos pasar de un formato numérico de fecha a carácter?

Podemos tener fechas en formatos numéricos que expresan en días desde una fecha concreta (en
R el origen es 1970-01-01). Las funciones que podemos usar para transformar entre numérico y
carácter son: as_date(), en caso de solo fechas y as_datetime() para fechas con la hora.

Nota: En el caso de fechas con la hora, las unidades son segundos desde el origen:
as_datetime(295555055).

¿Cómo extraemos el mes, el año, el día del año?

40
¿Cómo cambiamos de idioma para referirnos a los meses?

Es algo que puede ser interesante cuando quisiéramos publicar un gráfico en un idioma diferente al
que tiene nuestro sistema por defecto.

Las fechas y horas convertidas en objetos reconocibles por R también nos permiten hacer cálculos.

Debemos tener cuidado con month() vs. months(), etc. Las funciones de unidades temporales que
terminan en “s”, como months, days, hours, nos permiten crear objetos temporales de periodos.

41
¿Qué hacemos cuando tenemos una fecha con hora?

Simplemente, se amplían las funciones que usamos para convertir fechas (ymd*()) añadiendo *_hm
o *_hms. No es necesario indicar el huso horario con el argumento tz; no obstante, por defecto se
establece como huso el “UTC”. Si el huso horario no está correctamente definido, puede provocar
cálculos erróneos entre diferentes husos. Podemos encontrar un listado de husos, por ejemplo, en
wikipedia: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones.

42
Nota: Si solo queremos trabajar con la hora, existe el paquete hms (forma parte de tidyverse,
tidyverse_packages()), por ejemplo, hms(56, 34, 12).

Cuando trabajamos con variables temporales, un procedimiento común es no convertir variables


como año o año-mes en una fecha reconocible en R, lo cual puede arrastrar errores posteriores. Si,
por ejemplo, tuviésemos un data.frame de datos mensuales con las columnas mes y año o solo
año, deberíamos pasarlos igualmente a clase Date.

43
2.5 Manipulación de tablas y vectores
El paquete dplyr funciona con una gramática de manipulación de datos que nos proporciona un
conjunto de verbos muy útiles para resolver los problemas más comunes en manipulación de datos.
Las funciones principales son las siguientes:

Además, podemos combinar estas funciones entre sí y con otra esencial, que es group_by(), que
permite hacer operaciones según grupos predefinidos por el usuario.

Vamos a volver a nuestros datos de las horas de sol de Vigo. Primero usaremos la función mutate()
para añadir columnas o cambiar las existentes. Lo que haremos con ella es:

1) Convertir la fecha en clase Date.

2) En la columna SS (horas de sol) reemplazar los -9999 por NA y dividir entre 10.

3) Añadir el mes y el año como columnas nuevas.

Una gran ventaja de mutate() es la posibilidad de crear nuevas variables a partir de otras nuevas.
Aunque, ¡cuidado!, el orden es relevante, ya que crear nuevas columnas a partir de otras solo es
posible si se han creado en el orden correcto. También existen funciones derivadas, como
mutate_all() o mutate_at(), que aplican una función a todas las columnas o en columnas
seleccionadas, respectivamente.

44
¿Cómo seleccionamos columnas?

Es posible usar los nombres o la posición de las columnas. Además, también podemos usar - para
(de)seleccionar una columna o varias. Por último, : tiene utilidad para (de)seleccionar entre
columnas consecutivas. Para la función select() existen varias funciones auxiliares: contains()
o starts_with(), que permiten seleccionar columnas a partir de patrones en sus nombres.

45
46
¿Y si queremos seleccionar una fila?

Nota: La función select() también permite el uso de las posiciones de columnas, en lugar de los
nombres.

¿Cómo filtramos nuestro data.frame?

En la función filter() se pueden incluir variables separadas por una coma, lo cual equivale a la
condición AND (&). En el caso de OR (|) debe ser una condición seguida.

47
48
¿Cómo ordenamos un date.frame?

49
¿Cuántas horas de sol anuales tiene Vigo?

Para poder responder a esta pregunta, debemos sumar todas las horas por año. En la función de
sum() se usa na.rm = TRUE, ya que la serie temporal contiene 647 valores ausentes (NA). La función
que permite resumir es summarise(), en la que, igual que en mutate(), creamos nuevas variables
usando otras funciones. En este caso, será 1) la suma de las horas de sol, 2) el número de años y 3)
la división entre el total de horas y el número de años.

50
En R Base se cambian los nombres de columnas con la función names() asignando los nuevos. En el
paquete dplyr encontramos la función alternativa rename(), que sirve para cambiar algunos
nombres concretos o, si queremos cambiar todos los nombres, se emplea la función set_names().

51
Nota: Otras funciones útiles son: distinct(), ungroup(), bind_rows(), etc.

Para facilitar el trabajo en la gestión, manipulación y visualización de datos, el paquete magrittr


introduce el operador llamado pipe en la forma %>% con el objetivo de combinar varias funciones
sin la necesidad de asignar el resultado a un nuevo objetivo. El operador pipe pasa la salida de una
función aplicada al primer argumento de la siguiente función. Esta forma de combinar funciones
permite encadenar varios pasos de forma simultánea. Se debe entender y pronunciar el %>% como
“luego” (then).

Para facilitar la compresión del encadenamiento de funciones, podemos cargar el paquete tidylog.
De este modo nos indica lo que hace en cada paso.

52
Otro grupo de funciones interesante es el dedicado a unir tablas. Según hacia qué tabla (izquierda
o derecha) se quiere unir, cambia la función *_join():left_join(), right_join().
full_join() implicaría que en la unión de ambas tablas se mantienen todas las filas y columnas.

53
Nota: A diferencia de su homólogo merge(), no es necesario indicar una columna común a ambas
tablas con el argumento by. La función automáticamente busca en ambas tablas una columna en
común. Si los nombres de las columnas no son iguales, se puede usar el siguiente formato: by =
c("nombrecolumna_izq" ="nombrecolumna_der"). Es posible unir tablas por más de una
columna.

Con el objetivo de cambiar la estructura de datos importados, podemos hacer uso de gather() y
spread() del paquete tidyr. Una tabla es tidy cuando 1) cada variable es una columna, 2) cada
observación/caso es una fila y 3) cada tipo de unidad observacional forma una tabla. Es esencial
entender la diferencia entre dos formas estructurales de una tabla: larga o ancha.

Una tabla ancha sería el siguiente caso:

En cambio, una tabla larga tendría el siguiente aspecto:

54
En el caso de nuestros datos de temperaturas y horas del sol de Vigo, podemos cambiar a una tabla
larga. Los nombres Variable y Valor en nuestro dataset serán las columnas donde se incluyen los
nombres y los valores correspondientes a la temperatura y horas de sol. Además, debemos indicar
las columnas afectadas que serán “fundidas” en las nuevas columnas.

¿Queremos volver al formato anterior?

Es suficiente con indicar dónde se encuentran las variables y los valores. Una de las ventajas de este
sistema es que podemos calcular estadísticas de diversas variables dentro de la misma función.

55
2.6 Otras funciones útiles
Existen otras tres funciones que son muy útiles para la manipulación de datos: separate(), que
sirve para asegurar una columna en varias nuevas; case_when(), que sirve para establecer
condionales y es similar a ifelse() y complete() que sirve para completar una variable o una
combinación de variables.

separate()

Para mostrar la primera función convertimos la fecha en tres columnas: año (yr), mes (mo) y día
(dy), cuyos elementos están separados por “-“. Por ello, es necesario indicar la columna afectada,
los nombres de las nuevas columnas y el símbolo separador. La función mutate_all() aplica a
todas las columnas otra función, en este caso, as.numeric() para convertir todas en numéricas.

56
¿Cómo podemos crear una nueva variable indicando la estación?

case_when()

En lugar de encapsular y encadenar ifelse(), podemos usar la función case_when(), en la que


empleamos fórmulas en dos tiempos: por un lado la condición; por otro, la acción cuando se cumpla
esa condición. En R una fórmula de dos tiempos o dos lados se constituye con el operador ~.

57
La última condición también podría ser simplemente: TRUE ~ "otoño".

complete()

Para mostrar el potencial de esta función creamos una selección de datos del objeto data_vigo
usando la función sample(), que crea números aleatorios de longitud n de un conjunto de datos
determinado. En este crearemos 10 000 números aleatorios de entre el número de filas del objeto
data_vigo (de 1 a 26298). Como la selección es aleatoria, aplicamos posteriormente la función
arrange() con el objetivo de ordenar la fecha de menor a mayor.

Nuestro conjunto de datos contiene datos diarios desde el 1 de enero de 1980 hasta el 31 de
diciembre de 2015. Así que únicamente debemos crear un vector con fechas de este periodo. En la
función complete() indicamos la columna que queremos completar y le asignamos el vector
entero de fechas. El resultado es un nuevo data.frame con todas las fechas, rellenando el resto de
columnas con NA. En el siguiente capítulo usaremos la misma función en otro contexto,
completando la combinación entre dos variables.

58
Nota: Existe un paquete llamado dbplyr de tidyverse que permite conectar a bases de datos de
tipo MySQL, SQLite, Postgres, etc., usando las mismas funciones que hemos visto anteriormente.
Más detalles, en https://dbplyr.tidyverse.org/articles/dbplyr.html

2.7 Importar varias hojas de Excel


Cuando trabajamos con un archivo Excel, nos podemos encontrar con tablas distribuidas en varias
hojas. En este ejemplo práctico vamos a importar la temperatura media diaria de Madrid y Berlín,
que se encuentra en dos archivos de Excel con hojas para cada año entre 2000 y 2005. También se
podría usar el mismo método para importar múltiples archivos de otros formatos.

Usaremos los paquetes fs y readxl. Es útil saber que readxl puede importar archivos Excel, pero
no permite exportarlos. Para exportar tablas a Excel hay que usar el paquete openxls.

Por defecto, la función read_excel() importa la primera hoja. Para importar una hoja diferente es
necesario indicarlo con el argumento sheet o bien el número o el nombre (segundo argumento).

59
La función excel_sheets() permite extraer los nombres de las hojas.

El resultado nos indica que en cada hoja encontramos cada uno de los años desde 2000 a 2005. La
función más importante para leer múltiples hojas es map() del paquete purrr que forma para de
la colección de paquetes tidyverse.map() permite aplicar una función a cada elemento de un
vector o lista.

60
El resultado es una lista cuyos nombres coinciden con el nombre de cada hoja que contiene el
data.frame. Dado que se trata de la misma tabla en todas las hojas, podríamos usar la función
bind_rows(); no obstante, existe una variante de map() que directamente nos une todas las tablas
por fila: map_df(). Si fuese necesario unir por columna, se debería usar map_dfc().

En nuestro caso tenemos una columna en cada hoja (el año, pero también la fecha) que diferencia
cada tabla. Si no fuera así, deberíamos usar el nombre de las hojas como nueva columna al unir
todas. En bind_rows() puede hacerse con el argumento .id asignando un nombre para la columna.
Lo mismo valdría para map_df().

61
En principio, para este ejemplo no nos haría falta usar el argumento .id = "yr", ya que
disponemos de una columna date que identifica cada fila de cada hoja.

¿Cómo importamos múltiples archivos de Excel?

La función dir_ls() del paquete fs (https://github.com/r-lib/fs), a pesar de ser similar a dir() de


R Base, tiene algunas ventajas, como su total compatibilidad con la colección de funciones de
tidyverse. Por ejemplo, el argumento regexp permite buscar con una expresión regular un patrón
en las rutas y ficheros.

Importar los dos archivos de Excel que tenemos.

62
Ahora bien, en este caso solo importamos la primera hoja de cada archivo Excel. Para resolver el
problema, damos un paso más y creamos nuestra propia función, en la que hacemos lo que
realizamos previamente, pero de forma individual.

Aplicamos nuestra función creada para importar múltiples hojas de varios archivos Excel.

63
Para “limpiar” la columna city y dejar únicamente los nombres de archivo, usamos dos funciones
del paquete fs que permiten suprimir la ruta (path_file()) y la extensión del archivo
(path_ext_remove()). Además, eliminamos "_temp" del nombre de las dos ciudades usando la
función str_replace() del paquete stringr.

64
3 Visualización de datos con ggplot2
3.1 Introducción
ggplot2 es un sistema elegante, estéticamente moderno y con una enorme variedad de opciones
para visualización de datos. Actualmente es uno de los paquetes gráficos más populares. ggplot2
utiliza una gramática diferente del sistema gráfico de R Base. Es importante subrayar que, cuando
se llega a entender la filosofía de organización, ggplot2 se convierte en una herramienta muy
potente a la hora de visualizar cualquier tipo de datos. La adecuada visualización de datos tiene gran
relevancia. Por ejemplo, ¿se deben usar dobles ejes con distintas unidades? Una respuesta la da Lisa
Charlotte Rost en su blog sobre representación gráfica (https://blog.datawrapper.de/dualaxis/).
Una lectura muy recomendable sobre visualización es https://serialmentor.com/dataviz/. Si
buscamos tipos de gráficos o inspiración, es muy interesante consultar la galería de r-graph
(https://www.r-graph-gallery.com).

Por ejemplo, con el paquete gráfico básico podemos crear un gráfico de puntos o scatterplot de la
siguiente forma:

El dataset iris es un conjunto de datos que proporciona las medidas en centímetros de la longitud
y el ancho del pétalo y sépalo, respectivamente, para 50 flores de cada una de las especies de iris.
Las especies son Iris setosa, versicolor y verginica.

Por el contrario, en ggplot2 se aplicaría la gramática por objetos o capas:

65
La gramática de los gráficos (grammar of graphics, de ahí “gg”) consiste en la suma de varias capas
u objetos independientes. En la creación de gráficos clásica, o incluso en otros softwares como Excel,
el proceso es diferente: primero, a partir de una tabla de datos, se crea un gráfico básico y después
se manipulan los colores, las dimensiones, la escala u otros elementos gráficos u opciones. Por el
contrario, ggplot diferencia entre los datos, lo que se visualiza y la forma en que se visualiza.

Primero necesitamos indicarle a ggplot2 la tabla sobre la que se aplica una serie de mapping
(visualización) y transformaciones con el objetivo de crear una representación gráfica.
Habitualmente, un gráfico con ggplot2 se construye a partir de varios componentes:

• data: nuestro conjunto de datos representado en una tabla. Siempre es un data.frame().


• aesthetics: con la función aes() indicamos las variables que corresponden a los ejes x, y, z,
... o incluso, cuando se pretende aplicar parámetros gráficos (color, size, shape), según una
variable. Es posible incluir aes() en ggplot() o en la función correspondiente a una
geometría geom_*. En función de la geometría que usemos, existen argumentos específicos.
• geometries: son objetos geom_* que indican la geometría a usar (p.ej.: geom_point(),
geom_line(), geom_boxplot(), geom_tile(), geom_bar(), etc.).
• scales: son objetos de tipo scales_* (p.ej.: scale_x_continous(),
scale_colour_manual()) para manipular los ejes, definir colores, etc.
• statistics: son objetos stat_* (p.ej.: stat_density()) que permiten aplicar
transformaciones estadísticas.

Usando + se combinan todos los componentes para construir una representación gráfica final.
Volvemos a nuestro scatterplot sobre la longitud del sépalo y el ancho del pétalo, y creamos el
mismo gráfico que antes, pero con la gramática de ggplot().

66
67
La función labs() también permite definir el título (title), subtítulo (subtitle), pie de figura
(caption) y el nombre de la leyenda (en función del parámetro elegido: fill, color, etc.).

3.2 La gramática de gráficos en ggplot2


3.2.1 Primeros pasos
Para demostrar algunas posibilidades más de ggplot2, primero importamos y limpiamos un dataset
con el que trabajaremos. Los datos que usaremos son del informe “World Population Data Sheet
2017” de Population Reference Bureau (https://www.prb.org/wp-
content/uploads/2017/08/2017_World_Population.pdf). En total son nueve archivos csv que
debemos importar, unir y limpiar.

Usaremos la colección de funciones disponibles en tidyverse y en el paquete fs:

La función dir_ls() del paquete fs nos permite ver los archivos presentes en una carpeta. Ya la
hemos mencionado en el capítulo anterior cuando importamos varias hojas de Excel. Además, la
misma función tiene un argumento regexp que busca por patrones en los nombres. Únicamente
leeremos de la carpeta aquellos archivos que contienen el nombre WPFS_2017_data. Se trata de
una expresión regular ?regex, de las que hemos hablado en el capítulo anterior sobre manipulación
de caracteres. Cuando los datos se encuentran en una carpeta dentro del directorio de trabajo
debemos indicarlo en la forma relativa: ./[nombre_carpeta]/[nombre_archivo].

68
La función lapply() ayuda a aplicar cualquier función a una lista o un vector. Devuelve
nuevamente una lista con el resultado de la función aplicada. También, en lugar de la función
lapply(), podríamos usar map() (del paquete purrr), que ya aplicamos en el ejemplo del capítulo
anterior importando archivos de Excel.

Aquí aplicamos una función del paquete plyr que tiene relación con dplyr. Si queremos usar
alguna función puntualmente sin cargar el paquete, ya vimos que podemos emplear fácilmente la
forma paquete::FUN. En este caso, la función join_all() nos permite unir todas las tablas de la
lista en una única según una variable.

69
Si nos fijamos en el modo de las columnas, observamos que algunas variables son del tipo chr. La
causa puede ser que existan elementos no numéricos en una columna mayormente numérica.

Otra causa puede ser el uso de la coma (,) como separador decimal o de unidades de millar.

Por esta razón, aplicamos la función parse_number() del paquete readr, que nos ayuda a detectar
números en formato de carácter. En el caso de que tuviéramos que especificar el formato,
podríamos usar el argumento locale e indicar con la función locale() las especificaciones del
formato. Además, ahora aplicamos una versión diferente de mutate(), que es mutate_at(), lo
que nos permite hacer cambios en varias columnas de forma simultánea (más información en
?mutate_at()). La conversación provocará la introducción de NA, ya que no es posible convertir
cualquier carácter en número.

El último paso antes de seguir con la visualización en ggplot2 será la separación en regiones y
países. Si nos fijamos en la primera variable, Country, vemos que incluye nombres de países y
regiones. Aprovechamos que las regiones están en mayúsculas, lo que podemos detectar con una

70
expresión regular [A-Z], es decir, todas las letras del alfabeto en mayúsculas que por lo menos
aparecen dos veces seguidas. Posteriormente, usamos otra función, ifelse(), para crear una
nueva variable únicamente con los nombres de las regiones; en otras filas dejamos NA. La existencia
de NA y el orden de aparición de las regiones nos permite usar la función na.locf() del paquete
zoo. Esta función sustituye los NA con el valor más reciente que no es NA.

3.2.2 Gráficos de puntos


Podemos crear un scatterplot en un análisis exploratorio de la relación entre esperanza de vida y
educación terciaria de mujeres.

71
72
73
Los códigos para el tipo de punto o símbolo se muestran a continuación:

Nota: La función aes() puede estar en ggplot() o en geom_*(), o ambos para añadir o sobre
escribir definiciones. Incluso, podemos definir el objeto dentro de geom_*() usando el argumento
data = df.

74
75
3.2.3 Cambiar colores
En el último gráfico ggplot usa unos colores por defecto. Si queremos cambiar la gama, podemos
hacer uso de las funciones scale_color_*. No obstante, debemos recordar que nuestra variable
empleada es un factor. Por lo tanto, únicamente podemos usar scale_color_hue(),
scale_color_grey(), scale_color_manual(), scale_color_brewer(), etc., que
corresponden a valores discretos. A continuación utilizaremos los esquemas de colores disponibles
en http://colorbrewer2.org/ y que están integrados en R mediante el paquete RColorBrewer.

Una alternativa interesante es la proporcionada por el paquete colorspace (más detalles en la


vignette: https://cran.r-project.org/web/packages/colorspace/vignettes/colorspace.html), que
tiene funciones para ggplot2 con las que podemos definir nuevas escalas de color:
scale_color_continuous_diverging() o scale_color_continuous_sequential().

76
También es posible usar la función choose_palette(), que nos abre una ventana en la que
podemos definir nuestra gama de colores y asignarla a un objeto. Se trata de un objeto que devuelve
el número de colores requerido (el máximo número está limitado por el número escogido), aunque
tiene una pequeña desventaja, y es que necesita que escojamos manualmente los colores cada vez
que la ejecutamos.

77
Para hacer un uso fácil de las paletas de color de brewer.colors existe la función
scale_color_brewer().

78
79
3.2.4 Transformaciones estadísticas
ggplot permite realizar transformaciones estadísticas fácilmente, como por ejemplo una curva
suavizada entre las dos variables. Este elemento estadístico se puede crear usando geom_smooth()
o stat_smooth(). Por defecto, stat_smooth() usa Locally Estimated Scatterplot Smoothing
(LOESS) (< 1000 observaciones) o Generalized Addive Model (GAM), es decir, una curva no lineal. Se
puede cambiar el método cambiando el argumento method, que en este caso está establecido como
lm, lo que representa una regresión lineal (linear model, lm).

80
3.2.5 Cambios en los ejes
Los ajustes en los ejes se pueden hacer añadiendo parámetros scale_*, por ejemplo:
scale_x_continuous(), scale_x_discrete(), scale_x_date(), etc.

81
Aquí hemos usado breaks para fijar los intervalos de corte donde queremos etiquetas. También
podemos usar label para indicar las etiquetas para cada uno de estos intervalos fijados. Por defecto,
si no se indican otros labels, ggplot2 escoge los breaks como etiquetas. Es posible definir
algunas transformaciones con el argumento trans en las funciones de tipo scale_x_continuous()
(entre otras, exp, sqrt, ...).

Nota: Es aconsejable evitar transformaciones directamente sobre los datos originales. Por eso
existen las funciones que transforman los datos al crear el gráfico.

3.2.6 Cambiar el estilo del gráfico


ggplot cuenta con un considerable número de extensiones (https://www.ggplot2-exts.org/). El
paquete ggthemes amplía los estilos generales de los gráficos y nos permite cambiar fácilmente el
estilo estándar usando theme_*() (p. ej.: theme_economist()). También se pueden ajustar los
estilos de forma manual a través de la función theme(); en la ayuda se encuentran todos los
argumentos de todos los elementos con sus especificaciones.

82
83
Los parámetros temáticos son muchísimos (ver ayuda ?theme). En función del elemento del gráfico
que queremos cambiar, se usa: element_text(), element_line(), element_rect(), etc.
Además, cada uno de los elementos tiene sus propios argumentos, como angle, size, face, etc.
La función general element_blank() se usa para suprimir cualquier elemento del gráfico.

84
3.2.7 Gráficos de facetas
ggplot tiene la posibilidad de crear facetas, esto es, un gráfico múltiple en función de una o varias
variables discretas. En nuestro caso usaremos el continente como variable. Si nos fijamos en los
datos, la variable es de tipo carácter. Por defecto, cuando se usa facet_grid(), una variable
discreta de caracteres es convertida en un factor, lo que provoca que el orden de las etiquetas sea
alfabético. Las funciones facet_grid() y facet_wrap() usan el formato de fórmula para
especificar en qué forma se crean las facetas: fila ~ columna. En caso de que no dispongamos
de una segunda variable, se indica en la fórmula con un punto “.”. La diferencia entre grid y wrap
es que la primera crea siempre una rejilla regular. Durante los próximos capítulos veremos más
ejemplos incluyendo otros argumentos.

85
86
Para cambiar el orden de las facetas, debemos convertir la variable en un factor y definir el orden
de los niveles (levels).

87
Existen geometrías para una, dos o tres variables, como geom_text() o geom_label(),
geom_histogram(), geom_line(), geom_tile() o geom_raster(), geom_boxplot(), etc. Para
mostrar un ejemplo con otras geometrías, importaremos datos meteorológicos de la estación
Madrid-Retiro (ECA&D).

88
Vemos que son varios archivos con las siguientes variables: DD: Dirección del viento, FG: Velocidad
de viento, HU: Humedad Relativa, TG: Temperatura media.

En el siguiente paso seleccionamos, en cada data.frame de la lista, solo la columna 2 (DATE) y 3


(variable: TG, HU, etc.). Este paso es necesario para unir todas las tablas. Si nos fijamos en el nombre
de la variable, este cambia en cada tabla. Aplicaremos una función, sin asignarla a un nuevo objeto
(llamada “función anónima”), en la que seleccionamos estas columnas por su posición y pasamos
con la función gather() a un formato largo.

89
Primero necesitamos limpiar los datos: convertimos la fecha, creamos una nueva variable year y
además convertimos la variable en factor y sustituimos los -9999 por NA.

3.2.8 Histograma y gráfico de densidad


La alta compatibilidad entre los paquetes de tidyverse permite aplicar una función como
filter() y pasar el resultado con el operador %>% 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.r-
project.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://r-
spatial.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, longitud,


tiempo/variables/etc.), que se organizan como si de un array se tratase (x, y, z).

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://r-
spatial.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/leaflet-
providers/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 (*.sg-
pts). 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 SAGA-
GIS) podemos usar las funciones readLAS() y writeLAS() (https://cran.r-
project.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

También podría gustarte