9  Mapas con ggmap

Con ggplot2 pueden construirse muchos tipos de gráficos de interés estadístico. Pero sus autores quisieron trasladar la arquitectura del paquete a otro ámbito: el de la representación de información georreferenciada. ggplot2 permite representar información geográfica (puntos, segmentos, etc.): basta con que las estéticas x e y se correspondan con la longitud y la latitud de los datos. Lo que permite hacer ggmap es, en esencia, añadir a los gráficos ya conocidos una capa cartográfica adicional. Para eso usa recursos disponibles en la web a través de APIs (de Google y otros).

Parte de las funciones en ggmap se apoyan en servicios que proporciona Google a través de APIs. Como se indica en ?register_google, desde mediados de 2018 estos servicios no son de libre acceso sino que hay que registrarse en la plataforma de mapas de Google y obtener una key personal. Además, es necesario abrir una cuenta, introducir la tarjeta de crédito, etc. Eso sí, Google proporciona cierto número de llamadas gratuitas al mes, mucho más que suficientes para un uso esporádico y no intensivo de estas herramientas, por lo que el coste de usarlas —al menos, en lo que concierne al presente capítulo— es cero.

A lo largo del capítulo se asumirá que el lector se ha registrado en la plataforma de Google siguiendo las instrucciones que se detallan ?register_google. Como alternativa, puede explorar por su cuenta y riesgo otras plataformas o paquetes de R que proporcionan servicios similares, en ocasiones gratuitos, como caRtociudad, pero que quedan fuera del alcance de este capítulo.

Un ejemplo sencillo ilustra los usos de ggmap. En primer lugar, se carga (si se ha instalado previamente) el paquete:

library(ggmap)

Como se ha indicado en la nota anterior, es necesario registrar la key de Google para poder usar gran parte de las funciones de dicho paquete:

register_google("saiiS_my_personal_key_W8sSA")

La función geocode encapsula la consulta a dicha API y devuelve un objeto (un data.frame) que contiene las coordenadas del lugar de interés:

unizar <- geocode('Calle de Pedro Cerbuna 12, Zaragoza, España',
                  source = "google")

La función get_map consulta otro servicio de información cartográfica (GoogleMaps en el ejemplo siguiente) y descarga un mapa (que es, esencialmente, una imagen raster). La función exige una serie de argumentos: el nivel de zoom, si se quiere un mapa de carreteras o del terreno, etc. Son, de hecho, los parámetros que uno puede manipular con los controles de la interfaz habitual de GoogleMaps.

map.unizar <- get_map(location = as.numeric(unizar),
                      color = "color",
                      maptype = "roadmap",
                      scale = 2,
                      zoom = 16)

Es obvio que para poder invocar las dos funciones anteriores hace falta una conexión a internet. Sin embargo, el resto de las operaciones que se van a realizar se ejecutan localmente. Se puede, por ejemplo, representar el mapa directamente (haciendo ggmap(map.unizar)). O bien se puede marcar sobre él el punto de interés:

ggmap(map.unizar) + geom_point(aes(x = lon, y = lat),
                               data = unizar, colour = 'red',
                               size = 4)

Como veremos a continuación, no estamos limitados a representar un único punto: unizar podría ser una tabla con más de una fila y todos los puntos se representarían sobr el mapa.

Como puede apreciarse, la sintaxis es similar a la de ggplot2. Una diferencia notables que, ahora, los datos se pasan en la capa, es decir, en este caso, en la función geom_point.

9.1 Funciones de ggmap

ggmap incluye muchas funciones que pueden clasificarse en tres categorías amplias:

  • Funciones para obtener mapas (de diversos tipos y de distintos orígenes: Google, Stamen, OpenStreetMap)
  • Funciones que utilizan APIs de Google y otros. Por ejemplo, geocode, revgeocode y route consultan la información que tienen distintos proveedores de servicios vía API sobre las coordenadas de un determinado lugar; indican el lugar al que se refieren unas coordenadas y, finalmente, encuentran rutas entre dos puntos. Es conveniente recordar que las consultas a los servicios de Google Maps exige la aceptación de las condiciones de uso y que existe un límite diario en el número de consultas gratuitas.
  • Funciones que pintan mapas y que representan determinados elementos adicionales (puntos, segmentos, etc.) en mapas.

En esta sección se van a presentar los tres tipos de funciones de ggmap.

9.1.1 Funciones para obtener mapas

ggmap obtiene sus mapas, por defecto, de GoogleMaps. Sin embargo hay otros proveedores de mapas libres, como OpenStreetMap (OSM) o Stamen. Cada proveedor exige una serie de parámetros distintos y, por ejemplo, un zoom de 8 puede significar una escala distinta en GoogleMaps que en OSM. Sin embargo, los autores de ggmap se han tomado la molestia de homogeneizar los argumentos de llamada para que sean aproximadamente equivalentes en todos los proveedores.

ggmap incluye funciones específicas para cada proveedor, como get_googlemap o get_stamenmap, pero salvo para usos avanzados, es recomendable usar la función get_map, que ofrece un punto de entrada único y homogéneo para el resto.

El gráfico siguiente muestra cuatro mapas obtenidos de diversos proveedores y con diversas opciones. En la fila superior, una capa de Google en modo imagen de satélite y otra estándar. En la inferior, dos mapas de Stamen, uno en modo toner y otro en modo watercolor o acuarela. Son solo cuatro de los muchos a los que la función get_map puede acceder.

Ejercicio 9.1 Representa la ubicación de la universidad de Zaragoza (u otra que prefieras) con otros tipos de mapas, otros zums, etc.

9.1.2 Funciones para consultar APIs cartográficas

Muchos servicios de información cartográfica proporcionan APIs para realizar consultas. Las APIs se consultan, típicamente, con URLs convenientemente construidas. Por ejemplo, la URL

http://maps.googleapis.com/maps/api/geocode/json?address=Universidad+de+Zaragoza

consulta el servicio de geolocalización de GoogleMaps y devuelve las coordenadas de la Universidad de Zaragoza (así como otra información relevante en formato JSON). La función geolocate de ggmap facilita la consulta a dicho servicio: toma su argumento (el nombre de un lugar), construye internamente la URL, realiza la consulta (para lo que es necesario conexión a internet), lee la respuesta y le da un formato conveniente (en este caso, un data.frame de R).

La de geolocalización no es la única API que permite consultar ggmap. También permite invertir la geolocalización, es decir, dadas unas coordenadas, devolver el nombre del lugar al que se refieren:

revgeocode(as.numeric(unizar))
[1] "C. de Pedro Cerbuna, 12, 50009 Zaragoza, Spain"

Finalmente, route permite obtener la ruta entre dos puntos distintos:

mapa <- get_map("Madrid", source = "stamen", maptype = "toner", zoom = 12)
ruta <- route(from = "Puerta del Sol, Madrid", to = "Plaza de Castilla, Madrid")
ggmap(mapa) +
  geom_path(aes(x = start_lon, y = start_lat, xend = end_lon, yend = end_lat),
            colour = "red", size = 2, data = ruta)

En el mapa anterior la ruta elegida por GoogleMaps para ir de la Puerta del Sol hasta la plaza de Castilla (dos plazas de Madrid) está marcado en rojo sobre un mapa de Stamen de tipo toner.

9.1.3 Funciones para representar elementos sobre mapas

Como se ha visto en las secciones anteriores, la función ggmap permite representar un mapa descargado previamente. Además, a esa capa subyacente se le pueden añadir elementos (puntos, segmentos, densidades etc.) usando las funciones ya conocidas de ggplot2: geom_point, etc.

En ggplot2 existe una función, geom_path que dibuja caminos (secuencias de segmentos). Se puede utilizar en ggmap para dibujar rutas, aunque este paquete proporciona una función especial, geom_leg que tiene la misma finalidad aunque con algunas diferencias menores: por ejemplo, los segmentos tienen las puntas redondeadas, para mejorar el resultado gráfico.

9.2 Ejemplos

En los ejemplos que siguen se va a utilizar el conjunto de datos crimes que forma parte del paquete ggmap y que incluye información geolocalizada de crímenes cometidos en la ciudad de Houston. En realidad, solo consideraremos los crímenes serios, es decir,

crimes.houston <- subset(crime, ! crime$offense %in% c("auto theft", "theft", "burglary"))

9.2.1 Puntos sobre mapas

El tipo de mapas más simples son los que se limitan a representar puntos sobre una capa cartográfica.

HoustonMap <- qmap("houston", zoom = 14, color = "bw")
HoustonMap +
  geom_point(aes(x = lon, y = lat, colour = offense), data = crimes.houston, size = 1)

En el código anterior hemos usado la función qmap, una función auxiliar que internamente llama primero get_map y luego a ggmap.

Los mecanismos conocidos de ggplot2, como las facetas, están disponibles en ggmap: es posible crear una retícula de mapas usando facet_wrap. En este primer caso, descomponiendo el gráfico anterior por tipo de crimen.

HoustonMap +
  geom_point(aes(x = lon, y = lat), data = crimes.houston, size = 1) +
  facet_wrap(~ offense)

O, alternativamente, por día de la semana.

HoustonMap +
  geom_point(aes(x = lon, y = lat), data = crimes.houston, size = 1) +
  facet_wrap(~ day)

Ejercicio 9.2 Prueba a pintar las gasolineras en el mapa de España (fichero dat/carburantes_20050222.csv).

Ejercicio 9.3 Baja datos georreferenciados del portal de datos abiertos del ayuntamiento de Madrid y represéntalos sobre un mapa.

9.2.2 Rutas sobre mapas

Vamos a hacer una digresión para representar información geográfica contenida en ficheros .kml usando ggmap como ejemplo de la versatilidad del paquete.

library(maptools)
# un fichero bajado el Ayto. de Madrid
rutas <- getKMLcoordinates("data/130111_vias_ciclistas.kml")

El conjunto de datos anterior contiene una lista de rutas (inspecciónalo), que queremos convertir en una única tabla para poder representarlas gráficamente con ggmap.

library(plyr)
rutas <- ldply(1:length(rutas), function(x) data.frame(rutas[[x]], id = x))
mapa <- get_map("Madrid", source = "stamen", maptype = "toner", zoom = 12)
ggmap(mapa) + geom_path(aes(x = X1, y = X2, group = id), data = rutas, colour = "red")

9.2.3 Más allá de los puntos: densidades y retículas

Además de geom_point, también están disponibles otros tipos de capas de ggplot2, como stat_bin2d, que cuenta el número de eventos que suceden en regiones cuadradas de un tamaño predefinido.

HoustonMap +
  stat_bin2d(
    aes(x = lon, y = lat, colour = offense, fill = offense),
    size = .5, bins = 30, alpha = 1/2,
    data = crimes.houston
  )

O se puede usar stat_density2d, que representa intensidades, para identificar las zonas de mayor criminalidad.

HoustonMap +
  stat_density2d(aes(x = lon, y = lat, fill = ..level.., alpha = ..level..),
                 size = 2, data = crimes.houston,
                 geom = "polygon"
)

Ejercicio 9.4 Lee este artículo y consulta qué otras cosas (además de puntos) pueden representarse sobre un mapa.

9.3 Resumen y referencias

ggmap extiende el paquete ggplot2 para representar información geográfica. Sin embargo, en R existen otros paquetes para procesar información geográfica. De hecho, existe una colección de paquetes construidos alrededor del fundamental, sf (de Simple Features) que fue diseñado para aplicaciones en geoestadística y que permiten hacer de R, prácticamente, un GIS (geographic information system). Estos paquetes permiten, por ejemplo, procesar shapefiles, que son ficheros usados en muchos GIS para almacenar información geográfica. El INE y otros organismos estadísticos suelen diseminar información con una componente geográfica en este formato. sf es el sucesor de sp, aún popular peor en estado de progresiva desaparición, gracias al cual se han reorganizado los paquetes relacionados con la información geográfica alrededor de un nuevo estándar, Simple Feature Access (véase http://www.opengeospatial.org/standards/sfa).

Además de lo anterior, paquetes como leaflet permiten crear mapas dinámicos en los que es posible hacer zum, desplegar marcadores, etc. De hecho, en múltiples aplicaciones y, en particular, las interactivas desarrolladas con shiny o flexdashboard, leaflet es preferible a ggmap.

Finalmente, los usuarios interesados en información geográfica española, tienen a su disposición el paquete caRtociudad, que explota una API del Instituto Geográfico Nacional que proporciona servicios similares a los de ggmap: mapas, geolocalización, rutas, etc. Tiene algunas ventajas con respecto a ggmap, como que no tiene restricción en el número de llamadas y que, además, proporciona información administrativa adicional, como códigos postales, secciones censales o de referencias catastrales.

9.4 Ejercicios adicionales

Ejercicio 9.5 Busca rutas en tu localidad y represéntalas sobre un mapa.

Ejercicio 9.6 El fichero carburantes_20050222.csv contiene información sobre todas las gasolineras de España y los precios de los carburantes. Incluye las coordenadas geográficas de los surtidores. Representa esos datos sobre un mapa de España (o de tu provincia o municipio). Modifica el tamaño (o color) de los puntos en función de, por ejemplo, el precio de los carburantes.