In the never-ending battle for truth, justice and publishing more R
packages than [Oliver](http://twitter.com/quominus), I whipped out an R
package for the [OpenStreetMap Nominatim
API](http://wiki.openstreetmap.org/wiki/Nominatim). It actually hits the
[MapQuest Nominatim Servers](http://open.mapquestapi.com/nominatim/) for
most of the calls, but the functionality is the same.
The R package lets you:
– `address_lookup`: Lookup the address of one or multiple OSM objects
like node, way or relation.
– `osm_geocode`: Search for places by address
– `osm_search`: Search for places
– `osm_search_spatial`: Search for places, returning a list of
`SpatialPointsDataFrame`, `SpatialLinesDataFrame` or a
`SpatialPolygonsDataFrame`
– `reverse_geocode_coords`: Reverse geocode based on lat/lon
– `reverse_geocode_osm`: Reverse geocode based on OSM Type & Id
Just like Google Maps, these services are not meant to be your
freebie-access to mega-bulk-geocoding. You can and should pay for that.
But, when you need a few items geocoded (or want to lookup some
interesting things on OSM since it provides [special
phrases](http://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
to work with), Nominatim lookups can be just what’s needed.
Let’s say we wanted to see where pubs are in the Seattle metro area.
That’s a simple task for nominatim:
# devtools::install_github("hrbrmstr/nominatim") library(nominatim) library(dplyr) sea_pubs <- osm_search("pubs near seattle, wa", limit=20) glimpse(sea_pubs) ## Observations: 20 ## Variables: ## $ place_id (chr) "70336054", "82743439", "11272568", "21478701", "... ## $ licence (chr) "Data © OpenStreetMap contributors, ODbL 1.0. htt... ## $ osm_type (chr) "way", "way", "node", "node", "node", "node", "no... ## $ osm_id (chr) "51460516", "96677583", "1077652159", "2123245933... ## $ lat (dbl) 47.64664, 47.63983, 47.60210, 47.62438, 47.59203,... ## $ lon (dbl) -122.3503, -122.3023, -122.3321, -122.3559, -122.... ## $ display_name (chr) "Nickerson Street Saloon, 318, Nickerson Street, ... ## $ class (chr) "amenity", "amenity", "amenity", "amenity", "amen... ## $ type (chr) "pub", "pub", "pub", "pub", "pub", "pub", "pub", ... ## $ importance (dbl) 0.201, 0.201, 0.201, 0.201, 0.201, 0.201, 0.201, ... ## $ icon (chr) "http://mq-open-search-int-ls03.ihost.aol.com:800... ## $ bbox_left (dbl) 47.64650, 47.63976, 47.60210, 47.62438, 47.59203,... ## $ bbox_top (dbl) 47.64671, 47.63990, 47.60210, 47.62438, 47.59203,... ## $ bbox_right (dbl) -122.3504, -122.3025, -122.3321, -122.3559, -122.... ## $ bbox_bottom (dbl) -122.3502, -122.3022, -122.3321, -122.3559, -122....
We can even plot those locations:
library(rgdal) library(ggplot2) library(ggthemes) library(sp) library(DT) # Grab a neighborhood map of Seattle url <- "https://data.seattle.gov/api/file_data/VkU4Er5ow6mlI0loFhjIw6eL6eKEYMefYMm4MGcUakU?filename=Neighborhoods.zip" fil <- "seattle.zip" if (!file.exists(fil)) download.file(url, fil) if (!dir.exists("seattle")) unzip(fil, exdir="seattle") # make it usable sea <- readOGR("seattle/Neighborhoods/WGS84/Neighborhoods.shp", "Neighborhoods") ## OGR data source with driver: ESRI Shapefile ## Source: "seattle/Neighborhoods/WGS84/Neighborhoods.shp", layer: "Neighborhoods" ## with 119 features ## It has 12 fields sea_map <- fortify(sea) # Get the extenes of where the pubs are so we can "zoom in" bnd_box <- bbox(SpatialPoints(as.matrix(sea_pubs[, c("lon", "lat")]))) # plot them gg <- ggplot() gg <- gg + geom_map(data=sea_map, map=sea_map, aes(x=long, y=lat, map_id=id), color="black", fill="#c0c0c0", size=0.25) gg <- gg + geom_point(data=sea_pubs, aes(x=lon, y=lat), color="#ffff33", fill="#ff7f00", shape=21, size=4, alpha=1/2) # decent projection for Seattle-y things and expand the zoom/clip a bit gg <- gg + coord_map("gilbert", xlim=extendrange(bnd_box["lon",], f=0.5), ylim=extendrange(bnd_box["lat",], f=0.5)) gg <- gg + labs(title="Seattle Pubs") gg <- gg + theme_map() gg <- gg + theme(title=element_text(size=16)) gg
Of course you can geocode:
addrs <- osm_geocode(c("1600 Pennsylvania Ave, Washington, DC.", "1600 Amphitheatre Parkway, Mountain View, CA", "Seattle, Washington")) addrs %>% select(display_name) ## Source: local data frame [3 x 1] ## ## display_name ## 1 Washington, District of Columbia, United States of America ## 2 Mountainview Lane, Huntington Beach, Orange County, California, 92648, Unit ## 3 Seattle, King County, Washington, United States of America addrs %>% select(lat, lon) ## Source: local data frame [3 x 2] ## ## lat lon ## 1 38.89495 -77.03665 ## 2 33.67915 -118.02588 ## 3 47.60383 -122.33006
Or, reverse geocode:
# Reverse geocode Canadian embassies # complete list of Canadian embassies here: # http://open.canada.ca/data/en/dataset/6661f0f8-2fb2-46fa-9394-c033d581d531 embassies <- data.frame(lat=c("34.53311", "41.327546", "41.91534", "36.76148", "-13.83282", "40.479094", "-17.820705", "13.09511", "13.09511"), lon=c("69.1835", "19.818698", "12.50891", "3.0166", "-171.76462", "-3.686115", "31.043559", "-59.59998", "-59.59998"), stringsAsFactors=FALSE) emb_coded_coords <- reverse_geocode_coords(embassies$lat, embassies$lon) emb_coded_coords %>% select(display_name) ## Source: local data frame [9 x 1] ## ## display_name ## 1 Embassy of Canada, Ch.R.Wazir Akbar Khan, Kabul, Afghanistan ## 2 Monumenti i Skënderbeut, Skanderbeg Square, Lulishtja Këshilli i Europëes, ## 3 Nomentana/Trieste, Via Nomentana, San Lorenzo, Salario, Municipio Roma II, ## 4 18, Avenue Khalef Mustapha, Ben Aknoun, Daïra Bouzareah, Algiers, Ben aknou ## 5 The Hole in the Wall, Beach Road, Āpia, Samoa ## 6 Torre Espacio, 259 D, Paseo de la Castellana, Fuencarral, Fuencarral-El Par ## 7 Leopold Takawira Street, Avondale West, Harare, Harare Province, 00263, Zim ## 8 Bishop's Court Hill, Bridgetown, Saint Michael, Barbados ## 9 Bishop's Court Hill, Bridgetown, Saint Michael, Barbados
It can even return `Spatial` objects (somewhat experimental):
# stock example search from OSM osm_search_spatial("[bakery]+berlin+wedding", limit=5)[[1]] ## coordinates place_id ## 1 (13.34931, 52.54165) 9039748 ## 2 (13.34838, 52.54125) 2659941153 ## 3 (13.35678, 52.55138) 23586341 ## 4 (13.34985, 52.54158) 7161987 ## 5 (13.35348, 52.5499) 29179742 ## licence ## 1 Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright ## 2 Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright ## 3 Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright ## 4 Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright ## 5 Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright ## osm_type osm_id lat lon ## 1 node 939667448 52.54165 13.34931 ## 2 node 3655549445 52.54125 13.34838 ## 3 node 2299953786 52.55138 13.35678 ## 4 node 762607353 52.54158 13.34985 ## 5 node 2661679367 52.54990 13.35348 ## display_name ## 1 Baguetterie, Föhrer Straße, Brüsseler Kiez, Wedding, Mitte, Berlin, 13353, Germany ## 2 Föhrer Cafe & Backshop, Föhrer Straße, Brüsseler Kiez, Wedding, Mitte, Berlin, 13353, Germany ## 3 Körfez, Amsterdamer Straße, Leopoldkiez, Wedding, Mitte, Berlin, 13347, Germany ## 4 Knusperbäcker, Torfstraße, Brüsseler Kiez, Wedding, Mitte, Berlin, 13353, Germany ## 5 Hofbäckerei, Müllerstraße, Brüsseler Kiez, Wedding, Mitte, Berlin, 13353, Germany ## class type importance ## 1 shop bakery 0.201 ## 2 shop bakery 0.201 ## 3 shop bakery 0.201 ## 4 shop bakery 0.201 ## 5 shop bakery 0.201 ## icon ## 1 http://mq-open-search-int-ls04.ihost.aol.com:8000/nominatim/v1/images/mapicons/shopping_bakery.p.20.png ## 2 http://mq-open-search-int-ls04.ihost.aol.com:8000/nominatim/v1/images/mapicons/shopping_bakery.p.20.png ## 3 http://mq-open-search-int-ls04.ihost.aol.com:8000/nominatim/v1/images/mapicons/shopping_bakery.p.20.png ## 4 http://mq-open-search-int-ls04.ihost.aol.com:8000/nominatim/v1/images/mapicons/shopping_bakery.p.20.png ## 5 http://mq-open-search-int-ls04.ihost.aol.com:8000/nominatim/v1/images/mapicons/shopping_bakery.p.20.png ## bbox_left bbox_top bbox_right bbox_bottom ## 1 52.5416504 52.5416504 13.349306 13.349306 ## 2 52.5412496 52.5412496 13.3483832 13.3483832 ## 3 52.5513806 52.5513806 13.3567785 13.3567785 ## 4 52.54158 52.54158 13.3498507 13.3498507 ## 5 52.5499029 52.5499029 13.3534756 13.3534756
The lookup functions are vectorized but there’s a delay built in to
avoid slamming the free servers.
Some things on the TODO list are:
– enabling configuration of timeouts
– enabling switching Nominatim API server providers (you can host your
own!)
– better `Spatial` support
So, give the [code a spin](https://github.com/hrbrmstr/nominatim) and
submit feature requests/issues to github!