Your first network¶
This builds the road network of Monaco from scratch, then queries it, routes on it and draws it.
It takes a few minutes. You need duckOSM installed with pip install "duckosm[routing,viz]".
1. Choose your area¶
Search for Monaco on openstreetmap.org and click a result whose
border is drawn on the map. The page address ends in relation/<id>: that number is the area's
OSM id. Monaco has two: the country, relation/1124039,
whose border reaches far out to sea (its territorial waters), and its land area,
relation/2220322. For roads we want the land:
2220322.
2. Download the map data¶
OpenStreetMap data comes as .osm.pbf files. Geofabrik offers free
extracts of every continent, country and many regions, updated daily. Monaco has its own:
curl -LO https://download.geofabrik.de/europe/monaco-latest.osm.pbf # 0.7 MB
For your own area, download the smallest region that contains it.
3. Make the boundary file¶
duckosm boundary --osm-id 2220322 --pbf monaco-latest.osm.pbf
wrote monaco.geojson: Monaco (admin level 8, OSM relation 2220322, 2.39 km²), from PBF monaco-latest.osm.pbf
4. Build the network¶
duckosm build --pbf monaco-latest.osm.pbf -b monaco.geojson \
-m driving -m walking -m cycling
About ten seconds later you have monaco.duckdb: one file holding a driving, a walking and a
cycling network, each in its own schema, plus the base-map layers (water,
buildings, POIs…). Roads that cross the border are kept whole, and small pieces that don't connect to
the rest are removed.
5. Query it¶
The database is a normal DuckDB file. Which kinds of road make up Monaco's driving network?
import duckdb
con = duckdb.connect("monaco.duckdb", read_only=True)
con.sql("""SELECT highway, count(*) AS edges, round(sum(length_m) / 1000, 1) AS km
FROM driving.edges GROUP BY highway ORDER BY km DESC LIMIT 5""").show()
| highway | edges | km |
|---|---|---|
| residential | 919 | 31.7 |
| service | 781 | 20.1 |
| secondary | 428 | 14.9 |
| tertiary | 387 | 12.5 |
| primary | 197 | 11.2 |
6. Find a route¶
Routes go from one edge (a directed piece of road) to another, and only take legal turns:
from duckosm import route
q = "SELECT min(edge_id) FROM driving.edges WHERE name = ?"
a = con.execute(q, ["Boulevard du Larvotto"]).fetchone()[0]
b = con.execute(q, ["Avenue Princesse Grace"]).fetchone()[0]
r = route(con, a, b)
r["time_s"], r["length_m"] # (114.1, 1513.0): about 2 minutes, 1.5 km
r["edges"] # the 29 edge_ids along the way
Every edge_id stays the same when you rebuild, cut out a smaller area, or export: see
Stable edge ids.
7. Draw it¶
duckosm viz monaco.duckdb -m driving # -> reports/monaco_driving_network.html (drawn by mapstyle)
Open the file in a browser. This is that file, live: zoom, hover a road, click one to see its
edge_id, toggle road classes in the legend: