The limit of a single pixel
The starting point
Every summer, Spain burns. Some of it is unavoidable — heat, drought, terrain.
But not all fire risk is equal across a landscape. Some patches of forest are far more likely to carry a fire once it starts than others.
If you could see which ones, from space, before it happens, that's not just an academic exercise — it's exactly the kind of data that shapes where resources get positioned before they're needed.
Satellites already collect the raw material for this every 5 days, for free, over the entire planet.
The question I wanted to answer wasn't "can I make a nice-looking map?" — plenty of tools already do that. It was narrower, and harder:
Can a simple, explainable formula, computed from free satellite data, actually predict where a fire is more likely to spread — and can I prove it against what really burned?
That last part, proving it, is the part almost nobody does. It's easy to make a map that looks like it's showing risk. It's much harder to check whether that map beats simply assuming "the whole forest is equally dangerous."1
What the satellite measures
Satellites like Sentinel-2 don't take normal photos — they measure how much light bounces back at different wavelengths, some of them invisible to the human eye.
Certain combinations of those wavelengths correlate with real physical properties of the land. Three matter here:
- NDVI — how much live vegetation is present. High = dense, leafy: a lot of potential fuel.
- NDWI — how much water is in the surface. Low = dry ground.
- NBR — the "Normalized Burn Ratio," the standard index in wildfire science. It reacts to a mix of moisture and biomass, and drops sharply after a fire — which is why it's normally used to map burn scars after the fact. My question was whether it could say something useful before.
Sentinel-2 revisits the same spot roughly every 5 days. This is what a real forest looked like, 5 days before it burned — the closest cloud-free pass available before ignition:
Green on the NBR map means "lots of biomass, moist" — the kind of forest you'd intuitively expect to be lower risk. Red means dry and sparse.
So the first, most obvious hypothesis practically writes itself:
Hypothesis 1 — low NBR before a fire should predict where it spreads.
The formula
This is the actual formula, sent directly to Sentinel Hub as a request:
Each pixel of the resulting image ends up with three numbers between −1 and 1.
(The code for this project — the Sentinel Hub evalscript and the Python validation functions — was built through vibe coding with Cursor, Codex and Claude, iterating on the logic to fit each hypothesis.)
The method
It would be easy to draw a map, glance at it, and say "yep, the dry areas match the burned ones, looks about right." That's not proof, that's confirmation bias with extra steps.
Instead, I used something official: the Copernicus Emergency Management Service publishes a Delineation Map for major disasters — a shapefile tracing the real perimeter of what burned, surveyed after the fact. That's ground truth, not an estimate.
The check is simple to describe: take the pixels my index flags as "high risk," take the pixels that actually burned, and see how much they overlap — compared to what you'd get by pure chance.
If a model's precision doesn't clear the base rate, it isn't predicting anything — it's just describing how much of the map burned overall, dressed up as a formula.
(Copernicus EMS Delineation Maps are about as close to "ground truth" as you can get without walking the perimeter yourself — free, official, and shapefile-precise.)
First attempt
I tested this on two real, well-documented fires with very different landscapes:
- Sierra de la Culebra (Zamora, June 2022) — ~30,000 hectares, dry oak and scrubland plateau.
- Sierra Bermeja (Málaga, September 2021) — ~9,700 hectares, pine forest on a coastal mountain range.
First pass, one threshold picked by eye (NBR < 0.3):
Culebra looked genuinely promising. Bermeja didn't.
Same formula, same threshold, opposite outcome — which already says something: the threshold, picked by eye, was probably not the right way to test this.
Sweeping the threshold
So I went back to Culebra and swept across five thresholds instead of guessing one:
Read this carefully and the earlier "71.1%" mostly evaporates.
At no threshold does the index clear the base rate by a meaningful margin — the closest attempt (+0.5 pts) comes with 100% coverage, meaning the "model" was flagging the entire map as high risk.
Marking everything as dangerous isn't a prediction — it's the mathematical equivalent of a shrug.
Conclusion: NBR alone doesn't reliably predict where a Mediterranean forest fire will spread.2
Second hypothesis
This is where the project stopped being a coding exercise and became a real investigation.
NBR blends two different things: how much vegetation there is, and how dry it is.
A healthy, dense forest can have a high NBR — plenty of live, moist biomass — and still be extremely dangerous, because once it does ignite, there's far more material to burn than in sparse, already-dry scrubland.
In other words: NBR alone can't tell "safe because it's not flammable" apart from "dangerous because there's a lot of fuel, even if it's currently green."
If that reasoning is right, the fix isn't tuning the NBR threshold further — I'd already shown that doesn't work. The fix is separating the two things NBR was blending: fuel load (how much vegetation, from NDVI) and dryness (from NBR) — and only flagging high risk where both are true at once.
The nice part: this needed no new satellite imagery. NDVI, NDWI and NBR were already computed for both fires — this was pure local computation, a few minutes of NumPy, zero extra cost.
The expensive part of a real proof-of-concept is rarely the equation: it's sitting with a negative result long enough to figure out whether it's honest or simply wrong.
Does the composite work?
Same test, same two fires, same threshold sweep:
At the lower thresholds, the pattern repeats: no real improvement over the base rate, and very high coverage — the same problem as with NBR alone.
Looking closer
Look at the one number that seems to break the pattern — Bermeja at threshold 0.3, +5.9 points.
That result comes with only 17% coverage: the model is only making a call on a very small slice of the map.
With that few pixels involved, a couple of lucky hits move the percentage quite a bit without meaning anything structural. If this were a genuine signal, you'd expect precision to climb steadily as the threshold tightens, not spike once, right at the edge, on the smallest sample. It doesn't clear that bar.
Conclusion: the composite index doesn't discriminate spread risk either — and it fails the same way, in two forests that share nothing except that they both burned.
(Precision figures between the two fires aren't directly comparable on their own — the base rates differ too, 33.7% in Culebra vs. 15.5% in Bermeja, because each fire burned a different proportion of its surrounding landscape. What is fair to compare is each fire against its own base rate, which is exactly what we did.)
What this actually proves
A negative result can look like a worse story than a positive one. It's the opposite, if you can explain why.
Two different hypotheses, tested with the same rigor, in two forests with different vegetation and geography — and both rejected, the same way both times. That consistency is the finding.
It points strongly to the ceiling here not being "which formula I picked" — it's that a single pixel, viewed in isolation, doesn't carry enough information to predict spread.
Real fire spread depends on things a satellite pixel can't see on its own: slope, wind direction and speed, whether the vegetation forms a continuous path for fire to travel along or is broken up by roads, rivers, clearings.
What did work, independent of the result: a real, reproducible, end-to-end pipeline, built entirely on free official data — Copernicus for imagery, EMS for ground truth — that can be pointed at any fire, anywhere, and validated the same rigorous way.
That infrastructure being solid isn't a small thing; it's usually the hardest part of any proof-of-concept, and unlike the hypotheses, it held up both times.3
What's next
The next real step isn't tuning this formula a third time — it's a different kind of question, and deserves its own phase rather than a rushed extension of this one: combining NDVI, NDWI and NBR through an actual model instead of a fixed formula, and testing other pre-fire time windows (5, 10, 30 days) to see if timing matters more than the index itself.
Neither NBR alone nor the composite beat chance, on two different fires. Sometimes the real result of a project isn't the answer you were hoping for — it's finding out, with evidence, exactly which question you were asking wrong.
Footnotes
- "Beating chance" sounds like a low bar, but it's the correct one — a model that can't clear it isn't a model, it's decoration on top of a map.↩
- A model flagging 100% of the map as "high risk" isn't being cautious — mathematically, its precision always converges to the base rate at 100% coverage, by definition, whether the index means anything or not.↩
- If you're wondering why I didn't just throw all three indices into one model right away — that's the honest next question, and it's more work than a footnote can hold.↩
- The evalscript runs inside Sentinel Hub and turns four spectral bands into NDVI, NDWI and NBR for every returned pixel.↩
- The validation function rasterises the official fire perimeter and compares predicted pixels with the observed burn mask, reporting precision, coverage and the base rate.↩
- The composite function normalises vegetation and dryness to 0–1 and multiplies them, so a pixel scores highly only when both fuel and dryness are present.↩