Skip to content

Latest commit

 

History

History
81 lines (66 loc) · 3.16 KB

analysis.md

File metadata and controls

81 lines (66 loc) · 3.16 KB

Geospatial analysis with osm2pgsql

An osm2pgsql database and PostGIS is well-suited for geospatial analysis using OpenStreetMap data where topology is not a consideration.

PostGIS provides an extensive number of geometry functions and a full description of how to perform analysis with them is beyond the scope of a readme, but a simple example of finding the total road lengths by classification for a municipality should help.

To start with, we'll download the data for the region as an extract from Geofabrik and import it with osm2pgsql.

osm2pgsql --database gis --number-processes 4 --multi-geometry british-columbia-latest.osm.pbf

--multi-geometry (-G) is necessary for most analysis as it prevents MULTIPOLYGONs from being split into multiple POLYGONs, a step that is normally used to increase rendering speed but increases the complexity of analysis SQL.

Loading should take about 10 minutes, depending on computer speed. Once this is done we'll open a PostgreSQL terminal with psql -d gis, although a GUI like pgadmin or any standard tool could be used instead.

To start, we'll create a partial index to speed up highway queries.

CREATE INDEX planet_osm_line_highways_index ON planet_osm_line USING GiST (way) WHERE (highway IS NOT NULL);

We'll first find the ID of the polygon we want

gis=# SELECT osm_id FROM planet_osm_polygon
WHERE boundary='administrative' AND admin_level='8' AND name='New Westminster';
  osm_id
----------
 -1377803

The negative sign tells us that the geometry is from a relation, and checking on the OpenStreetMap site confirms which it is.

We want to find all the roads in the city and get the length of the portion in the city, sorted by road classification. Roads are in the planet_osm_line table, not the planet_osm_roads table which is only has a subset of data for low-zoom rendering.

gis=# SELECT
    round(SUM(
      ST_Length(ST_Transform(
        ST_Intersection(way, (SELECT way FROM planet_osm_polygon WHERE osm_id=-1377803))
        ,4326)::geography)
    )) AS "distance (meters)", highway AS "highway type"
  FROM planet_osm_line
  WHERE highway IS NOT NULL
  AND ST_Intersects(way, (SELECT way FROM planet_osm_polygon WHERE osm_id=-1377803))
  GROUP BY highway
  ORDER BY "distance (meters)" DESC
  LIMIT 10;
 distance (meters) | highway type
-------------------+---------------
            138122 | residential
             79519 | service
             51890 | footway
             25610 | tertiary
             23434 | secondary
             14900 | cycleway
              6468 | primary
              5217 | motorway
              4389 | motorway_link
              3728 | track

The ST_Transform(...,4326)::geography is necessary because the data was imported in Mercator. This step could have been avoided by importing in a local projection like a suitable UTM projection.

More complicated analysises can be completed, but this simple example shows how to use the tables and put conditions on the columns.