Cartographic Generalization of OSM Data Jump to heading
Zooming out is not the same as shrinking. A map at zoom 6 that contains everything a zoom 14 map contains, drawn smaller, is illegible long before it is too large — and OSM, which is mapped at maximum detail everywhere, makes this problem unusually acute.
The Problem This Topic Solves Jump to heading
Your tile pipeline produces a legible map at high zoom and an unreadable smear at low zoom: buildings merged into a grey mass, road labels overlapping, every minor stream competing with every major river. The size budget forces features out, but it forces out the wrong ones, and the result is a map that is both too full and missing things.
The failure scenario is a map nobody trusts at continental scale. A reader zooms out to see the shape of a region and gets a uniform texture of detail that conveys nothing. They zoom back in, and the map is fine. The conclusion they draw is that the map “does not work zoomed out”, which is a conclusion about cartography rather than about data volume — and no amount of tuning the size budget fixes it, because the problem is that nobody decided what a zoom-6 map is for.
Prerequisites Jump to heading
Know the tile grid’s precision from The Mapbox Vector Tile Spec & Tile Geometry, since simplification tolerance should be expressed in its units. Understand rank assignment from Tuning Tippecanoe Zoom and Feature Dropping. And be comfortable with geometry operations from Geometry Validation & Repair, because every operator below can produce invalid geometry if applied carelessly.
The Five Operators Jump to heading
Selection removes whole features. It is the cheapest operator, the easiest to review, and the one that should do most of the work. Driven by a rank computed once, it is a lookup rather than a computation, and it is fully reversible in the sense that nothing about the surviving features changes.
Simplification reduces vertex counts while keeping the feature. The Douglas-Peucker family of algorithms is standard, and the important discipline is the tolerance: express it in tile grid units at the target zoom, because geometry is going to be quantised to that grid anyway. Simplifying finer than the grid is wasted work; simplifying much coarser produces visible corner-cutting.
Aggregation merges adjacent features into one. A hundred adjacent residential parcels become one built-up polygon; a cluster of small ponds becomes one water body. This is the operator that most improves low-zoom legibility and the one most pipelines skip, because it creates an object that does not exist in the source and therefore needs a rule somebody agreed to. Merging Adjacent OSM Polygons for Low Zoom works it through.
Displacement moves features apart so they remain distinguishable — a road and a parallel railway that would overlap at zoom 8, drawn slightly separated. It is genuinely changing position, which is acceptable in a map and unacceptable in data, so it belongs at the tile-generation stage and should never flow back into an analytic dataset.
Typification replaces a group with a representative subset that preserves the pattern: a dozen islands in an archipelago become four, arranged so the shape of the group survives. It is the most sophisticated operator and the least often automated, but the principle — preserve the pattern rather than the members — is worth knowing even when applied by hand.
Simplification Tolerance and the Grid Jump to heading
Tolerance should be derived, not guessed. At zoom \(z\) with extent \(E\), one grid unit covers
and geometry will be rounded to that grid during encoding regardless. A tolerance of roughly one grid unit removes vertices the grid cannot represent anyway, at no visible cost. A tolerance of two to four units removes visible detail but keeps recognisable shape, and is a reasonable default for a base map. Beyond about eight units, corner-cutting becomes obvious on curves.
The corollary is that tolerance must vary with zoom. A single tolerance in metres applied at every level either does nothing at low zoom or destroys high-zoom geometry. Simplifying OSM Geometry per Zoom Level implements the per-zoom derivation.
Deciding What a Zoom Level Is For Jump to heading
The operators above are mechanisms; choosing how hard to apply them is a question about purpose, and answering it explicitly is what separates a map that reads well from one that merely fits.
A useful exercise is to write one sentence per zoom band describing what a reader is doing there. At zoom 4 to 6 they are locating a country or a region and want coastlines, major water bodies and a handful of cities. At 7 to 9 they are orienting within a region: primary road network, settlement hierarchy, large land-use masses. At 10 to 12 they are navigating a city: street network down to residential, districts, parks and water. At 13 and above they are looking at a place: individual buildings, addresses, footpaths and points of interest.
Those four sentences determine every threshold in the pipeline. A feature class that appears in none of them should not be in the tile set at all; a class named in a band should be legible throughout it, not thinned out to meet a byte budget. When a reviewer says the map “looks wrong” at some zoom, the productive first question is which of those sentences it is failing, and the answer usually names one operator that was not applied.
The second thing worth writing down is what the map is allowed to lie about. Displacement moves things; aggregation invents things; typification discards most of a group. All three are legitimate and all three produce output that disagrees with the source data. Recording that decision — in the same document as the zoom-band sentences — is what lets somebody later distinguish a deliberate cartographic simplification from a bug in the pipeline, which is otherwise an extremely difficult distinction to make from the tiles alone.
Validation and Error Handling Jump to heading
| Condition | Root cause | Detection | Remediation |
|---|---|---|---|
| Polygons invalid after simplification | Tolerance collapsed a narrow neck | Validity fails on the simplified geometry | Validate after simplifying; fall back to the original |
| Coastline develops gaps | Adjacent features simplified independently | Shared boundaries diverge | Simplify shared edges once, not per feature |
| Aggregated areas leak across classes | Merge grouped on geometry alone | A park merged into an industrial estate | Group by class before merging |
| Map still crowded at low zoom | Only selection and simplification applied | Buildings and land use dominate | Add aggregation for area classes |
| Features jump between zooms | Rank thresholds too coarse | A feature appears and vanishes on adjacent levels | Smooth the rank-to-zoom mapping |
| Displacement moved data | Operator applied before the analytic branch | Positions differ from the source | Displace only in the tile branch |
| Simplification slower than rendering | Tolerance far below the grid | Vertex counts barely change | Derive tolerance from the grid unit |
Performance and Scale Jump to heading
Generalization is where a tile build spends its geometry time, and the costs are very unevenly distributed.
Selection is free. It is a comparison against a precomputed rank, and it should therefore run first, because every feature it removes is a feature the expensive operators never see.
Simplification is linear in vertex count and cheap per vertex. Running it after selection, on a per-zoom basis, keeps it well-behaved.
Aggregation is the expensive one. Merging adjacent polygons requires finding adjacency, which is a spatial join, and then a union, which is geometrically costly. For a country-sized land-use layer this can dominate the whole build, which is why it is usually precomputed per zoom and cached rather than recomputed on every run.
The practical structure is a precomputation pass that produces, for each zoom, a ready-made set of generalized features, and a generation pass that simply selects from them. That separation also makes the generalization reviewable independently of the tiles.
Failure Modes and Gotchas Jump to heading
- Simplification can invalidate. A narrow neck collapsing turns a valid polygon into a self-intersecting one; validate after, not before.
- Shared boundaries diverge. Two adjacent polygons simplified independently no longer share an edge, leaving slivers and gaps. Simplify the shared topology, not each polygon.
- Aggregation must respect class. Merging by adjacency alone produces an area that is part park and part car park, labelled as whichever won.
- Displacement is not data. It belongs only in the rendering branch; letting it reach an analytic output corrupts positions silently.
- Rank thresholds want smoothing. A feature that appears at zoom 9 and vanishes at zoom 10 signals thresholds that disagree between operators.
- Tolerance in metres does not travel. The same metric tolerance is wildly different relative to the grid at different zooms and latitudes.
Integration Points Jump to heading
Generalization sits between normalization and tile encoding. Its input is the normalized feature set from Parsing & Tag Normalization Workflows, with the rank attached; its output is a per-zoom feature set consumed by whichever generator you use. Because aggregation is expensive, that output is worth materialising — a per-zoom table in a warehouse, along the lines of Modelling OSM for Analytics Warehouses, makes the generalization reusable across tile builds and inspectable on its own.
Guides in This Topic Jump to heading
- Simplifying OSM Geometry per Zoom Level — deriving tolerance from the tile grid and keeping shared boundaries together.
- Merging Adjacent OSM Polygons for Low Zoom — class-aware aggregation that produces areas a reader recognises.
Frequently Asked Questions Jump to heading
Why is my low-zoom map crowded even though tiles are within budget?
Because fitting the budget and being legible are different goals. The budget is met by removing features until the bytes fit, which produces a tile full of arbitrary survivors; legibility comes from deciding what a map at that zoom is for and keeping the features that serve it. The usual missing ingredient is aggregation: at low zoom a reader wants to see where the built-up areas are, not a thinned-out sample of individual buildings.
What simplification tolerance should I use?
Derive it from the tile grid rather than picking a distance. Geometry is quantised to the grid during encoding anyway, so a tolerance of about one grid unit removes vertices that could not have been represented, at no visible cost. Two to four units is a reasonable base-map default that keeps recognisable shape while removing real detail. Because the grid unit changes with zoom, the tolerance must change with it too.
Why do gaps appear between adjacent areas after simplification?
Because each polygon was simplified independently, so a boundary the two shared has been reduced differently on each side and they no longer meet. The fix is topological: extract the shared edges once, simplify each edge a single time, and rebuild both polygons from the simplified edges. Any approach that treats each polygon as an isolated geometry will produce slivers and gaps along every shared boundary.
Is it acceptable to move features to make a map readable?
In a map, yes — displacement is a legitimate and long-established cartographic operator, and a map that shows a road and a parallel railway as distinguishable at low zoom is more truthful about the world than one where they overlap into a single line. In data, no. The rule is that displacement happens in the tile-generation branch only, and that no analytic output is ever derived from displaced geometry.
Should generalization run during tile generation or before it?
Before it, and materialised. Aggregation in particular is expensive enough that recomputing it on every tile build is wasteful, and separating it makes the generalized features inspectable in their own right rather than only through the tiles they produce. A per-zoom generalized feature set is also reusable across several tile builds and across other consumers that need a simplified view.
Related Jump to heading
- OSM Vector Tiles & Rendering Pipelines — the parent section and the size budget generalization serves.
- Simplifying OSM Geometry per Zoom Level — the tolerance derivation in code.
- Merging Adjacent OSM Polygons for Low Zoom — class-aware aggregation.
- Geometry Validation & Repair — catching the invalidity these operators can introduce.
- Tuning Tippecanoe Zoom and Feature Dropping — the rank that drives selection.
- Modelling OSM for Analytics Warehouses — where materialised per-zoom features naturally live.
Up one level: OSM Vector Tiles & Rendering Pipelines.