Introducing the nominatim geocoding package

[This article was first published on rud.is » R, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

In the never-ending battle for truth, justice and publishing more R packages than Oliver, I whipped out an R package for the OpenStreetMap Nominatim API. It actually hits the MapQuest Nominatim Servers 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 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

seattle_map-1

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 and submit feature requests/issues to github!

To leave a comment for the author, please follow the link and comment on their blog: rud.is » R.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)