Plotline overview
Plotline is a compact store for EUDR forest-loss screening. It keeps only the facts the decision reads and gives the same answers as the original map layers.
- The problem: EUDR screening intersects farm plots with years of forest maps, and repeats the check whenever a map updates. The challenge brief asks for compact storage, fast queries and the same plot-level answer as the original layers.
- The result: a 6.1 KB decision layer replaces 623 KB of original layers, with identical answers for all 744,732 map cells.
- The speed: registered plots re-check 44× faster and new boundaries about 5× faster. Every answer carries a receipt.
EUDR plot-level screening
Companies that sell rubber, palm oil, cocoa or coffee into the EU must show that every supplying farm plot is deforestation-free under the EU Deforestation Regulation, EUDR.
A plot's boundary is checked against satellite maps for two things: whether the land was forest on 31 December 2020, the rule's cut-off date, and whether tree cover has been lost since. The maps come from different sources at different sharpness and update every year. The check is therefore re-run for millions of plots whenever a layer updates, and the data accumulates.
The brief's slide title frames the task: "Keep the decision, not the data." The layers are to be stored compactly and queried fast while reproducing exactly the same plot-level decisions as the original layers.
Cut-offHansen records one loss year per map cell, 2001 to 2025.
A schematic of years, not data: no heights are measured values.
17 supplier plots and two public maps
A raster is a map stored as a grid of squares, one number per square, like graph paper. Satellite forest maps are rasters. A farm plot is a vector: an outline traced with coordinates. The task is laying outlines over grids.
17 supplier plots
One shipment lot, one supplier. A CSV of 17 declarations (35 columns) and a GeoJSON of 17 matching outlines, in Chai Buri, Surat Thani, Thailand. Smallholdings of 0.53 to 20.07 ha. The two files join one to one.
Tree-cover loss
Three bands at about 28 m: canopy in 2000, the year of loss (2001 to 2025), and a land/water mask. The chip is 1,233 × 604 = 744,732 cells.
Forest in 2020
Forest or not, at the cut-off year, at about 9 m on a different grid (3,695 × 1,809). Each Hansen cell holds an exact 3 × 3 block of JRC cells.
Select a pattern for the nine small (JRC) cells to show what the written rule reads.
The rule reads
Plotline design: three questions, one decision layer
Plotline starts from the three questions an EUDR-style screen asks of a plot, and what each needs from the maps.
Was it forest on 31 Dec 2020?
Needs JRC's 2020 forest class, and land / water / unknown.
Has that forest been lost since?
Needs Q1 plus the Hansen loss year, 2021 to 2025.
What did the supplier's own check say?
The supplier named "Hansen Tree Cover Loss 2021-2023": any Hansen loss in 2021 to 2023, on any land.
No question reads the canopy percentages, which are 72% of Hansen's bytes, or loss years before 2021. Both are dropped. Each map cell is reduced to one of 20 codes.
SizeFour original files, 623,237 bytes.
Bars are to true scale on one sample region (34 × 17 km): bytes, not hectares or plots.
The screening layer answers all three questions. The decision layer answers Q1 and Q2 only, so it also forgets the loss year on land that was not forest in 2020: loss on land the EU's 2020 forest map does not class as forest, which a Hansen-only check counts as loss. The 20 codes are below.
| On land that was… | no loss since | lost 2021 | lost 2022 | lost 2023 | lost 2024 | lost 2025 |
|---|---|---|---|---|---|---|
| forest in 2020 | F | F·21 | F·22 | F·23 | F·24 | F·25 |
| not forest in 2020 | N | N·21 | N·22 | N·23 | N·24 | N·25 |
| forest state unknown | ? | ?·21 | ?·22 | ?·23 | ?·24 | ?·25 |
3 forest states × 6 loss states + water + unknown = 20 codes. The decision layer merges every N·year into plain N. Orange outline = loss after the cut-off. Unknown is its own value: a missing observation is never recorded as "no loss".
Where the last bytes come from technical
A plain GeoTIFF of the decision codes is already 8,532 B, 98.6% smaller than the originals, so most of the saving comes from deciding what to keep rather than from a codec. Plotline's encoding (separate bit-planes for land, water and forest, plus a sparse list of the few loss events) removes a further 28%, down to 6,146 B. The lossless "v1" store is retained as the audit tier in case the rule changes.
A learned codec selector lost to a fixed setting on a sealed holdout region and was rejected.
From outline to answer
A cell belongs to a plot if the cell's centre falls inside the outline. This written rule is part of the decision: changing it changes answers.
Synthetic illustration; no real plot, cell or count.
Identical answers, checked for every cell
Dropping data is acceptable only if nothing the decision reads is lost. An independent path rebuilds the code for every map cell straight from the original GeoTIFFs and compares it with the decision layer. The comparison covers all 744,732 cells, not a sample.
This covers every plot, not only the 17 supplied: each answer depends only on the codes of the selected cells, so if every cell's code matches, any boundary drawn in the region gets identical outputs under the same centre rule.
CheckEvery cell is rebuilt from the originals and compared.
The grid has the real chip's dimensions but not its data; colours are decorative. The 9,829 fuzzed polygons (holes, multipolygons, edges through cell centres, chip edges, water) exclude 171 invalid shapes that both paths rejected identically. "Break one cell" illustrates the negative controls, which all detected the change.
The Plotline app: five views
The Plotline app presents the evidence to a reviewer. It is map-first and draws the real Hansen and JRC grids in the browser.
A year scrubber for 2001 to 2025, Hansen stacked with the JRC 2020 forest, and a plot view showing its cells and centres.
All 17 plots by 25 years as a loss "barcode", with supplier declarations beside what the maps show.
The fidelity, storage and timing numbers, and the ladder of what was dropped and why.
A newly drawn boundary is answered by both the original and compact paths.
Every answer carries layer versions, grid, rule and hashes so anyone can re-check it.
Results: identical answers, smaller storage, faster queries
Three claims are measured separately, each with its conditions stated beside the number.
Sample-region and whole-tile bars are linear; speed bars are log.
Design limits
- Edge cells are all-or-nothing. Under the centre rule a cell counts for a plot when its centre lies inside the boundary; cells are about 0.076 ha. Partial edge coverage and the 0.5 ha minimum area are not modelled.
- JRC is sampled once per Hansen cell, at the centre of its 3 × 3 block. The alternatives (majority, any forest) give the same decision for all 17 plots, but only one plot has mapped forest.
- The layer is rule-specific. A changed rule or an added layer means re-deriving from the lossless audit tier: seconds per region, about 7 CPU-minutes per tile (estimated).
- The largest speed-ups need registered plots. The 44× to 410× figures apply to plots registered in advance; a new boundary gets 5.2×.
- Storage was measured on a whole tile and query timing on one region.
Speed phases: 24× to 44× history
The decision layers were benchmarked first: registered plots 24×, new boundaries 2.2×. Four phases followed with no change to any output, store byte or file format. Phase 1 sped up decoding, histogram reduction and polygon selection (31× and 3.0×). Phase 2 added a scalar scan, a batch evaluator and the numpy-free re-check (33× and 5.0×). Phase 3 sped up the shared reducer (44×). Phase 4 trimmed it again (numpy-free 65× to 83×; new boundaries read 5.2×) and ended with a research pass that found nothing that beats this approach for small exact plots on a CPU.
Findings on the 17 supplied plots
With Hansen alone, 7 of the 17 plots show tree-cover loss after 2020. Hansen records any tree-cover loss on any land, and the region is rubber and oil-palm country. With the JRC 2020 forest map added, only P-0001 has mapped loss on mapped 2020 forest: 2 cells, in 2022, out of its 38 Hansen loss cells that year.
Filter
One dot per plot; positions are decorative. The six other plots with Hansen loss after 2020 (P-0005, P-0006, P-0013, P-0014, P-0016, P-0018) had that loss only on land JRC did not map as forest in 2020. Counts are cells, not hectares.
Declared indication, no mapped loss
All 17 declare "Deforestation-free", checked against "Hansen Tree Cover Loss 2021-2023". Five (P-0003, P-0005, P-0008, P-0010, P-0013) record an "indication of deforestation", resolved by on-site verification. On that layer and the project's rule, none of those five shows loss in 2021 to 2023.
Declared none, map shows some
Three plots declared no indication but show 2021 to 2023 loss on the layer they cite: P-0001 (38 cells in 2022), P-0016 (1 in 2023), P-0018 (1 in 2021). Neither the older Hansen release nor a different boundary rule explains the gap.
Other pages
How Plotline works
The 20 codes, the proof and the app.
Performance
The baseline and conditions behind each speed multiple.
What the plots show
The declaration gap and what the results do not claim.
Results are encoding and query evidence on a sample region, not legal compliance findings. Supplier plot boundaries and declaration rows are not shown; every plot drawn here is synthetic.