Skip to content

Commit 7e7aeeb

Browse files
committed
Add a file explaining how to do basic geospatial analysis with osm2pgsql
Based on an unpublished blog post I never finished off
1 parent 21ab40f commit 7e7aeeb

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

docs/analysis.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Geospatial analysis with osm2pgsql #
2+
3+
An osm2pgsql database and PostGIS is well-suited for geospatial analysis using
4+
OpenStreetMap data where topology is not a consideration.
5+
6+
PostGIS provides an [extensive number of geometry functions](http://postgis.net/docs/manual-2.1/reference.html)
7+
and a full description of how to perform analysis with them is beyond the
8+
scope of a readme, but a simple example of finding the total road lengths by
9+
classification for a municipality should help.
10+
11+
To start with, we'll download the data for the region as an [extract from Geofabrik](http://download.geofabrik.de/) and import it with osm2pgsql.
12+
13+
osm2pgsql --database gis --number-processes 4 --multi-geometry british-columbia-latest.osm.pbf
14+
15+
``--multi-geometry`` (``-G``) is necessary for most analysis as it prevents
16+
MULTIPOLYGONs from being split into multiple POLYGONs, a step that is
17+
normally used to [increase rendering speed](http://paulnorman.ca/blog/2014/03/osm2pgsql-multipolygons)
18+
but increases the complexity of analysis SQL.
19+
20+
Loading should take about 10 minutes, depending on computer speed. Once this
21+
is done we'll open a PostgreSQL terminal with ``psql -d gis``, although a GUI
22+
like pgadmin or any standard tool could be used instead.
23+
24+
To start, we'll create a partial index to speed up highway queries.
25+
26+
```sql
27+
CREATE INDEX planet_osm_line_highways_index ON planet_osm_line USING GiST (way) WHERE (highway IS NOT NULL);
28+
```
29+
30+
We'll first find the ID of the polygon we want
31+
32+
```sql
33+
gis=# SELECT osm_id FROM planet_osm_polygon
34+
WHERE boundary='administrative' AND admin_level='8' AND name='New Westminster';
35+
osm_id
36+
----------
37+
-1377803
38+
```
39+
40+
The negative sign tells us that the geometry is from a relation, and checking
41+
on [the OpenStreetMap site](https://www.openstreetmap.org/relation/1377803)
42+
confirms which it is.
43+
44+
We want to find all the roads in the city and get the length of the portion in
45+
the city, sorted by road classification. Roads are in the ``planet_osm_line``
46+
table, not the ``planet_osm_roads`` table which is only has a subset of data
47+
for low-zoom rendering.
48+
49+
```sql
50+
gis=# SELECT
51+
round(SUM(
52+
ST_Length(ST_Transform(
53+
ST_Intersection(way, (SELECT way FROM planet_osm_polygon WHERE osm_id=-1377803))
54+
,4326)::geography)
55+
)) AS "distance (meters)", highway AS "highway type"
56+
FROM planet_osm_line
57+
WHERE highway IS NOT NULL
58+
AND ST_Intersects(way, (SELECT way FROM planet_osm_polygon WHERE osm_id=-1377803))
59+
GROUP BY highway
60+
ORDER BY "distance (meters)" DESC
61+
LIMIT 10;
62+
distance (meters) | highway type
63+
-------------------+---------------
64+
138122 | residential
65+
79519 | service
66+
51890 | footway
67+
25610 | tertiary
68+
23434 | secondary
69+
14900 | cycleway
70+
6468 | primary
71+
5217 | motorway
72+
4389 | motorway_link
73+
3728 | track
74+
```
75+
76+
The ``ST_Transform(...,4326)::geography`` is necessary because the data was
77+
imported in Mercator. This step could have been avoided by importing in a local
78+
projection like a suitable UTM projection.
79+
80+
More complicated analysises can be completed, but this simple example shows how
81+
to use the tables and put conditions on the columns.

0 commit comments

Comments
 (0)