OpenStreetMap to GeoJSON
Posted on 2023-12-19, by Racum.
Use OpenStreetMap as your repository of geometries, and export them in the more convenient GeoJSON format. This technique only works with geometries with area (Polygon and MultiPolygon), points and lines break the exporting tool used here.
Features on OpenStreetMap
OpenStreetMap (OSM for short) has its own file format (OSM XML): this is an open format, but it was designed for OSM’s needs, it is not a good generic geometry format like Shapefile, KML or GeoJSON (specially popular for APIs and databases).
To understand how OSM data is organized, you first need to understand their 3 element types: nodes (points), ways (lines) and relations (groups of nodes and/or lines). There is no native “polygon” type, for example, if you see the limits of a city, the data behind looks like a group of ways (like “north border”, “east border”, etc) and a relation connecting them together. So, it is not a direct match, but “relation” is closest abstraction OSM has to a polygon.
Searching Relation IDs
On an OSM map view, right-click on the area you want to export, and click ”Query features”; if this menu is disabled you need keep zooming-in until it appears clickable:
This will open the “Query Features” panel, inside it, on “Enclosing features”, pick the feature you want, it usually goes smaller to bigger, like: location, neighborhood, city, state, country.
Notice that every feature open a relation page with name, ID, tags and a map. For exporting, the most important information on this page is the relation ID (in parenthesis after the relation name). For the example above on St. Mark's Square in Venice, you’ll get:
- St. Mark's Square: 7932512
- Venezia: 4817103
- Veneto: 43648
- Italian Peninsula: 4056532
Option 1: Online converter tool
The community from OpenStreetMap France created an online tool to convert relations into polygons (although is if provided by the fresh OSM, it works worldwide).
Just paste the relation ID into it, submit, and save the GeoJSON file that it generates:
The output is always a GeoJSON with a MultiPolygon
in its root, even if the feature could fit in a single Polygon
.
You can automate the operation above accessing via curl:
$ curl http://polygons.openstreetmap.fr/get_geojson.py?id=7932512 > st_mark_square.geojson
$ curl http://polygons.openstreetmap.fr/get_geojson.py?id=4817103 > venice.geojson
$ curl http://polygons.openstreetmap.fr/get_geojson.py?id=43648 > veneto.geojson
$ curl http://polygons.openstreetmap.fr/get_geojson.py?id=4056532 > italy.geojson
Option 2: Self-hosted converter tool
If you don’t want to depend on 3rd-parties, you can use a tool to convert from the OSM API directly, like osmexp. It is a Python command-line tool, that can be installed like any Python package:
$ pip install osmexp
To use it, just give it an element type (notice the rel
, for “relation”) and its id; the GeoJSON will be sent to STDOUT, where it can be piped into a file:
$ osmexp rel 7932512 > st_mark_square.geojson
$ osmexp rel 4817103 > venice.geojson
$ osmexp rel 43648 > veneto.geojson
$ osmexp rel 4056532 > italy.geojson
It also works for the elements of type way
and node
:
$ osmexp way 398987317 > canal_grande.geojson # Just a LineString
$ osmexp node 9589344640 > outdoor_seating.geojson # Just a Point
If you want to research deeper on how osmexp works, the core concepts from the OSM API and how to interpret them from Python are explained in the article Accessing the OpenStreetMap API with Python directly.
GeoJSON editors
Most complete GIS tools like QGIS and ArcGIS have support to many formats including GeoJSON. But, if you don’t want to install a complex application and just want to see a preview and do basic changes, I recommend the online tool geojson.io:
Notice that geojson.io coerces the GeoJSON into a FeatureCollection
.
PostGIS
If you are creating your own GIS solution based on PostGIS, you can handle GeoJSON import/export with the functions ST_GeomFromGeoJSON
and ST_AsGeoJSON
:
-- Creating a table with geometry field:
create table cities (
name text,
geometry geometry(MultiPolygon)
);
-- Inserting a GeoJSON string into a geometry field:
insert into cities (name, geometry)
values ('Venice', ST_GeomFromGeoJSON('{"type":"MultiPolygon", ...'));
-- Returning a GeoJSON as string from a geometry field:
select ST_AsGeoJSON(geometry) from cities where name = 'Venice';