Following the whole cross-sectional distribution — and asking whether geography conditions mobility
A convergence regression compresses regional growth into one slope. Quah’s critique is that the slope can mislead: β-convergence is perfectly compatible with a widening or polarizing distribution — poor regions can grow faster on average while the cross-section splits into “twin peaks” of rich and poor clubs. Distribution dynamics therefore follows the entire cross-sectional distribution over time — its shape period by period, and the movement of individual regions within it, summarized by Markov transition matrices:
### Distribution dynamics
**What it is.** Distribution dynamics studies how the whole cross-sectional distribution of a variable (typically income per capita relative to the average) evolves: does it narrow (convergence), widen (divergence), or split into humps ('twin peaks' — convergence clubs)? The toolkit follows the density of the *relative* variable over time (kernel densities per period) and summarizes movement within the distribution with transition matrices. It answers questions a single β cannot: β-convergence is compatible with a widening or polarizing distribution (Quah's critique) ...
Note
The two analyze_* functions in this article require the optional giddy dependency: pip install "geometrics[dynamics]" (it is included in geometrics[all]).
The shape of the distribution, period by period
explore_distribution_over_time estimates one kernel density per period on a shared grid. With relative=True each district is divided by the period’s cross-sectional mean first — the distribution-dynamics convention — so 1.0 marks the period average and the plot isolates changes in shape from changes in the overall level:
The relative distribution is strongly right-skewed and stable: a heavy mass of districts below the mean and a long bright tail, with no sign of the mass narrowing toward 1. The same densities animate over the slider if you prefer one curve at a time:
Densities hide who is where. The space-time heatmap pivots the panel to one row per district and one column per year, so persistence (rows keeping their shading left to right) is visible unit by unit. sort_by="north_south" orders rows by centroid latitude using the geometry, and relative=True compares districts within each year rather than tracking the level:
Read top to bottom, the bright bands are not scattered — brightness comes in latitudinal blocks that persist across all six years, a first hint that both the distribution and the map are sticky.
Markov transitions: who moves between quintiles?
analyze_markov_transitions discretizes each year’s relative luminosity into k=5 quintiles and pools every year-to-year move into a transition-probability matrix — row Q1, column Q2 is the probability that a bottom-quintile district climbs one class by the next period:
The result carries the long-run implications of the matrix — the ergodic (steady-state) distribution, the expected sojourn time in each class, and scalar mobility indices:
Pooling 2,595 period-to-period moves, **ntl_total** was discretized into 5 quantile states and its movement summarized by a transition-probability matrix: each row gives the chance of ending the next period in each state, conditional on the current one.
On average a region stays in its current state with probability 0.833 — the diagonal is dominant, so positions in the distribution are highly persistent. The stickiest state is **Q5** (stay probability 0.933); the most mobile is **Q3** (0.744).
The Shorrocks mobility index is 0.209 on a 0 (complete immobility: the identity matrix) to 1.25 (all mass off the diagonal) scale; the Prais determinant index is 0.636 and the Bartholomew index 0.209.
If these transition probabilities kept operating, the cross-section would settle into the ergodic (steady-state) mix with the largest long-run share in **Q4** (0.2, versus 0.2 under an even split).
Expected sojourn times say a region entering **Q5** remains there for about 14.9 consecutive periods before moving.
_These are associations, not causal effects. A causal reading needs a research design — see `explain('correlation_vs_causation')`._
The diagonal dominates: a district’s position in the luminosity distribution is highly persistent (average stay probability 0.83, Shorrocks 0.21), and the extremes are the stickiest — a district entering the top quintile stays roughly fifteen periods. Low mobility is the transition-matrix face of the flat inequality trend in the regional inequality article.
Spatial Markov: does the neighborhood condition mobility?
The classic chain treats every district’s move as exchangeable. Rey’s spatial Markov re-estimates the transition matrix conditional on the spatial lag — the average state of each district’s 6 nearest neighbors — giving one matrix per neighborhood class, and the Bickenbach–Bode LR / Q tests of whether those conditional matrices differ from the pooled one:
H0: transition dynamics identical across the 4 neighbor classes — 6-nearest-neighbor (geographic centroids), row-standardized, n=519
Test
Statistic
dof
p-value
Likelihood ratio (LR)
73.550
24
0.0000
Chi-square (Q)
73.534
24
0.0000
print(smk.interpret())
The spatial Markov chain splits **ntl_total**'s 4-state transition matrix by the neighbors' position (spatial lag under 6-nearest-neighbor (geographic centroids), row-standardized, n=519), giving one matrix per neighborhood class (4 classes); values were expressed relative to each period's mean first.
The unconditional matrix keeps regions in place with average probability 0.871.
Conditioning on context, regions surrounded by **low-value neighbors** stay in place with average probability 0.837, while regions surrounded by **high-value neighbors** do so with 0.896 — movement is more common in low-value neighborhoods.
The homogeneity tests (LR = 73.6, p = 6.26e-07; Q = 73.5, p = 6.3e-07; 24 degrees of freedom) are statistically significant at the 1% level: transition dynamics **differ across neighborhood contexts** — a region's mobility is associated with the state of its neighbors.
_These are associations, not causal effects. A causal reading needs a research design — see `explain('correlation_vs_causation')`._
Both homogeneity tests reject decisively (LR = 73.6, Q = 73.5, p < 0.001): transition dynamics are not the same in every neighborhood. Districts surrounded by dim neighbors move around more (and find it harder to hold a high rank), while districts embedded in bright neighborhoods stay put — geography conditions mobility, the distribution-dynamics counterpart of the spatial spillovers found by the SDM in the India case study.
Where next
Regional inequality — Gini/Theil levels and the between-state decomposition behind this persistence
The India case study — convergence regressions, spillovers, and convergence clubs on the same panel
gm.explain("markov_chains"), gm.explain("spatial_markov"), gm.explain("mobility_measures") — the concept explainers