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!
3 Comments
You mention for bulk-geocoding using a paid for service. I have access to a paid for nominatim server with a company I work for. They currently use Python to do geocoding but I would like to use R. Could you point me in the right direction to start doing this? I see that you want to add this functionality to the nominatim package.
The github version of nominatim allows for specifying a server directly. If that doesn’t work, let me know which paid nominatim service you are using as I need to make a change for new authentication requirements from MapQuest and can try to make it more flexible depending on the server type (I suspect most of the paid services will end up using different auth mechanisms)
I’m getting “Please provide a openstreet API key”, on my first (and subsequent) searches, help?
One Trackback/Pingback
[…] projet Nominatim semble être le plus abouti. Un package a récemment été publié, le bien nommé nominatim, qui permet de faire des requêtes sur une instance de l’API (chez MapQuest). Comme ce […]