peteris.rocks

OpenStreetMap administrative boundaries in GeoJSON

Extracting city administrative boundaries as GeoJSON polygons from OpenStreetMap data

Last updated on

Step 1 - find relation ID

Option A - openstreetmap.org

Go to openstreetmap.org and search for your city or neighborhood.

On the left side and also in the URL you'll see the relation ID.

OpenStreetMap showing Riga with its relation ID

Write that down.

Option B - Nominatim

Go to nominatim.openstreetmap.org and search for your city.

Then click the Details button in the search results.

Scroll down until you see the OSM column in the table.

Nominatim showing Riga OSM relation ID

Write down the relation ID number.

If you scroll down to the Administrative table, you can also find the administrative boundaries in this city.

Nominatim showing Riga OSM administrative boundaries

Step 2 - generate polygon in GeoJSON

Go to polygons.openstreetmap.fr and enter the ID of the relation.

Or just go directly to http://polygons.openstreetmap.fr/?id=RELATIONID

OpenStreetMap polygons

Then click on the first GeoJSON link.

OpenStreetMap polygons

Or just go directly to http://polygons.openstreetmap.fr/get_geojson.py?id=RELATONID&params=0

Script

Here is a script that will download GeoJSON files of several administrative boundaries.

Create a tab separated file (osm.relations.txt) with name-relation pairs

Rīga    2921953
Āgenskalns    450690
Atgāzene    1554508
Avoti    1727754
Beberbeķi    5598409
Berģi    1727755
Bieriņi    1726817

Then install the necessary node.js dependencies

npm install request async

Create the script osm-relations.js

// http://nominatim.openstreetmap.org/details.php?place_id=143216199
// http://polygons.openstreetmap.fr/?id=2921953

var request = require('request')
var async = require('async')
var fs = require('fs')

var inputFile = process.argv[2]
var outputFile = process.argv[3]

var data = {}
var relations = fs.readFileSync(inputFile).toString().split('\n').map(line => line.split('\t'))

var queue = async.queue(osm2geojson, 1)
queue.drain = save
queue.push(relations)

function osm2geojson(array, cb) {
  var [name, id] = array
  console.log(name, id)

  request('http://polygons.openstreetmap.fr/get_geojson.py?id=' + id + '&params=0', (err, res, body) => {
    if (err) return cb(err)
    if (body == 'None\n') return cb()
    data[id] = { id: id, name: name, geo: JSON.parse(body) }
    cb()
  })
}

function save() {
  var geojson = { "type": "FeatureCollection", "features": [] }
  for (var id in data) {
    var region = data[id]
    geojson.features.push({
      "type": "Feature", 
      "properties": {
        "osm-relation-id": region.id,
        "name": region.name
      },
      "geometry": region.geo.geometries[0]
    })
  }
  fs.writeFileSync(outputFile, JSON.stringify(geojson, null, 2))
}

Run it with node.js 6.x and later

node osm-relations.js osm-relations.txt riga.geojson

Do not abuse this service.

The output file will look something like this

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "osm-relation-id": "147426",
        "name": "Imanta"
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [
                23.9574542,
                56.956114
              ],
              ...
            ]
          ]
        ]
      }
    },
    ...
  ]
}

Explore results

geojson.io is an easy to use tool to visually see the generated output file on a map.

Go to geojson.io, click Open, then File and choose the generated file.

geojson.io map showing administrative boundaries in Riga

You can also manually delete and draw polygons in this tool.