Understanding spatial patterns: how to measure and compare them

Jakub Nowosad, https://jakubnowosad.com/

EON Summer School 2025

2025-09-04

Hi, I am Jakub

Computational geographer: intersection between geocomputation and environmental sciences


Associate Professor at the Adam Mickiewicz University, Poznan; Visiting Scientist, University of Münster


Main scientific interest: spatial pattern analysis, focusing on quantifying and understanding patterns in environmental data

Co-author of a few books on geocomputation and spatial analysis with R and Python, including “Geocomputation with R”


Creator and contributor of various R packages for spatial data processing and visualization


Educator, teaching courses on geocomputation, spatial analysis, programming, and data visualization

Website: jakubnowosad.com

Spatial patterns

Discovering and describing patterns is a vital part of many spatial analysis However, spatial data is gathered in many ways and stored in forms, which requires different approaches to understanding spatial patterns

Spatial patterns of categorical rasters

Discovering and describing spatial patterns is an important part of many geographical studies, and spatial patterns are linked to natural and social processes.

Evaluation of the susceptibility of forest landscapes to agricultural expansion

Bourgoin et al., 2020, 10.1016/j.jag.2019.101958

Quantification of diversity and racial segregation

Dmowska et at., 2020, j.apgeog.2020.102239

Reinterpretation of histological images as categorized rasters and their use for disease classification (e.g., liver cancer)

Kendall et al., 2020, 10.1038/s41598-020-74691-9

Spatial patterns in landscape ecology

Hesselbarth, M.H.K., Nowosad, J., de Flamingh, A. et al. Computational Methods in Landscape Ecology. Curr Landscape Ecol Rep 10, 2 (2025). https://doi.org/10.1007/s40823-024-00104-6

Quantification of categorical spatial patterns

Quantification of categorical spatial patterns

Spatial patterns can be quantified using landscape metrics (O’Neill et al. 1988; Turner and Gardner 1991; Li and Reynolds 1993; He et al. 2000; Jaeger 2000; Kot i in. 2006; McGarigal 2014).

Software such as FRAGSTATS, GuidosToolbox, or landscapemetrics has proven useful in many scientific studies (> 12,000 citations).

There is a relationship between an area’s pattern composition and configuration and ecosystem characteristics, such as vegetation diversity, animal distributions, and water quality within this area (Hunsaker i Levine, 1995; Fahrig i Nuttle, 2005; Klingbeil i Willig, 2009; Holzschuh et al., 2010; Fahrig et al., 2011; Carrara et al., 2015; Arroyo-Rodŕıguez et al. 2016; Duflot et al., 2017, many others..)

Quantification of categorical spatial patterns (example questions)

1. Habitat fragmentation

  • How do fragmentation metrics (e.g., patch number, edge density) differ between natural and disturbed landscapes?
  • When are fragmentation thresholds crossed, and how do they affect ecological processes?

2. Biodiversity and habitat suitability

  • Which landscape metrics best predict species richness?
  • How does spatial configuration affect habitat suitability and occupancy?

3. Land use & land cover change

  • How do landscape metrics change over time with deforestation, urbanization, or agriculture?
  • Can time-series metrics identify tipping points or policy shifts?

4. Climate change impacts

  • How will climate-driven range shifts alter landscape structure of species’ habitats?
  • Which landscapes are most vulnerable to climate extremes?

5. Spatial configuration and pattern analysis

  • What is the effect of scale on the interpretation of landscape metrics?
  • What spatial scales capture key landscape patterns?

Example data

Randomly selected 16 rasters (100x100 cells) with different proportions of forest (green) areas from Land cover data for the year 2016 of the CCI-LC project (simplified into nine categories)



Landscape metrics

General assumption is that the spatial pattern of a landscape influences the processes that occur within it

In the last 40 or so years, several hundred different landscape metrics were developed

They quantify the composition and configuration of spatial patterns of categorical rasters

Landscape metrics

Landscape metrics can be calculated for three different levels: patch, class, and landscape (here we (mostly) focus on the landscape level)

Landscape metrics

They can be divided into several groups, for example:

  1. Area and edge metrics describe the size of patches and classes and the amount of edge. These metrics mainly characterize the composition of the landscape and are able to show dominance or rareness of classes.
  2. Shape metrics describe the shape of patches, mainly by using its area and perimeter. This can be important for many research questions, because, e.g., even though, being equal in size, long and narrow patches have probably different characteristics than a squared patch of the same size.
  3. Core metrics describe the area of patches that are not an edge. These metrics can be interesting for research questions in which, e.g., only areas that are not influenced by neighboring patches of a different class are of interest.
  4. Aggregation metrics describe if patches (of the same class) are rather clumped (aggregated) or tend to be isolated. Following, these metrics describe mainly the spatial configuration of the landscape.
  5. Diversity metrics are only available on the landscape level. They describe the abundance and dominance/rareness of classes. Thereby, they show the diversity of present classes.
  6. Complexity metrics represent various aspects of the complexity of the landscape.

Landscape metrics

  • SHDI - Shannon’s diversity index - takes both the number of classes and the abundance of each class into account; larger values indicate higher diversity (diversity metric)
  • AI - Aggregation index - from 0 for maximally disaggregated to 100 for maximally aggregated classes (aggregation metric)

SHDI:


AI:

Landscape metrics

Important considerations:

  • Scale: the size of the area over which the metrics are calculated
  • Extent: the borders of the study area
  • Spatial resolution: the size of the raster cells
  • Categorization: the categories used in the analysis
  • Redundancy: many metrics are highly correlated

IT metrics

  • Five information theory metrics based on a co-occurrence matrix exist (Nowosad and Stepinski, 2019, https://doi.org/10.1007/s10980-019-00830-x)
  • Marginal entropy [H(x)] - diversity (composition) of spatial categories - from monothematic patterns to multithematic patterns
  • Relative mutual information [U] - clumpiness (configuration) of spatial categories from fragmented patterns to consolidated patterns)
  • H(x) and U are uncorrelated

Entropy:


Relative mutual information:

IT metrics

2D parametrization of categorical rasters’ configurations based on two weakly correlated IT metrics groups similar patterns into distinct regions of the parameters space

{landscapemetrics}

library(landscapemetrics)
list_lsm()
# A tibble: 133 × 5
   metric name                                type           level function_name
   <chr>  <chr>                               <chr>          <chr> <chr>        
 1 area   patch area                          area and edge… patch lsm_p_area   
 2 cai    core area index                     core area met… patch lsm_p_cai    
 3 circle related circumscribing circle       shape metric   patch lsm_p_circle 
 4 contig contiguity index                    shape metric   patch lsm_p_contig 
 5 core   core area                           core area met… patch lsm_p_core   
 6 enn    euclidean nearest neighbor distance aggregation m… patch lsm_p_enn    
 7 frac   fractal dimension index             shape metric   patch lsm_p_frac   
 8 gyrate radius of gyration                  area and edge… patch lsm_p_gyrate 
 9 ncore  number of core areas                core area met… patch lsm_p_ncore  
10 para   perimeter-area ratio                shape metric   patch lsm_p_para   
# ℹ 123 more rows

{landscapemetrics}

library(terra)
r9 = rast("exdata/r9.tif")
r1 = rast("exdata/r1.tif")
plot(r1); plot(r9)

{landscapemetrics}: patch-level

lsm_p_perim(r9)
# A tibble: 305 × 6
   layer level class    id metric  value
   <int> <chr> <int> <int> <chr>   <dbl>
 1     1 patch     1     1 perim    1200
 2     1 patch     1     2 perim    1200
 3     1 patch     1     3 perim    1800
 4     1 patch     1     4 perim    1800
 5     1 patch     1     5 perim  255000
 6     1 patch     1     6 perim    1800
 7     1 patch     1     7 perim    1800
 8     1 patch     1     8 perim    2400
 9     1 patch     1     9 perim    6600
10     1 patch     1    10 perim    6000
# ℹ 295 more rows

{landscapemetrics}: class-level

lsm_c_ai(r9)
# A tibble: 7 × 6
  layer level class    id metric value
  <int> <chr> <int> <int> <chr>  <dbl>
1     1 class     1    NA ai      75.9
2     1 class     2    NA ai      90.4
3     1 class     3    NA ai      60.9
4     1 class     5    NA ai      46.1
5     1 class     7    NA ai      75  
6     1 class     8    NA ai       0  
7     1 class     9    NA ai      80.2

{landscapemetrics}: landscape-level

lsm_l_shdi(r9)
# A tibble: 1 × 6
  layer level     class    id metric value
  <int> <chr>     <int> <int> <chr>  <dbl>
1     1 landscape    NA    NA shdi    1.06
lsm_l_ai(r9)
# A tibble: 1 × 6
  layer level     class    id metric value
  <int> <chr>     <int> <int> <chr>  <dbl>
1     1 landscape    NA    NA ai      82.1

{landscapemetrics}: many metrics calculations

calculate_lsm(r9, what = c("lsm_l_shdi", "lsm_l_ai"))
# A tibble: 2 × 6
  layer level     class    id metric value
  <int> <chr>     <int> <int> <chr>  <dbl>
1     1 landscape    NA    NA ai     82.1 
2     1 landscape    NA    NA shdi    1.06
two_r = list(r1, r9)
calculate_lsm(two_r, what = c("lsm_l_shdi", "lsm_l_ai"))
# A tibble: 4 × 6
  layer level     class    id metric   value
  <int> <chr>     <int> <int> <chr>    <dbl>
1     1 landscape    NA    NA ai     98.7   
2     1 landscape    NA    NA shdi    0.0811
3     2 landscape    NA    NA ai     82.1   
4     2 landscape    NA    NA shdi    1.06  

{landscapemetrics}: moving window calculations

mat_window = matrix(1, nrow = 11, ncol = 11)
w_result = window_lsm(r9, window = mat_window, what = "lsm_l_ai")
plot(r9); plot(w_result$layer_1$lsm_l_ai)

{landscapemetrics}: other features

https://r-spatialecology.github.io/landscapemetrics/

# A tibble: 133 × 5
   metric name                                type           level function_name
   <chr>  <chr>                               <chr>          <chr> <chr>        
 1 area   patch area                          area and edge… patch lsm_p_area   
 2 cai    core area index                     core area met… patch lsm_p_cai    
 3 circle related circumscribing circle       shape metric   patch lsm_p_circle 
 4 contig contiguity index                    shape metric   patch lsm_p_contig 
 5 core   core area                           core area met… patch lsm_p_core   
 6 enn    euclidean nearest neighbor distance aggregation m… patch lsm_p_enn    
 7 frac   fractal dimension index             shape metric   patch lsm_p_frac   
 8 gyrate radius of gyration                  area and edge… patch lsm_p_gyrate 
 9 ncore  number of core areas                core area met… patch lsm_p_ncore  
10 para   perimeter-area ratio                shape metric   patch lsm_p_para   
# ℹ 123 more rows
  • Sampling around points of interest
  • Calculating landscape metrics for irregular areas
  • Calculating landscape metrics across scales
  • Visualizations
  • More…

Landscape metrics

Helpful resources:

Exercises

Analyze forest dynamics, fragmentation, and spatial complexity over time using categorical raster land cover data to investigate how the forest structure of broadleaved deciduous trees has changed due to bark beetle infestation and other drivers.

  1. Load land cover raster for 2018, 2021, and 2023 ("exdata/harz_lc2018.tif", "exdata/harz_lc2021.tif", "exdata/harz_lc2023.tif"). Visualize the data to understand its spatial characteristics. Check CRS, extent, resolution, number of categories.
  2. Read the "exdata/harz_borders.gpkg" file and crop and mask the land cover rasters to the Harz region.
  3. Reclassify the land cover rasters to create binary forest maps (1 for forest, 0 for non-forest). (Hint 1: see the ifel() function in terra; Hint 2: broadleaved deciduous trees are represented by the value of 2 in the original data).
  4. Calculate the total forest area for each year and compare changes over time.
  5. Compute key landscape metrics (Total Edge, Patch Density, Mean Patch Area, Marginal Entropy, Relative Mutual Information) for each year.
  6. Compare temporal trends in these metrics to assess fragmentation and diversity. Interpret whether the landscape is becoming more fragmented, diverse, or homogeneous.

Pattern-based spatial analysis

Pattern-based spatial analysis

In recent years, the ideas of analyzing spatial patterns have been extended through an approach called pattern-based spatial analysis (Long in in. 2010; Cardille in in. 2010; Cardille in in. 2012; Jasiewicz i in. 2013; Jasiewicz i in. 2015).

The fundamental idea is to divide data into a large number of smaller areas (local landscapes).

Next, represent each area using a statistical description of the spatial pattern - a spatial signature.

Spatial signatures can be compared using a large number of existing distance or dissimilarity measures (Lin 1991; Cha 2007).

This approach enables spatial analyses such as searching, change detection, clustering, or segmentation.

Pattern-based spatial analysis

Knowing the distance between spatial signatures can be used in several contexts (Nowosad, 2021, 10.1007/s10980-020-01135-0):

one-to-many

finding similar spatial structures

one-to-one

quantitative assessment of changes in spatial structures

many-to-many

clustering similar spatial structures

Examples of applications

Using spatial signatures to compare and evaluate digital soil maps (Rossiter et al., 2022, 10.5194/soil-8-559-2022)


Changes in spatial patterns resulting from the inclusion of small woody elements in land use maps (Golicz et al., 2021, 10.3390/land10101028)

Code examples

library(terra)
library(motif)
landcover = rast(system.file("raster/landcover2015s.tif", package = "motif"))
ecoregions = read_sf(system.file("vector/ecoregionss.gpkg", package = "motif"))
ecoregion1 = ecoregions[1, ]
landcover1 = crop(landcover, ecoregion1, mask = TRUE)
plot(landcover)

plot(landcover1)

Code examples

search_result = lsp_search(landcover1, landcover, 
           type = "cove", dist_fun = "jensen-shannon", window = 25,
           output = "sf")
plot(search_result["dist"])

search_result$id[which.min(search_result$dist)]
[1] 75
search_results_75 = lsp_extract(landcover, window = 25, id = 75)
plot(search_results_75)

Exercises

  1. Use the cropped and masked land cover rasters (with original categories) for 2018, 2021, and 2023 from the Harz region from the previous exercises.
  2. Explore structural change of land cover in the Harz region on a scale of 250 meters: using the lsp_compare() function from the motif package, compare the spatial signatures of land cover in 2018 and 2023 in a window of size 25. (Hint: you need to use the "cove" signature type, "jensen-shannon" as a distance measure used, and "terra" as an output; Hint 2: see https://jakubnowosad.com/motif/articles/v4_compare.html for inspiration).
  3. Plot the dist layer of the results to highlight areas with the strongest changes. How can you interpret the results?
  4. Now, compare 2018 and 2021, and 2021 and 2023. Are the changes between these years similar or different?
  5. Load the land cover raster from 2023 for a given area of interest (AOI) located in the Harz region (“exdata/harz_lc2023_aoa.tif”). Your task is to identify a structurally similar area elsewhere in the Harz region – but from the year 2018 (Hint: use a window = 50 as it looks for areas of a similar size as AOI; Hint 2: see https://jakubnowosad.com/motif/articles/v3_search.html for inspiration). The aim is to identify areas that resemble the 2023 landscape of the AOI in the past, in order to track how such landscapes have evolved over time.
  6. Once you’ve found the most similar area in the 2018 land cover data, examine how this location has evolved in subsequent years – 2021 and 2023 – by comparing the land cover in those years.

Spatial patterns of non-categorical rasters

Non-categorical rasters

library(terra); library(sf)
past = rast("data/past.tif")
cmip_tmin_pl = rast("data/cmip_tmin_pl.tif")

WorldClim version 2.1 climate data
for 1970-2000

CMIP6 downscaled future climate projection for 2061-2080 [model: CNRM-ESM2-1; ssp: “585”]

Minimum temperature (°C)

{spquery}

https://jakubnowosad.com/spquery/

How to find and compare areas with similar spatial patterns in non-categorical rasters (e.g., raster time-series)?

library(spquery)

Search

pzn = st_sf(st_sfc(st_point(c(16.934167, 52.408333)), crs = "EPSG:4326"))
vec = as.numeric(extract(past, pzn, ID = FALSE))
search_tmin = spq_search(vec, cmip_tmin_pl, dist_fun = "euclidean")

Compare

compare_tmin = spq_compare(past, cmip_tmin_pl, dist_fun = "euclidean")

{patternogram}

https://jakubnowosad.com/patternogram/, https://jakubnowosad.com/ecem-2023

How to detect and describe a range of spatial similarity (spatial autocorrelation) for multiple variables?

It can be used to:

  • explore spatial autocorrelations of predictors in machine learning models
  • detect spatial autocorrelation in various data structures
  • compare the spatial autocorrelation of variables over time
  • investigate spatial autocorrelation of categorical spatial patterns

{patternogram}

library(patternogram)
pg1 = patternogram(past, sample_size = 1000)
pg2 = patternogram(cmip_tmin_pl, sample_size = 1000)

{supercells}

https://jakubnowosad.com/supercells/, https://jakubnowosad.com/foss4g-2022/

supercells: an extension of SLIC (Simple Linear Iterative Clustering; Achanta et al. (2012), doi:10.1109/TPAMI.2012.120) that can be applied to non-imagery geospatial rasters that carry:

  • pattern information (co-occurrence matrices)
  • compositional information (histograms)
  • time-series information (ordered sequences)
  • other forms of information for which the use of Euclidean distance may not be justified

Segmentation/regionalization: partitioning space into smaller segments while minimizing internal inhomogeneity and maximizing external isolation

A way to improve the output and reduce the cost of segmentation.

Code examples

library(terra)
library(supercells)
# Version 1
mintemp_zones = supercells(cmip_tmin_pl, k = 150, compactness = 4)
plot(cmip_tmin_pl[[1]]); plot(mintemp_zones, add = TRUE, col = NA)
# Version 2
mintemp_zones = supercells(cmip_tmin_pl, k = 50, compactness = 4)
plot(cmip_tmin_pl[[1]]); plot(mintemp_zones, add = TRUE, col = NA)
# Version 3
mintemp_zones = supercells(cmip_tmin_pl, k = 150, compactness = 1)
plot(cmip_tmin_pl[[1]]); plot(mintemp_zones, add = TRUE, col = NA)

Summary

Summary

  • Landscape metrics are still a useful tool for quantification of spatial patterns in categorical raster data
  • Pattern-based spatial analysis, on the other hand, enables searching, change detection, clustering, and segmentation of spatial patterns in categorical raster data
  • Spatial patterns of non-categorical rasters (e.g., time-series) can be analyzed using the ideas of pattern-based spatial analysis, and also using new methods
  • Many methods are already implemented in open-source software
  • Think of what scientific problems you can tackle using these methods