Builds a neighbour list from an sf polygon layer for the BYM2 model.
By default, a district with no neighbours is linked to the nearest district.
Usage
spi_adjacency(
boundaries,
id_col,
contiguity = "queen",
handle_islands = TRUE,
snap_tolerance = 1e-05
)Arguments
- boundaries
sf object with polygon geometries.
- id_col
character. column name containing the unique district identifier.
- contiguity
character. "queen" (default) or "rook" contiguity rule.
- handle_islands
Logical. If TRUE (default), districts with no neighbours are linked to their nearest district. Separate groups of connected districts are not joined.
- snap_tolerance
numeric. tolerance for boundary matching in CRS units. default 1e-5.
Value
Object of class nb (spdep). A list of length
nrow(boundaries) where element i is an integer vector of neighbour
indices for district i. Key attributes:
region.id– character vector of district ids in graph order; downstream functions use this to aligncases$district_idwith the spatial index.type– "queen" or "rook".sym– logical, TRUE for symmetric graphs (always TRUE for contiguity graphs; may become FALSE after island attachment via knn).ncomp– list describing the connected components.
Details
Neighbour list. An nb object (from spdep) has one element per
district. Element i lists the row numbers of district i's neighbours.
This records which districts share a boundary under the chosen rule.
Use in the model. The BYM2 spatial random effect fitted inside
spi_expected() separates district variation into a structured component (correlated
across neighbours) and an unstructured component. The structured part is
a Gaussian Markov random field whose precision matrix is built directly
from this neighbour graph. Districts with no neighbours contribute no
spatial smoothing. By default, the function links these isolated
districts to their nearest district.
Contiguity rule. Queen contiguity treats districts as neighbours if they share any boundary point (edge or corner); rook requires a shared edge. Queen is the usual choice for administrative polygons.
Inspecting the output
Use the print and summary methods from spdep to inspect the graph:
summary(adj) # link counts, component count, extremes
length(adj) # number of districts
spdep::card(adj) |> table() # distribution of neighbour counts
which(spdep::card(adj) == 0) # remaining islands (should be empty)
attr(adj, "region.id") # district ids in graph order
adj[[1]] # integer indices of district 1's neighboursPlot the graph over the polygons:
ctr <- sf::st_centroid(sf::st_geometry(boundaries))
plot(sf::st_geometry(boundaries), border = "grey80")
plot(adj, sf::st_coordinates(ctr), add = TRUE, col = "steelblue")What to look for.
Average neighbours of roughly 4-7 is typical for admin-2 layers. An average below 2 or above 10 is a reason to check the coordinate reference system and look for gaps, overlaps, or duplicated polygons.
Disjoint connected subgraphs > 1 means the country splits into separate components. BYM2 still fits, but each component is smoothed independently. Check whether the separate components reflect actual geography, such as islands, or errors in the boundaries.
Remaining islands (
card == 0) should be empty whenhandle_islands = TRUE.
See also
spi_expected(), spdep::poly2nb(), spdep::summary.nb()