Geocode names via API
Posted: | Tags: tilTo plot rail stations on a map for past blogs1 and toots23 I needed to fetch their longitudinal and latitudinal coordinates. This process can be described as geocoding, getting a coordinates from name or address. There are many powerful libraries out there that have the capability to do this, but I wanted something quick and simple to get started, this is where Nominatim comes in. In their own words:
Nominatim (from the Latin, ‘by name’) is a tool to search OSM data by name and address and to generate synthetic addresses of OSM points (reverse geocoding). It has also limited capability to search features by their type (pubs, hotels, churches, etc).
Before using the API, take some time to read their usage policy.
The following query gets up to 10 OSM objects from a search term, in this case, “Amsterdam Centraal”, in JSON format. I’ll be adding those results to a file called “centraal.json” so we can inspect the data later.
curl 'https://nominatim.openstreetmap.org/search?q=Amsterdam+Centraal&format=json' >> centraal.json
This request returns a list in the following format.
[
{
"place_id":170500094,
"licence":"Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright",
"osm_type":"node",
"osm_id":4573124013,
"lat":"52.3789084",
"lon":"4.901278",
"class":"railway",
"type":"stop",
"place_rank":30,
"importance":9.99999999995449e-06,
"addresstype":"railway",
"name":"Amsterdam Centraal",
"display_name":"Amsterdam Centraal, Oosttunnel, Centrum, Amsterdam, Noord-Holland, Nederland, 1012 AA, Nederland",
"boundingbox":[
"52.3788584",
"52.3789584",
"4.9012280",
"4.9013280"
]
},
... rest omitted
]
Objects of various “types” are returned, I’d like to only see stations so I use jq
to filter out only the object of type “station”.
cat centraal.json | jq '.[] | select(.type=="station")'
{
"place_id": 169180437,
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. http://osm.org/copyright",
"osm_type": "node",
"osm_id": 4290854847,
"lat": "52.378901",
"lon": "4.9005805",
"class": "railway",
"type": "station",
"place_rank": 30,
"importance": 0.4754190541635401,
"addresstype": "railway",
"name": "Amsterdam Centraal",
"display_name": "Amsterdam Centraal, Middentunnel, Centrum, Amsterdam, Noord-Holland, Nederland, 1012 AB, Nederland",
"boundingbox": [
"52.3739010",
"52.3839010",
"4.8955805",
"4.9055805"
]
}
If you do not see the place you’re looking for within the initial 10 objects, you can try increasing the limit to more than 10, although I find this method does not always work. Instead, using the exclude_place_ids
parameter, and passing in a list of the place IDs you’ve already got will return a new list of objects hopefully containing the one you’re looking for.
The following jq
command will return all the place_ids as a string separated by a URI-encoded comma.
cat centraal.json | jq '[.[] | .place_id] | join("%2C")'
We can then paste that string at the end of our new query with the exclude_place_ids
parameter.
curl 'https://nominatim.openstreetmap.org/search?q=Amsterdam+Centraal&format=json&exclude_place_ids=9180437%2C172174754%2C169611729%2C169464979%2C169847839%2C170132670%2C170335664%2C170500094' >> centraal.json
This will return a new list of 10 different OSM objects.
In addition to the API, you can also do the same queries through their webpage. This will allow you to visualise the results returned from the API and give you the formatted query string with the debugging information, accessible from under the search bar. Lastly, you can also see this in use, written in Python, in my rail-maps project on GitHub.