OpenStreetMap es un servicio de mapas online que publica información contribuida en forma libre por mÔs de un millón de voluntarios, que benefician a los 5,5 millones de usuarios de la plataforma.
Los contribuidores mĆ”s entusiastas mapean barrios completos utilizando herramientas GPS para enviar información local completa, actualizada y precisa a OpenStreetMap. Varias empresas y entidades pĆŗblicas que producen información geogrĆ”fica tambiĆ©n contribuyen al permitir que sus datos sean incluidos. Existen equipos profesionales de contribuidores que que se coordinan para agregar y mantener actualizada información georeferenciada de lĆmites polĆticos, calles, edificios, negocios y otros puntos de interĆ©s; en ocasiones empleados por compaƱĆas que dependen de OpenStreetMap para el āmapa baseā de sus productos, como mapbox.com y carto.com.
Toda la información disponible en OpenStreetMap puede ser descargada y reutilizada por cualquier persona, ya sea accediendo al mapa online, obteniendo una copia completa de la base de datos, o accediendo a los datos vĆa API.
Utilizaremos osmdata, un paquete de R que permite acceder a los datos de OpenStreetMap (OSM de aquĆ en mĆ”s) con sus atributos, geometrĆa y posición.
Como siempre, si no tenemos aĆŗn el paquete lo instalamos:
library(osmdata)
Y lo activamos junto a otros paquetes que vamos a utilizar:
library(osmdata)
library(tidyverse) # nuestra navaja suiza para manipulación y visualización de datos
library(sf) # para procesar info espacial
library(leaflet) # Para generar mapas interactivos
Antes de descargar información, definimos el lugar que queremos consultar. Ćste puede ser un barrio, un municipio, un paĆs, un continente⦠en Ć©ste caso, lo intentaremos con la ciudad de Rosario.
Las funciones de osmdata nos permiten realizar consultas a Overpass (http://overpass-api.de/), una interfaz que permite extraer información de la base de datos global de OpenStreetMap. Overpass requiere que se especifique una ābounding boxā, es decir las coordenadas de un rectĆ”ngulo que abarque la zona de interĆ©s.
Podemos obtener la bounding box de cualquier lugar con la función getbb():
bbox <- getbb("Rosario, Santa Fe")
bbox
## min max
## x -60.78326 -60.61167
## y -33.03487 -32.86965
Con getbb() tambiĆ©n podemos obtener un polĆgono con los lĆmites polĆticos, las fronteras exactas, de un lugar. Esto es muy Ćŗtil para realizar mapas, o para filtrar la información que obtendremos luego para quedarnos sólo con la que corresponda a nuestra ciudad de interĆ©s, descartando la de Ć”reas aledaƱas:
bbox_poly <- getbb("Municipio de Rosario, Santa Fe", format_out = "sf_polygon")
Para asegurarnos de que tenemos el lugar que queremos, y no otro de nombre similar en alguna otra parte del mundo, lo verificamos en un mapa rĆ”pido provisto vĆa leaflet:
leaflet(bbox_poly) %>%
addTiles() %>%
addPolygons()
Luce bien, asĆ que continuamos.
El siguiente paso es utilizar la función add_osm_feature() para especificar los datos que queremos descargar. Esto requiere conocer las palabras clave con las que se identifican los registras en la base de OSM, que permiten indicar con gran detalle el tipo de datos georeferenciados que queremos: ya sean Ć”reas de parques pĆŗblicos, posición de oficinas de correo o cajeros automĆ”ticos, vĆas de ferrocarril⦠u otro, en un larguĆsimo etcĆ©tera que se puede consultar en https://wiki.openstreetmap.org/wiki/Map_Features
En este caso vamos a solicitar todas las vĆas de circulación (calles, avenidas, autopistas, etc) de la ciudad. En la base de datos de OSM todas aparecen con la clave āhighwayā.
rosario <- opq(bbox) %>%
add_osm_feature(key = "highway")
Observemos que lo único que hemos obtenido hasta ahora es la definición de una consulta (qué y en dónde), pero aun no descargamos ningún dato:
rosario
## $bbox
## [1] "-33.0348662,-60.7832623,-32.8696532,-60.6116695"
##
## $prefix
## [1] "[out:xml][timeout:25];\n(\n"
##
## $suffix
## [1] ");\n(._;>;);\nout body;"
##
## $features
## [1] " [\"highway\"]"
##
## attr(,"class")
## [1] "list" "overpass_query"
Es sólo la definición de una consulta a la base de datos de OpenStreetMap: āTodas las calles (objetos con claveāhighwayā) dentro de Ć©ste rectĆ”ngulo (que sabemos, corresponde a Rosario)ā. Para hacer efectiva la consulta y descargar los datos, la pasamos por la función osmdata_sf() que recolecta lo que buscamos y lo entrega en forma de dataset espacial:
rosario <- rosario %>%
osmdata_sf()
La descarga de información para una ciudad grande puede tomar varios minutos, y mĆ”s aĆŗn la de un Ć”rea metropolitana (o paĆs, o continente, etc) asĆ que es normal esperar un poco en Ć©sta parte.
En cuanto se completa, ya tenemos calles:
rosario
La consulta devolvió toda la información de puntos, lĆneas y polĆgonos disponibles en la base de OSM. A nos otros nos interesan las lĆneas, āosm_linesā, que demarcan la traza de las calles. Los registros con otras geometrĆas, como polĆgonos, pueden representar elementos asociados a las calles como bulevares o Ć”reas de vereda que no vamos a usar por el momento.
Del conjunto de datos disponibles, extraemos el dataframe con lĆneas, y chequeamos los atributos disponibles. Todos han sido recopilados por la comunidad de OpenStreetMap.
calles <- rosario$osm_lines
head(calles)
Dado que las calles han sido descargadas en formato sf, podemos visualizarlas con ggplot: y geom_sf:
ggplot() +
geom_sf(data = calles)
Las calles exceden los lĆmites de Rosario, ya que tenemos todos los datos encontrados dentro del rectĆ”ngulo de la bounding box. Para ārecortarā los datos conservando solo las calles de la ciudad, podemos extraer su intersección con el polĆgono de lĆmites que obtuvimos antes.
calles <- st_intersection(calles, bbox_poly)
Ahora si!
ggplot() +
geom_sf(data = calles)
Podemos visualizar atributos de las calles, por ejemplo el de la velocidad mÔxima permitida, que estÔ presente para casi todas. Pero antes va a ser necesario limpiar un poco los datos⦠como es usual.
Los dataframes en formato sf que crea osmdata tienen todos los valores en formato texto, incluso aquellos que son números como maxspeed (la velocidad mÔxima), o lanes, la cantidad de carriles. Lo arreglamos:
calles <- calles %>%
mutate(maxspeed = as.numeric(maxspeed),
lanes = ifelse(is.na(lanes), 1, as.numeric(lanes)))
Con eso tenemos limpias las variables de velocidad mƔxima y ancho en carriles. Listos para visualizar.
ggplot(calles) +
geom_sf(aes(color = maxspeed), alpha = 0.5) +
scale_color_viridis_c() +
theme_void() +
labs(title = "Rosario",
subtitle = "VĆas de circulación",
caption = "fuente: OpenStreetMap",
color = "velocidad mƔxima")
O podemos revisar la posición de las avenidas:
ggplot() +
geom_sf(data = calles,
color = "gray40", alpha = .5) +
geom_sf(data = filter(calles, str_detect(name, "Avenida")),
color = "salmon") +
theme_void() +
labs(title = "Rosario",
subtitle = "Avenidas",
caption = "fuente: OpenStreetMap")
Imaginemos que estamos interesados en identificar y caracterizas los bares presentes en un barrio determinado, como San Telmo en la Ciudad de Buenos Aires. Como punto de partida, podemos consultar la base de OSM a ver que encontramos.
Comenzamos por definir nuestra Ɣrea de interƩs
bbox_st <- getbb('San Telmo, Ciudad Autonoma de Buenos Aires')
bbox_st_poly = getbb('San Telmo, Ciudad Autonoma de Buenos Aires', format_out = "sf_polygon")
leaflet(bbox_st_poly) %>%
addTiles() %>%
addPolygons()
Habiendo verificado que tenemos el Ɣrea correcta, armamos una consulta por la grilla de calles, y la ejecutamos.
SanTelmo_calles <- opq(bbox_st) %>%
add_osm_feature(key = "highway") %>%
osmdata_sf()
Y tambiĆ©n descargamos información sobre la posición de bares. Habiendo revisado https://wiki.openstreetmap.org/wiki/Map_Features, sabemos que para obtener bares necesitamos la categorĆa āamenityā, y el subtipo ābarā. En tĆ©rminos de OSM, key = "amenity", value = "bar":
SanTelmo_bares <- opq(bbox_st) %>%
add_osm_feature(key = "amenity", value = "bar") %>%
osmdata_sf()
Extraemos la información dentro de los lĆmites exactos del barrio.
A diferencia de las calles, que aparecen en la geometrĆa de lĆneas, para los bares nos interesan los puntos.
SanTelmo_calles <- st_intersection(SanTelmo_calles$osm_lines, bbox_st_poly)
SanTelmo_bares <- st_intersection(SanTelmo_bares$osm_points, bbox_st_poly)
Y listos para mapear! De paso, resaltamos aquellos donde se baila tango, al colorear segĆŗn el atributo ādance.styleā, incluido en los datos.
ggplot() +
geom_sf(data = SanTelmo_calles,
color = "darkslateblue") +
geom_sf(data = SanTelmo_bares,
aes(color = dance.style)) +
geom_sf_label(data = SanTelmo_bares,
aes(label = name), size = 2) +
theme_void() +
labs(title = "San Telmo",
subtitle = "Bares",
caption = "fuente: OpenStreetMap",
color = "Ofrecen baile")
Casi listo. Antes de darnos por satisfechos, tenemos que mejorar la ubicación de las etiquetas, que se superponen por la proximidad de los lugares.
Por el momento geom_sf_label() -la geometrĆa de ggplot que permite graficar etiquetas de datos sf- no incluye la Ćŗtil opción de correr la posición de las etiquetas en forma automĆ”tica para que no se solapen. Por suerte, existe un pequeƱo paquete, ggsflabel, que provee la funcionalidad que necesitamos.
Podemos instalar el paquete directo desde el repositorio de su autor:
install.packages("devtools")
devtools::install_github("yutannihilation/ggsflabel")
library(ggsflabel)
Y ahora, usamos geom_sf_label_repel() para la versión final de nuestro mapa de bares en San Telmo:
ggplot() +
geom_sf(data = SanTelmo_calles,
color = "darkslateblue") +
geom_sf(data = SanTelmo_bares,
aes(color = dance.style)) +
geom_sf_label_repel(data = SanTelmo_bares,
aes(label = name), size = 2) +
theme_void() +
labs(title = "San Telmo",
subtitle = "Bares",
caption = "fuente: OpenStreetMap",
color = "Ofrecen baile")