Rook vs Queen Contiguity Weights

TL;DR: Build both with libpysal.weights.Rook.from_dataframe(gdf) and libpysal.weights.Queen.from_dataframe(gdf). Rook links polygons that share an edge; Queen also links polygons that touch at a single vertex, so Queen is a superset of Rook. Queen raises average neighbour counts and slightly smooths downstream statistics like Moran’s I. On regular grids the difference is systematic (every interior cell gains four diagonal neighbours); on irregular polygons it is usually minor.

Why This Matters

Contiguity is the most common way to define who counts as a neighbour, and the Rook-versus-Queen choice quietly propagates through every statistic you compute afterward. Because a spatial weight matrix encodes your assumption about how influence flows across space, picking the wrong contiguity rule can either isolate units that genuinely interact or connect units that merely graze at a corner. This decision is foundational to the Core Concepts of Spatial Statistics & Geostatistics workflow, and it directly shapes autocorrelation diagnostics, spatial regression, and cluster detection.

The distinction is purely topological. For polygons ii and jj, the contiguity weight is:

wij={1if i and j are contiguous0otherwisew_{ij} = \begin{cases} 1 & \text{if } i \text{ and } j \text{ are contiguous} \\ 0 & \text{otherwise} \end{cases}

What “contiguous” means differs by rule. Under Rook contiguity, ii and jj are neighbours only if their shared boundary has positive length — a genuine edge. Under Queen contiguity, they are neighbours if they share an edge or a single vertex. The chessboard analogy is exact: a rook reaches orthogonally adjacent squares, a queen reaches orthogonal and diagonal squares. Every Rook neighbour is a Queen neighbour, but not the reverse.

Rook vs Queen contiguity neighbours of the centre cell Left grid: rook contiguity highlights the four edge-sharing cells (up, down, left, right) of the centre. Right grid: queen contiguity highlights all eight surrounding cells, adding the four diagonal vertex-touching cells. Rook — shared edge 4 neighbours i N N N N Queen — edge or vertex 8 neighbours i N N N N N N N N Queen adds the four diagonal (vertex-only) contacts that Rook omits i = focal cell · N = neighbour

Rook vs Queen at a Glance

Property Rook Queen
Adjacency rule Shared edge only Shared edge or vertex
Chess analogy Orthogonal moves Orthogonal + diagonal moves
Neighbours on a regular grid (interior) 4 8
Neighbour set Subset of Queen Superset of Rook
Average neighbour count Lower Higher
Effect on spatial lag Sharper, more conservative Smoother, more connected
Sensitivity to corner touches Ignores them Includes them
Common default When only edge flow matters Irregular administrative polygons

Environment and Version Pinning

bash
pip install "geopandas>=1.0" "libpysal>=4.9.0" "esda>=2.5.0" "numpy>=1.23"
python
import geopandas as gpd
import numpy as np
import libpysal
from libpysal.weights import Rook, Queen
from esda.moran import Moran
from shapely.geometry import box

Comparing the Two in Code

The clearest way to decide is to build both weights on the same geometry and inspect how the neighbour structure changes. A regular grid makes the contrast starkest, because every interior cell touches four diagonal neighbours at a vertex.

Build a shared grid and both weights objects

python
# 5x5 grid of unit squares — interior cells reveal the rook/queen gap
cells = [box(x, y, x + 1, y + 1) for y in range(5) for x in range(5)]
gdf = gpd.GeoDataFrame(geometry=cells, crs="EPSG:32618").reset_index(drop=True)

w_rook = Rook.from_dataframe(gdf)
w_queen = Queen.from_dataframe(gdf)

Compare neighbour counts and a single focal cell

python
print(f"Rook  mean neighbours: {w_rook.mean_neighbors:.2f}")
print(f"Queen mean neighbours: {w_queen.mean_neighbors:.2f}")

centre = 12  # interior cell of the 5x5 grid
print(f"Rook  neighbours of cell {centre}: {sorted(w_rook.neighbors[centre])}")
print(f"Queen neighbours of cell {centre}: {sorted(w_queen.neighbors[centre])}")

Typical output:

text
Rook  mean neighbours: 2.72
Queen mean neighbours: 3.84
Rook  neighbours of cell 12: [7, 11, 13, 17]
Queen neighbours of cell 12: [6, 7, 8, 11, 13, 16, 17, 18]

The interior cell has exactly 4 Rook neighbours and 8 Queen neighbours — the four extra are the diagonal, vertex-only contacts.

Measure the downstream effect on Moran’s I

python
rng = np.random.default_rng(3)
gdf["value"] = rng.normal(size=len(gdf))
y = gdf["value"].values

for name, w in [("Rook", w_rook), ("Queen", w_queen)]:
    w.transform = "R"
    mi = Moran(y, w, permutations=999)
    print(f"{name:5s} -> Moran's I = {mi.I:.4f}, p_sim = {mi.p_sim:.3f}")

Running Moran’s I under both weights on identical data isolates the contiguity effect: the statistic shifts purely because the neighbour set changed. On this small grid the two values differ modestly; on a fine raster the Queen smoothing is more pronounced.

Interpreting the Output

w.mean_neighbors quantifies connectivity: Queen is always greater than or equal to Rook because it never removes a neighbour, only adds vertex contacts. The per-cell w.neighbors[centre] printout confirms the mechanism — Queen contributes the diagonal indices Rook lacks.

The downstream Moran’s I comparison is the practically important result. Because Queen spreads the spatial lag across more neighbours, it averages over a slightly larger neighbourhood, which typically attenuates sharp local contrasts and nudges Moran’s I relative to Rook. Whether that nudge helps or hurts depends on your process: if diagonal influence is real, Queen is more faithful; if only edge-adjacent flow is meaningful, Queen introduces spurious links and Rook is more honest.

Critical Best Practices

Match contiguity to the real interaction mechanism

Ask what physically or socially connects your units. If influence travels along shared frontage — a road, a river, an administrative boundary — Rook is the honest model. If corner adjacency plausibly transmits influence, or if boundaries are digitised imprecisely, Queen better reflects reality. The rule should encode a hypothesis, not a habit.

Beware the regular-grid caveat

On lattices and raster-derived polygons, Queen contiguity systematically grants every interior cell four extra diagonal neighbours, doubling connectivity from 4 to 8. This is rarely justified by a real diagonal process and can over-smooth your statistics. On regular grids, default to Rook unless you have a specific reason to treat diagonals as neighbours.

Watch for slivers and digitising artefacts

With irregular administrative polygons, tiny gaps or overlaps from digitising can make two units that should share an edge appear to touch only at a point — or not at all. Queen is more forgiving of these near-touches, which is a reason it is often preferred for real-world boundary data. Inspect w.islands under both rules to catch units left with no neighbours.

Keep the same weights object throughout an analysis

Once you choose Rook or Queen, row-standardize it (w.transform = "R") and reuse the same object for every downstream statistic — global and local autocorrelation, regression, cluster detection. Silently swapping contiguity between steps makes results incomparable. For fully bespoke neighbour definitions beyond contiguity, see Building Custom Spatial Weights Matrices.

Document the choice

Report which contiguity rule you used and why. Because the rule changes neighbour counts and therefore every derived statistic, an undocumented Rook-versus-Queen decision undermines reproducibility. State it alongside your CRS and standardization choice.

Troubleshooting

Symptom Likely cause Fix
Rook and Queen give identical neighbours No polygons meet at a single vertex Expected for many irregular layouts; no action needed
Unexpected islands under Rook Units touch only at a corner Use Queen, or merge/snap boundaries
Queen over-smooths results on a grid Diagonal contacts inflate connectivity Switch to Rook for lattice/raster data
mean_neighbors far higher than expected Overlapping or slivered polygons create false contacts Clean geometries with gdf.geometry = gdf.buffer(0)
UserWarning: islands under both rules Genuinely disconnected units Remove them or switch to KNN.from_dataframe
Moran’s I changes drastically between rules Signal concentrated along diagonals or edges Report both and justify the contiguity from the process

Next Steps

Once you have chosen a contiguity rule, feed the row-standardized weights into an autocorrelation test — see How to Calculate Moran’s I in PySAL. When contiguity is too rigid for your process, move on to fully custom neighbour definitions in Building Custom Spatial Weights Matrices, both anchored in the Spatial Weight Matrices topic.

Frequently Asked Questions

What is the difference between Rook and Queen contiguity?

Rook contiguity treats two polygons as neighbours only when they share a boundary segment (an edge), like a rook moving on a chessboard. Queen contiguity also counts polygons that touch at a single point (a vertex), like a queen moving diagonally. Queen is therefore a superset of Rook: every Rook neighbour is also a Queen neighbour, plus the vertex-only contacts.

Does the choice of Rook or Queen change Moran’s I?

It can. Queen contiguity adds diagonal neighbours, which raises the average neighbour count and slightly smooths the spatial lag, usually nudging Moran’s I. On irregular administrative polygons the difference is often small because few units meet at a single point, but on regular grids every interior cell gains four diagonal neighbours, so the effect is systematic and larger.

Which should I use by default for polygons?

Queen contiguity is the common default for irregular administrative polygons because it avoids treating near-touching units as isolated when boundaries meet at a corner due to digitising precision. Use Rook when only genuine shared-edge flow is meaningful, such as adjacency defined by a shared road or river frontage, or when you want the more conservative neighbour set.


← Back to Spatial Weight Matrices

Related