Build the symmetric adjacency matrix that spatial() and spatial_car()
consume, from a common spatial layout, instead of hand-coding it. The model
still receives an explicit graph (spatial(graph = g$adjacency, ...)), so the
graph stays inspectable before fitting – the engine never guesses
connectivity from coordinates silently.
adjacency() is a single front-door verb that dispatches on the kind of
input:
- a
data.frame cell centroids on a regular grid – queen (edge or corner) or rook (edge only) contiguity over the lattice. This covers both plain coordinate grids and rasterised cells passed as a table of centres.
- an
sfobject polygon contiguity from shared boundaries (queen = share a point or edge; rook = share an edge). Requires sf.
- a
SpatRaster(terra) orstarsobject raster cells – the lattice of (non-
NA) cell centres, queen or rook. Requires terra or stars respectively.
The result is a tulpa_adjacency object holding the matrix plus the cell
identifier for each node, so a model can pass g$adjacency while the
observation data is remapped to 1-based node indices with node_index().
Usage
adjacency(x, ...)
# Default S3 method
adjacency(x, ...)
# S3 method for class 'data.frame'
adjacency(
x,
type = c("queen", "rook"),
x_coord = "x",
y_coord = "y",
id = NULL,
order = 1L,
tolerance = 1.5,
offsets = NULL,
...
)
# S3 method for class 'sf'
adjacency(x, type = c("queen", "rook", "touches"), id = NULL, ...)
# S3 method for class 'SpatRaster'
adjacency(
x,
type = c("queen", "rook"),
order = 1L,
tolerance = 1.5,
offsets = NULL,
na_rm = TRUE,
...
)
# S3 method for class 'stars'
adjacency(
x,
type = c("queen", "rook"),
order = 1L,
tolerance = 1.5,
offsets = NULL,
na_rm = TRUE,
...
)Arguments
- x
The spatial layout: a
data.frameof centroids, ansfpolygon layer, or a raster (SpatRaster/stars).- ...
Passed to methods.
- type
Contiguity rule:
"queen"(default; neighbours share an edge or a corner) or"rook"(neighbours share an edge only). For polygons,"touches"is an alias of"queen".- x_coord, y_coord
For the
data.framemethod, the names of the coordinate columns holding the cell centres (default"x"and"y").- id
For the
data.frameandsfmethods, an optional column naming each cell's identifier. Nodeiof the graph corresponds toid's value in rowi; pass this column tonode_index()to translate the observation data's cell column into node indices. DefaultNULLuses the row position (1:n) as the identifier.- order
For grid / raster layouts, the neighbourhood order (ring count):
order = 1(default) is first-order contiguity (queen = 8 neighbours, rook = 4);order = kextends the stencil to the k-th ring, so queen keeps every cell within Chebyshev distancek((2k + 1)^2 - 1neighbours: 8, 24, 48, ... fork = 1, 2, 3) and rook every cell within Manhattan distancek(2k(k + 1)neighbours: 4, 12, 24, ...). Any positive integer is allowed, so the neighbourhood is fully settable. Ignored by thesf(polygon) method, which is first-order contiguity only.- tolerance
For grid / raster layouts, the per-offset neighbour distance cut-off as a multiple of the inferred cell size: a candidate at a lattice offset is kept when its true centre distance is at most
tolerancetimes that offset's expected distance. The default1.5admits a snapped neighbour while rejecting one much farther than its lattice slot implies; raise it only for irregularly spaced centroids. Neighbourhood extent is set byorder, not bytolerance.- offsets
Advanced, grid / raster layouts only: a custom neighbour stencil as a two-column integer matrix or a list of length-2
c(dx, dy)lattice offsets (cell-step units, origin excluded). Supplying it overridestypeandorderand builds exactly that stencil, so any neighbourhood is expressible (anisotropic, ring-only, off-axis). An ICAR / CAR field is undirected, so the graph must be symmetric: an asymmetric stencil (e.g.list(c(0, 1), c(-1, 0), c(1, 0))= up / left / right but not down) is symmetrized to an undirected graph, with a message, since a directed neighbourhood cannot be represented by an undirected field. DefaultNULLuses thetype/orderstencil.- na_rm
For raster layouts, drop cells whose value is
NAbefore building the graph (defaultTRUE), so the nodes are the cells that carry data.
Value
A tulpa_adjacency object: a list with
adjacencythe
[n x n]symmetric sparse adjacency matrix (dgCMatrix, 0/1, zero diagonal) to pass asgraph/adjacency.idsthe cell identifier for each node, in node order (length
n).nthe number of nodes.
cellsizethe inferred cell size
c(x, y)for grid / raster layouts, orNAfor polygons.typethe contiguity rule used.
See also
node_index() to map cell identifiers to node indices,
check_adjacency() to validate a hand-built matrix, spatial() and
spatial_car() which consume the graph.
Examples
# A 3 x 3 regular grid of cell centres
grid <- expand.grid(x = 1:3, y = 1:3)
grid$cell <- paste0("c", seq_len(nrow(grid)))
g <- adjacency(grid, x_coord = "x", y_coord = "y", id = "cell",
type = "queen")
g
g$adjacency
# Second-order (24-neighbour) queen contiguity: any order is settable
g2 <- adjacency(grid, id = "cell", order = 2)
# Advanced: a custom stencil (symmetrized for the undirected field)
g3 <- adjacency(grid, id = "cell", offsets = list(c(1, 0), c(0, 1)))
# Use it in a model: graph stays explicit and inspectable
spatial(graph = g$adjacency, formula = ~ 1 || cell_idx)
# Remap observation data (original cell ids -> 1:n node indices) by key
obs <- data.frame(cell = c("c5", "c1", "c5", "c9"))
obs$cell_idx <- node_index(g, obs$cell)
obs