Landcover absorption drifts every class into the dominant one #41

Closed
opened 2026-08-03 06:48:00 +00:00 by art-bot · 2 comments
Collaborator

Noticed while measuring #36. Pre-existing, not caused by that work, and not fixed by it.

What

Polygon absorption reclassifies a sub-threshold polygon to its dominant neighbour, the
largest thing beside it. Repeated once per zoom, that is a ratchet toward whatever the
country's dominant class is, and it has no notion of preserving the class proportions.
Sweden's cover, area per class per zoom, on the code as it stood before #36:

z9 z8 z7 z6 z5
nature 1 902 064 1 962 959 2 002 061 2 030 983 2 045 529
water 563 752 545 615 532 511 522 813 521 598
agricultural 86 313 47 273 23 565 7 571 2 868
artificial 10 083 3 892 920 502 268

km². Sweden loses 97% of its agricultural area and 97% of its built-up area between z9
and z5
, both into nature. #36 makes absorption actually merge, which takes those to 105
and 2 km² — the direction was already set, the change just finishes the job.

The visible consequence: at z5 Sweden is uniformly forest-green. Skåne is not farmland and
Stockholm is not a city, on a map where both are several pixels across and a reader would
expect to see them.

Poland drifts the other way (agricultural is its dominant class) and less far: nature
−33%, agricultural +18%, artificial +44% from z9 to z5.

Why it happens

"Dominant neighbour" is the right de-speckling rule for a speck and the wrong one for a
region made of specks. Sweden's farmland at z5 is thousands of individual fields, none of
them a pixel; each absorbs into the forest beside it, and the region they collectively form
— which is the thing a reader can see — is never considered.

Shapes a fix could take, none of them investigated

  • Cluster before absorbing. Merge adjacent same-class polygons first and test the
    cluster against the threshold, so a thousand touching fields count as one region. This
    is the cartographically standard answer and probably the right one.
  • A per-class floor. Never let a class fall below some fraction of its z-above area;
    crude, but it would preserve proportions by construction.
  • Rank the neighbour by something other than area. Aggregate class share, say, so a
    speck of the locally-dominant class wins over a single large polygon of another.

The absorb_boundary mechanism (conf/common.yaml) is a precedent for the shape of a fix:
a preference ordering ahead of n._a DESC, never a filter, so the coverage stays
hole-free.

Not urgent

The map is not wrong, it is over-generalized, and it has been like this since absorption
landed. Filed so it is written down somewhere other than a docs paragraph.

Noticed while measuring #36. Pre-existing, not caused by that work, and not fixed by it. ## What Polygon absorption reclassifies a sub-threshold polygon to its **dominant neighbour**, the largest thing beside it. Repeated once per zoom, that is a ratchet toward whatever the country's dominant class is, and it has no notion of preserving the class *proportions*. Sweden's `cover`, area per class per zoom, on the code as it stood before #36: | | z9 | z8 | z7 | z6 | z5 | |---|---:|---:|---:|---:|---:| | nature | 1 902 064 | 1 962 959 | 2 002 061 | 2 030 983 | 2 045 529 | | water | 563 752 | 545 615 | 532 511 | 522 813 | 521 598 | | agricultural | 86 313 | 47 273 | 23 565 | 7 571 | **2 868** | | artificial | 10 083 | 3 892 | 920 | 502 | **268** | km². **Sweden loses 97% of its agricultural area and 97% of its built-up area between z9 and z5**, both into `nature`. #36 makes absorption actually merge, which takes those to 105 and 2 km² — the direction was already set, the change just finishes the job. The visible consequence: at z5 Sweden is uniformly forest-green. Skåne is not farmland and Stockholm is not a city, on a map where both are several pixels across and a reader would expect to see them. Poland drifts the other way (agricultural is its dominant class) and less far: nature −33%, agricultural +18%, artificial +44% from z9 to z5. ## Why it happens "Dominant neighbour" is the right de-speckling rule for a *speck* and the wrong one for a *region made of specks*. Sweden's farmland at z5 is thousands of individual fields, none of them a pixel; each absorbs into the forest beside it, and the region they collectively form — which is the thing a reader can see — is never considered. ## Shapes a fix could take, none of them investigated - **Cluster before absorbing.** Merge adjacent same-class polygons first and test the *cluster* against the threshold, so a thousand touching fields count as one region. This is the cartographically standard answer and probably the right one. - **A per-class floor.** Never let a class fall below some fraction of its z-above area; crude, but it would preserve proportions by construction. - **Rank the neighbour by something other than area.** Aggregate class share, say, so a speck of the locally-dominant *class* wins over a single large polygon of another. The `absorb_boundary` mechanism (`conf/common.yaml`) is a precedent for the shape of a fix: a preference ordering ahead of `n._a DESC`, never a filter, so the coverage stays hole-free. ## Not urgent The map is not wrong, it is over-generalized, and it has been like this since absorption landed. Filed so it is written down somewhere other than a docs paragraph.
Owner

Greenlit by maintainer 2026-08-04. Cross-ref: #47 (water eats coastlines) may be the water-specific face of the same absorption ratchet — the #47 worker investigates that first; if the fixes are shared, this closes as fixed-by, otherwise it gets its own pass with the cluster-before-absorbing direction from the body.

Greenlit by maintainer 2026-08-04. Cross-ref: #47 (water eats coastlines) may be the water-specific face of the same absorption ratchet — the #47 worker investigates that first; if the fixes are shared, this closes as fixed-by, otherwise it gets its own pass with the cluster-before-absorbing direction from the body.
Owner

PR #56#56

PR #56 — https://git.blahonga.org/art/ismap/pulls/56
art closed this issue 2026-08-05 07:20:28 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
art/ismap#41
No description provided.