Land Cover With Ambiguous Zero¶
A categorical land-cover raster that declares NoData = 0 while 0 is also a real class ("unclassified / bare"). Masking on data == nodata silently deletes a legitimate class; ignoring NoData treats sentinel pixels as data. Nothing in the file tells the two apart.
| Property | Value |
|---|---|
| Case ID | landcover_ambiguous_zero_small |
| Category | raster |
| Format | GeoTIFF |
| CRS | EPSG:32633 |
| Location | Southern Italy / Sicily (synthetic, UTM 33N) — 15.00°E, 40.65°N → 15.00°E, 40.65°N |
| Test tier | integration |
| Size class | tiny |
| Storage class | bundled |
| Redistributable | yes |
| Loader | rasterio |
| Status | validated |
Use this case¶
import pytest
@pytest.mark.geocase_case("landcover_ambiguous_zero_small")
def test_landcover_ambiguous_zero_small(geocase_case) -> None:
data = geocase_case.load()
assert data is not None
Use GeoCase in your tests¶
Install the complete set of vector, raster, and NetCDF dependencies:
What this case checks¶
Surface the sentinel/class collision at 0. The sibling case landcover_small is the same scene with the ambiguity removed — every pixel classified and no NoData declared — so the pair isolates the collision itself: any difference in how your code treats the two files is the ambiguity acting on it (Plan 32).
Risk types covered¶
failure_mode/consumernodata/ambiguous_zeronodata/ignoredscaling/category_misread
Expected behavior¶
| Assertion | Expected |
|---|---|
expect_loadable |
yes |
expect_crs |
yes |
expected_epsg |
32633 |
expect_nodata |
yes |
expected_band_count |
1 |
expected_dtype |
uint8 |
expected_shape |
[16, 16] |
expected_nodata_value |
0 |
expected_compression |
deflate |
expected_band_names |
landcover |
expected_colormap_present |
yes |
Known answer¶
Computed from the actual bytes and gated against them. Grade your own output against these.
| Quantity | Value |
|---|---|
| Mean over valid pixels | 2.0 |
| Mean including NoData | 1.5 |
| NoData pixels | 64 |
| Bounds (case CRS) | [500000.0, 4499840.0, 500160.0, 4500000.0] |
Notes¶
A 16×16 single-band uint8 categorical land-cover raster in EPSG:32633, with a
colormap, declaring nodata = 0.
The ambiguity¶
The class scheme is:
| Value | Meaning |
|---|---|
| 0 | unclassified / bare — and the declared NoData sentinel |
| 1 | water |
| 2 | vegetation |
| 3 | urban |
An 8×8 block of genuine 0 pixels sits in the middle of the scene, surrounded by classes 1, 2 and 3. Those zeros are real, meaningful data. They are also, by the file's own declaration, NoData.
There is no way to tell the two apart from the file alone. That indistinguishability is the case — not a defect in the fixture to be cleaned up. Two reasonable consumers disagree about the same pixels:
- one masking
data == nodatasilently deletes an entire legitimate class, and reports 25% of the scene as missing; - one ignoring NoData treats sentinel pixels as classified data.
Neither can be shown wrong from the file. Real land-cover products ship this way, which is why "just read the nodata tag" is not a sufficient answer.
The sibling¶
landcover_small is the same scene with the ambiguity
removed: every pixel is classified, and the raster deliberately declares no
NoData at all. The pair is the useful artifact. Run the same code over both and
any difference in behaviour is the ambiguity acting on it, isolated from every
other property (CRS, dtype, shape, compression and colormap are identical).
Regeneration¶
Emitted by scripts/generate_raster_fixtures.py from the same array that
produces landcover_small, with the 0 block written in and nodata=0
declared. There is no hand-committed payload here — see
docs/plans/32-footprint-truth-and-ambiguous-zero.md Phase 2, and Plan 28 for
why every fixture must sit inside the regeneration gate.
Required capabilities¶
loadnodata-checkcolormap-check
Files¶
- Primary:
landcover_ambiguous_zero_small.tif - Notes:
notes.md
Source and license¶
- Source: geocase-synthetic
- License: MIT
Tags¶
categorical delivery:single-file geography:utm geotiff landcover nodata product:landcover raster
Related cases¶
- Land Cover Small --
landcover_small - DEM NaN NoData Small --
dem_nan_nodata_small - Water Mask Small --
water_mask_small - Bottom-Up DEM (Positive Y Resolution) --
bottom_up_dem_small - DEM Small --
dem_small