Clipping OSM Extracts to Retail Market Boundaries
This page solves one exact task: producing a smaller OpenStreetMap extract covering only the markets a chain operates in, without cutting the road network in a way that breaks routing at the market edge.
Clipping is worth doing — a graph a fifth the size imports in a fifth the time and serves from a fifth the memory — and it is the stage where an entire market’s edge quietly becomes unroutable. The failure is silent by construction: a severed road still produces contours, they are simply smaller than they should be, and only at the boundary where nobody is looking.
Prerequisites
- Command-line tools:
osmium-toolfor the extract operations, which handles complete ways and referenced nodes correctly. Install through your package manager or a container image. - Python packages:
geopandasandshapelyfor building the clip geometry,pyprojfor buffering in metres. Install withpip install geopandas shapely pyproj. - A market boundary layer — the administrative or trade geography the business plans on, as polygons with a declared CRS.
- The parent context. Preparing OSM network extracts for routing covers where clipping sits and what the build version records.
Configuration and execution parameters
| Parameter | Value for this task | Notes |
|---|---|---|
buffer_km |
30 | Larger than the longest contour you will compute |
buffer_crs |
EPSG:5070 | Buffering in degrees produces a distorted shape |
strategy |
complete ways | Keeps ways whole rather than cutting at the boundary |
simplify_tolerance_m |
500 | The clip polygon, not the roads |
union_markets |
true | One clip geometry, not one extract per market |
output_format |
pbf | Compact and what every importer expects |
keep_metadata |
false | Version and timestamp attributes are not needed for routing |
The strategy row is the one that decides whether this works. Cutting geometry at the boundary produces ways that end in mid-air; keeping complete ways means any way that touches the region is included in full, along with the nodes it references, which is what preserves connectivity. Every serious extract tool offers this, and it is not always the default.
Annotated implementation
The clip geometry is built in Python — buffered in a projected CRS, unioned across markets, simplified enough to keep the extract tool fast — and applied with an extract tool that understands ways and their referenced nodes.
from __future__ import annotations
import subprocess
from pathlib import Path
import geopandas as gpd
from pyproj import CRS
METRIC_CRS = CRS.from_epsg(5070)
BUFFER_M = 30_000
SIMPLIFY_M = 500
def build_clip_polygon(markets: gpd.GeoDataFrame, out_path: Path) -> Path:
"""Union the operating markets, buffer in metres, and write GeoJSON in WGS84."""
assert markets.crs is not None, "market layer has no CRS"
metric = markets.to_crs(METRIC_CRS)
# Buffer BEFORE union so narrow gaps between adjacent markets close, then
# simplify: the clip shape only needs to be roughly right, and a polygon
# with 200,000 vertices makes the extract tool far slower than the buffer.
buffered = metric.geometry.buffer(BUFFER_M)
merged = buffered.union_all().simplify(SIMPLIFY_M, preserve_topology=True)
out = gpd.GeoSeries([merged], crs=METRIC_CRS).to_crs("EPSG:4326")
out.to_file(out_path, driver="GeoJSON")
return out_path
def clip_extract(source_pbf: Path, clip_geojson: Path, out_pbf: Path) -> Path:
"""Complete ways keeps every way that touches the region intact, plus the
nodes it references — which is what preserves routability at the edge."""
cmd = [
"osmium", "extract",
"--polygon", str(clip_geojson),
"--strategy", "complete_ways",
"--overwrite",
"-o", str(out_pbf),
str(source_pbf),
]
subprocess.run(cmd, check=True)
assert out_pbf.stat().st_size > 0, "empty extract — check the clip geometry"
return out_pbf
Buffering before the union rather than after it is a small ordering detail with a real consequence: two adjacent markets separated by a few hundred metres of unincorporated land produce a clip polygon with a gap through the middle if unioned first, and the roads in that gap are exactly the ones connecting them.
Failure modes and debugging
A clip polygon with holes. Markets defined as separate polygons that share boundaries can, after a union of unbuffered geometry, leave slivers and holes where the boundaries did not quite coincide — the same sliver problem that afflicts spatial joins. Buffering first hides it; checking the polygon’s interior-ring count before use catches it.
Buffering in degrees. A buffer of 0.3 degrees is roughly thirty kilometres at the equator and twenty at fifty degrees north, so a degree-buffered clip is systematically tighter in the north of a country than the south. The symptom is edge truncation that correlates with latitude, which is a memorable afternoon of debugging if the buffer units are not checked first.
An over-detailed clip polygon. Passing a market boundary at full resolution to an extract tool can make the clip take longer than the import. Simplifying to a few hundred metres has no effect on which roads are included — the buffer is thirty kilometres wide — and it makes the operation fast.
Silently empty output. A clip polygon in the wrong CRS, or one that does not intersect the source extract at all, produces a valid, tiny output file rather than an error. Asserting on the output size and on the node count is the cheap guard, and it belongs in the pipeline rather than in a person’s memory.
Verification
- Count nodes and ways in the output and compare against the previous clip. A large unexplained drop is a clip geometry problem, not a map change.
- Snap every store to the clipped graph and confirm all of them land in the largest connected component. A store in a small component means its neighbourhood was severed.
- Compare edge-market contour areas against the unclipped extract for a sample of stores near the boundary. They should match; any that shrink identify exactly where the buffer is too tight.
- Confirm the clip polygon covers every store with room to spare — a store within the buffer distance of the clip edge will produce a truncated contour even when the clip itself was correct.
Frequently Asked Questions
Should the buffer scale with the longest contour computed?
Yes, and with a comfortable multiple. A thirty-minute drive-time contour can reach fifty kilometres on open highway, so a buffer smaller than that guarantees truncation for any store near the edge. The working rule is a buffer at least as large as the furthest distance the longest contour could plausibly reach, plus enough margin that the network beyond it is complete rather than fraying — which is where thirty kilometres comes from for fifteen-minute urban work and considerably more for regional analysis.
Can several markets share one extract?
They should, wherever their buffers overlap. Separate extracts per market duplicate the shared boundary region, multiply the import cost and — worse — produce two different graphs covering the same roads, so a store on the boundary gets different contours depending on which extract answered. One unioned clip covering all markets in a region avoids the whole class of problem.
How does clipping interact with the build version?
The clip geometry is part of the build configuration, so a change to markets or buffer produces a new build version exactly as a profile change would. That matters because a widened clip changes contours at the edge, and those changes need to be attributable. Hashing the clip polygon into the version identifier makes the connection automatic rather than remembered.
Is it worth clipping at all with cheap storage?
The storage was never the point — import time and serving memory are. A clipped extract turns a rebuild into something that can run monthly without negotiation and lets the engine run on modest instances, which in turn makes it affordable to keep several builds available for comparison. Where an organisation genuinely operates nationally, a national graph is simpler; for anyone else, clipping buys agility rather than disk.
What happens when a new market is opened?
The clip geometry changes, which means a new build version, a new graph and — importantly — a full re-score of anything that compared sites across the affected region. The mistake is treating a market addition as a configuration tweak: the roads that were previously outside the extract are now inside it, so catchments near the old boundary genuinely change. Handling it as a deliberate rebuild with a comparison against the previous build makes those changes visible instead of surprising.
Does the clip need to follow administrative boundaries at all?
No, and there is often a better shape. The clip only needs to cover every store plus the furthest reach of the longest contour, so a buffered convex hull around the estate can be simpler, smaller and less prone to the sliver problems that unioned administrative polygons produce. Administrative boundaries earn their place when the business plans in them and wants the extract to align with reporting geography, which is a legitimate reason — just not a routing one.
Related
- Preparing OSM Network Extracts for Routing — the surrounding build, publish and pin sequence.
- Validating Routable Network Topology Before Isochrone Runs — the connectivity gate that catches a bad clip.
- Troubleshooting Disconnected Road Networks in Rural Areas — what a severed network looks like downstream.