Fragmentation Metrics Change with Resolution

On this page

Problem statement

The fragmentation statistics from a 30 m forest map say the landscape has tens of thousands of patches; a study using 300 m data reports a few hundred for the same area. Edge density falls sevenfold; core area and the largest patch shift in ways that depend on how cells were aggregated. Neither study is wrong about its map. Fragmentation metrics describe the map at its resolution, and aggregating pixels merges patches, fills narrow gaps and smooths edges β€” systematically, in one direction.

Comparisons across studies, sensors or years with different data are only meaningful at a common resolution, and every fragmentation number should carry the pixel size it was computed at.

Quick answer

Aggregate the forest mask to several resolutions by majority and recompute the metrics:

import numpy as np, rasterio
from scipy import ndimage

with rasterio.open("rondonia_gfc.tif") as src:          # Hansen stack, reading guide
    treecover, lossyear, datamask = src.read()
f = (treecover > 30) & (datamask == 1) & (lossyear == 0)  # forest in 2024
px_m = 0.00025 * 111_320 * np.cos(np.radians(-10.55))       # ~27.4 m: the GFC grid step here

def majority(mask, k):
    h, w = (mask.shape[0] // k) * k, (mask.shape[1] // k) * k
    return mask[:h, :w].reshape(h // k, k, w // k, k).mean(axis=(1, 3)) >= 0.5

def metrics(mask, cell_m):
    lab, n = ndimage.label(mask, structure=np.ones((3, 3)))
    sizes = np.bincount(lab.ravel())[1:]
    edge = mask & ~ndimage.binary_erosion(mask)
    core = ndimage.binary_erosion(mask, iterations=max(1, int(round(100 / cell_m))))
    ha = cell_m ** 2 / 1e4
    return (mask.mean(), n, sizes.max() / mask.sum(),
            edge.sum() * cell_m / (mask.size * ha), core.sum() / mask.sum())

print(f"{'cell':>6}{'forest':>8}{'patches':>9}{'largest':>9}{'edge m/ha':>11}{'core':>7}")
for k in (1, 2, 3, 5, 10):
    m = f if k == 1 else majority(f, k)
    share, n, lp, ed, core = metrics(m, px_m * k)
    print(f"{px_m * k:>5.0f}m{share:>8.0%}{n:>9,}{lp:>9.0%}{ed:>11.1f}{core:>7.0%}")
  cell  forest  patches  largest  edge m/ha   core
   27m     26%   25,871       4%       37.3    28%
   55m     28%   10,312       9%       25.7    31%
   82m     24%    6,339       6%       16.4    44%
  137m     22%    2,684       6%       10.2    37%
  274m     19%      892       5%        5.3    25%

Forest share moves by seven points between the finest and coarsest cells; the patch count falls nearly thirtyfold and edge density sevenfold, while core area moves up and down with no clear direction. The metrics most used to describe fragmentation are the ones most sensitive to resolution.

Record resolution, compare at one, prefer robust measures

1. Record the resolution with every metric

Patch counts and edge densities are meaningless without the pixel size that produced them.

2. Compare at a common resolution

Aggregate the finer dataset to the coarser one's resolution, with the same rule (majority is common), before comparing.

3. Use resolution-robust measures where possible

Forest share and, to a lesser extent, the largest patch index are more stable than patch counts and edge density.

4. Keep the core-area edge depth in metres

When cells get bigger, the number of erosion steps for a 100 m edge depth changes; express the depth in metres and convert per resolution. At coarse resolution it cannot go below one cell.

5. Choose the resolution from the process

Edge effects act over tens to hundreds of metres; a 300 m map cannot resolve them. Use the finest resolution that the data support and the question needs.

A fragmented forest at fine resolution and the same forest aggregated to coarse cells, with small patches and gaps disappearing. coarser cells merge patchesfine: many patches6 patches, narrow gapscoarse: gaps filled2 patchesNarrow clearings vanish first β€” and they are what breaks patches apart spatialworkflow.io
Coarser cells merge patches and fill the gaps between them.

Aggregation rules and vanishing gaps

The data used on this page

The RondΓ΄nia window used throughout the forest guides (63.0°–62.5Β°W, 10.8°–10.3Β°S): Hansen Global Forest Change v1.12 β€” tree cover in 2000, the year of loss, and the data mask β€” read from Google's storage into a three-band rondonia_gfc.tif, as in the Hansen reading guide.

import os

import rasterio
from rasterio.windows import from_bounds

W, S, E, N = -63.0, -10.8, -62.5, -10.3
V = "GFC-2024-v1.12"
if not os.path.exists("rondonia_gfc.tif"):
    bands = []
    for name in ("treecover2000", "lossyear", "datamask"):
        url = f"https://storage.googleapis.com/earthenginepartners-hansen/{V}/Hansen_{V}_{name}_10S_070W.tif"
        with rasterio.open(url) as src:
            window = from_bounds(W, S, E, N, src.transform)
            bands.append(src.read(1, window=window))
            profile = src.profile | {"count": 3, "width": bands[0].shape[1], "height": bands[0].shape[0],
                                     "transform": src.window_transform(window), "compress": "deflate",
                                     "driver": "GTiff", "tiled": False}
    profile.pop("blockxsize", None)
    profile.pop("blockysize", None)
    with rasterio.open("rondonia_gfc.tif", "w", **profile) as dst:
        for i, band in enumerate(bands, start=1):
            dst.write(band, i)
with rasterio.open("rondonia_gfc.tif") as src:
    print(src.count, src.shape, src.crs, src.res)
3 (2000, 2000) EPSG:4326 (0.00025, 0.00025)

Example 1 β€” the aggregation rule

k = 5
maj = majority(f, k)
h, w = (f.shape[0] // k) * k, (f.shape[1] // k) * k
blocks = f[:h, :w].reshape(h // k, k, w // k, k)
any_forest = blocks.any(axis=(1, 3))
all_forest = blocks.all(axis=(1, 3))
for name, m in (("any forest pixel", any_forest), ("majority", maj), ("all pixels forest", all_forest)):
    share, n, lp, ed, core = metrics(m, px_m * k)
    print(f"{name:<18} forest {share:5.0%}, patches {n:>6,}, core {core:4.0%}")
any forest pixel   forest   61%, patches    758, core  50%
majority           forest   22%, patches  2,684, core  37%
all pixels forest  forest    9%, patches  1,008, core  43%

At the same coarse resolution, the rule that decides whether a cell is forest changes even the forest share. At 137 m the forest share ranges from 9% to 61% depending on the rule. "Aggregated to 137 m" is not a complete description without it.

Example 2 β€” narrow gaps disappear

narrow = ~f & ndimage.binary_closing(f, iterations=2)             # gaps a 2-pixel closing fills
print(f"non-forest pixels in gaps up to ~4 pixels wide: {narrow.sum() / (~f).sum():.1%} of non-forest")
print(f"forest share after closing those gaps: {(f | narrow).mean():.1%} (was {f.mean():.1%})")
non-forest pixels in gaps up to ~4 pixels wide: 7.0% of non-forest
forest share after closing those gaps: 31.1% (was 25.9%)

Narrow clearings β€” tracks, stream corridors, the fishbone's side roads β€” are a small share of non-forest area and a large share of what breaks patches apart. They vanish first when resolution coarsens, which is why patch counts collapse.

Example 3 β€” the same change, two resolutions

f2000 = (treecover > 30) & (datamask == 1)
for k in (1, 10):
    a = f2000 if k == 1 else majority(f2000, k)
    b = f if k == 1 else majority(f, k)
    na, nb = metrics(a, px_m * k)[1], metrics(b, px_m * k)[1]
    print(f"{px_m * k:>4.0f} m: patches 2000 {na:>6,} β†’ 2024 {nb:>6,} ({nb / na:.1f}Γ—)")
  27 m: patches 2000 14,079 β†’ 2024 25,871 (1.8Γ—)
 274 m: patches 2000    397 β†’ 2024    892 (2.2Γ—)

Even the direction and size of change in patch count differ between resolutions. A trend in fragmentation is only a trend at one resolution.

Patch count of the 2024 forest at five resolutions, with edge density, for the same forest mask. patches in the 2024 forest, by cell size27 m25,871 Β· 37.3 m/ha edge55 m10,312 Β· 25.7 m/ha82 m6,339 Β· 16.4 m/ha137 m2,684 Β· 10.2 m/ha274 m892 Β· 5.3 m/ha013k26kForest share moves 26% β†’ 19%; patch count falls nearly thirtyfold spatialworkflow.io
The same forest, five pixel sizes, five fragmentation stories.

Why aggregation reduces fragmentation

Why aggregation reduces fragmentation

A coarse cell is forest or not as a whole. Small clearings inside a forested cell disappear; small forest patches inside a cleared cell disappear; narrow gaps between patches are filled when neighbouring cells are mostly forest. Every one of those operations reduces patch counts and edge length.

Why forest share is more robust

Majority aggregation preserves proportions approximately when landscapes are not dominated by features near the cell size. Structure measures depend on the arrangement of pixels, which is exactly what aggregation changes.

Why the choice of resolution is scientific, not technical

Processes act at particular scales: microclimate edges over 50–100 m, animal movement over hundreds of metres to kilometres. A metric computed at a resolution coarser than the process cannot describe it; one computed much finer may add noise.

Forest share, patches and core share at 137 m for three aggregation rules. the same 137 m, three rulesa cell is forest ifforestpatchescoreany pixel is forest61%75850%most pixels are22%2,68437%all pixels are9%1,00843%"Aggregated to 137 m" is incomplete without the rule spatialworkflow.io
The aggregation rule moves even the forest share, from 9% to 61%.

Sensors, mapping units and connectivity

  • Sensor resolution: comparing Landsat-based (30 m) with MODIS-based (250–500 m) fragmentation is comparing two maps, not two landscapes.
  • Minimum mapping unit acts like a resolution change for patch statistics.
  • Connectivity rule (4 or 8 neighbours) interacts with resolution; keep both fixed.
  • Scaling relationships between metrics and resolution are landscape-specific; they cannot be corrected with a universal factor.
  • FRAGSTATS documentation discusses scale dependence of each metric.

FAQ

Why do fragmentation metrics differ between studies?

Different resolutions, aggregation rules, connectivity rules and thresholds.

Which metrics are most sensitive to resolution?

Patch counts, edge density and core area. Forest share is the most robust.

How do I compare fragmentation from 30 m and 250 m data?

Aggregate the 30 m map to 250 m with a stated rule and compare at that resolution.

What aggregation rule should I use?

Majority is common; state it, because "any" and "all" rules give different results.

Can I correct metrics for resolution?

Not with a general factor; the relationship depends on the landscape.

What resolution should I use?

The finest the data support that matches the scale of the process you study.