PlanX
Urban Analytics Studio — Comprehensive Academic Reference Manual
Covering PlanX v4.10.1 · 69 Algorithms · 19 Tool Groups
August 2026
Yusuf Eminoğlu · github.com/YusufEminoglu/PlanX
How to Use This Manual
This manual is the definitive academic reference for every algorithm in PlanX — Urban Analytics Studio (v4.10.1). It is written for urban planners, spatial analysts, researchers, and students who need to understand not just what a tool produces, but why the method works, how to configure it correctly, and what the results mean in a real planning context.
Structure of each algorithm entry
Every one of the 69 algorithms is documented to an identical eight-section template:
- Overview — what problem it solves and how, in one page
- Theoretical Background — the academic lineage, key contributors, assumptions
- Mathematical Formulation — every equation with term-by-term explanation
- Input Data Requirements — what data you need, where to get it, how to prepare it
- Parameters — every dialog tab, every input, with recommendations per scenario
- Output Description — every output field, its meaning, units, and typical ranges
- Symbolic Representation — how to style the results in QGIS for publication
- Interpretation Guide — how to read the results, common pitfalls, planning actions
Academic references
Each algorithm section concludes with a curated list of academic references — the foundational papers, textbooks, and technical reports that underpin the method. Where a DOI exists, it is provided as a clickable link to the published version. Conference proceedings, institutional reports, and older monographs that do not assign DOIs are cited with full bibliographic detail and, where available, a stable institutional URL. All references have been selected to support both theoretical understanding and applied planning practice.
Typographic conventions
monospace— parameter names, field names, code identifiers- bold — key concepts on first introduction
- italic — journal names, book titles, emphasis
- Math is rendered with MathJax: $E = mc^2$ for inline, $$E = mc^2 \tag{1}$$ for display
Introduction to PlanX
PlanX — Urban Analytics Studio is a comprehensive geospatial analysis platform delivered as a QGIS Processing provider. Its 69 algorithms span the full urban-planning workflow: from understanding the existing city (network analysis, morphology, microclimate) through diagnosing problems (equity, accessibility, walkability) to designing and evaluating interventions (optimization, growth simulation, scenario comparison).
Architecture
PlanX follows a strict three-layer architecture:
- Algorithm layer (
algorithms/alg_*.py) — thin QGIS Processing wrappers that define parameters, validate inputs, and format outputs. They contain no analytical logic. - Engine layer (
engine/*.py) — pure NumPy/SciPy modules that implement every method. They contain no QGIS imports and can be tested, profiled, and reasoned about independently. - Plugin shell (
planx.py,provider.py,studio_dock.py) — the QGIS integration surface: menus, docks, the tool browser, and the dashboard.
This separation means the mathematics described in this manual corresponds
directly to the NumPy implementation in engine/ — what you read
here is what runs.
The 19 tool groups
| # | Group | Tools | Domain |
|---|---|---|---|
| 1 | Network Analysis | 6 | Graph construction, shortest paths, service areas, criticality |
| 2 | Centrality & Space Syntax | 2 | Closeness, betweenness, angular integration & choice |
| 3 | Urban Morphology | 4 | Building shape, tessellation, density, street form |
| 4 | Accessibility | 1 | 15-minute multi-amenity access scores |
| 5 | Microclimate | 10 | Solar, shadow, wind, heat, noise, emissions, air quality |
| 6 | Plan Standards & QA | 3 | Land-use balance, facility adequacy, density grids |
| 7 | Reporting & Dashboard | 7 | Reports, scenarios, snapshots, ranking, audits |
| 8 | Optimization | 5 | Facility location, allocation, land-use Pareto fronts |
| 9 | Equity | 3 | Gini, Theil, Lorenz curves, demographic cross-tabs |
| 10 | Walkability | 4 | Audit scores, slope comfort, street environment, route quality |
| 11 | Transit | 3 | GTFS import, frequency, travel-time access (RAPTOR) |
| 12 | Visibility | 3 | Viewshed, isovist field, landmark exposure |
| 13 | Population & Housing | 4 | Cohort-component projection, housing needs, capacity |
| 14 | Green Infrastructure | 2 | Park access hierarchy, connectivity (PC/dPC) |
| 15 | Urban Growth | 3 | Land-cover change, CA simulation, sprawl metrics |
| 16 | Cycling | 2 | Level of Traffic Stress, low-stress connectivity islands |
| 17 | Hazard Screening | 3 | Flow accumulation, HAND inundation, flood exposure |
| 18 | Travel Demand | 3 | Trip generation, gravity distribution, mode split |
| 19 | Seismic Risk | 1 | Seismic debris estimation |
Design principles
- No external solvers. Every method runs inside the plugin using only NumPy (and optionally SciPy for sparse-matrix acceleration, with an identical pure-Python fallback). No web services, no licensed libraries, no cloud dependencies.
- Deterministic. Given the same inputs and version, every algorithm produces identical outputs. Random seeds are fixed; tie-breaking is lexicographic.
- Screening, not compliance. The environmental modules (noise, air quality, solar) are professional screening tools — they use the standard engineering formulas but are not a substitute for detailed environmental impact assessment by a licensed professional.
1. Network Analysis
The Network Analysis group provides the foundational graph infrastructure for the entire PlanX platform. Streets are modelled as an undirected primal graph where junctions are nodes and street segments are edges weighted by length (or a user-specified cost field). On this graph, the group builds the six classic transport-network queries: preparation (topological cleaning and node assignment), origin–destination cost matrices and routes, service areas (isochrones), nearest-facility allocation, and link criticality screening.
All six tools share a single Dijkstra engine (engine/paths.py)
that uses scipy.sparse.csgraph when available and a pure-Python
heapq kernel otherwise, with identical results asserted by unit
tests. The engine tracks predecessor nodes and edge identifiers through the
shortest-path tree, enabling full route-geometry reconstruction — not just
costs.
Prepare Network
Processing ID: planx:preparenetwork
Overview
Converts raw street centreline layers into a topologically clean, routable network graph. This is the mandatory first step before any other network tool in PlanX: it snaps endpoints, assigns node IDs, computes edge lengths, and builds the adjacency structure that every downstream algorithm consumes. Without this preparation, crossing lines that appear connected visually will be treated as separate, unconnected edges — producing broken routes and nonsensical isochrones.
Theoretical Background
Academic lineage
Transport network analysis inherits from graph theory, whose formal foundations were laid by Leonhard Euler in 1736 with the Koenigsberg bridge problem — the first demonstration that the geometry of connection, not the geometry of distance, governs whether a network can be traversed. The modern computational treatment begins with Dijkstra's shortest-path algorithm (Dijkstra, 1959), which introduced the priority-queue relaxation paradigm that remains the backbone of every routing engine six decades later. In the GIS domain, network preparation was systematised through the 1990s and early 2000s as transportation agencies digitised their road inventories: the key contributions are the planar enforcement rules of early GIS topology engines (ARC/INFO, circa 1982), the generalised network data model of Goodchild (1998), and Curtin's (2007) comprehensive review that codified the distinction between geometric line layers and topological networks.
More recently, the explosion of OpenStreetMap (founded 2004) as a global
road dataset made network preparation a routine prerequisite rather than a
specialist task — but also introduced new challenges: OSM contributors draw
crossing roads that do not share a node, double-digitised carriageways, and
dangling stubs. The field has converged on a standard pipeline: (1) snap
endpoints within a tolerance, (2) split lines at mutual intersections,
(3) build an adjacency structure. This is the pipeline implemented in PlanX,
and it is functionally equivalent to the v.clean tool in GRASS
GIS, the pgRouting topology builder, and NetworkX's
from_edgelist — but runs in pure NumPy with an R-tree spatial
index so that no external network library is required.
Key assumptions
- Planarity. The algorithm assumes that street segments form
a planar or near-planar graph. Overpasses, tunnels, and grade-separated
intersections create false crossings that must be resolved before
preparation — the tool cannot distinguish a genuine intersection from a
bridge crossing on the basis of geometry alone. A
levelorlayerattribute should be used to split the input beforehand if grade separation matters for routing. - Projected CRS. Edge lengths are computed as Euclidean distances in map units. A geographic CRS (latitude–longitude degrees) will produce edge lengths in decimal degrees, which are meaningless for any distance-based analysis. Use a local UTM zone or an equal-area projection.
- Tolerance sensitivity. The snapping tolerance $\varepsilon$ is the most consequential parameter. Too small: crossing lines that appear connected visually remain disconnected in the graph. Too large: distinct intersections collapse into a single junction, creating false adjacency. A value of 0.5–1.0 metre works well for urban street-centreline data at 1:1,000–1:10,000 scale. For OSM data in dense urban cores, start at 1.0 m and inspect the result before proceeding.
- Undirected graph. The network is built as an undirected graph — all edges can be traversed in both directions. For one-way streets, filter the edge set after preparation and remove the forbidden direction from the adjacency list.
- No turn penalties. The primal graph representation does not model turn costs at intersections; a junction is a single node where all incident edges meet. If turn penalties matter (e.g. banned left turns, signalised intersection delays), use a line graph (dual graph) representation instead — this is precisely what the Space Syntax tool does with its segment angular analysis.
When to use vs. when NOT to use
Use Prepare Network when: you have a raw street-centreline layer and intend to run any downstream network analysis (shortest paths, catchments, centrality). The tool is mandatory before OD Cost Matrix, OD Routes, Service Areas, Nearest Facility, Link Criticality, Network Centrality, and Space Syntax. In practice, Prepare Network should be the first step in every PlanX project that involves the street grid.
Do NOT use when: (a) the input is already a verified
topological network (e.g. a pgRouting export, a previous Prepare Network
output with intact node_a/node_b fields);
(b) the analysis does not involve routing — building metrics, solar
radiation, and demographic analysis do not need a prepared network graph;
(c) the input contains grade-separated crossings that geometry alone cannot
resolve, and you lack a level attribute to split on — in this
case, manually split the input at the known bridge/underpass locations first.
Mathematical Formulation
Given a set of $m$ polylines $\{P_1, \ldots, P_m\}$ where each polyline is a sequence of coordinate pairs $P_i = \{(x_1, y_1), \ldots, (x_{k_i}, y_{k_i})\}$, the algorithm constructs a primal graph $G = (V, E)$ through the following sequence of operations.
Node set $V$ — snapping and deduplication. The raw endpoints of every polyline segment form a multiset of coordinate pairs. Two endpoints $p, q$ are snapped together when their Euclidean distance falls within the tolerance $\varepsilon$. The implementation uses an R-tree spatial index: for each unprocessed endpoint $p$, a bounding-box query of radius $\varepsilon$ retrieves nearby endpoints; all within tolerance are merged to their centroid. Formally:
$$\|p - q\|_2 \leq \varepsilon \quad\Rightarrow\quad p, q \text{ share the same node } v \in V \tag{3}$$where $\varepsilon$ is the snapping tolerance (default: 1.0 map unit). This step transforms $O(m^2)$ naive pairwise checking into $O(m \log m)$ spatial-index lookups. Nodes are assigned consecutive integer IDs $0, 1, \ldots, n-1$ after deduplication.
Edge set $E$ — splitting at mutual intersections. For every pair of segments that intersect at a point $p_{int}$ not already a node, both segments are split at $p_{int}$, and $p_{int}$ is added to $V$. This ensures that the resulting graph is planarised: every edge intersection corresponds to a node. Each edge $e = (u, v)$ carries a weight equal to either its geometric length or a user-specified cost field value:
$$w(e) = \ell_e \quad \text{or} \quad w(e) = f_{\text{cost}}(e) \tag{2}$$where $\ell_e$ is the Euclidean length of the segment in map units, computed as the sum of distances between consecutive vertices along the polyline:
$$\ell_e = \sum_{t=1}^{k-1} \sqrt{(x_{t+1} - x_t)^2 + (y_{t+1} - y_t)^2} \tag{1}$$When a cost field $f_{\text{cost}}(e)$ is provided (e.g. travel time in seconds), the edge weight becomes that field's value. This is critical for time-based routing: a short but slow street (e.g. a pedestrian lane with stairs) can carry a higher cost than a longer but faster one. The cost must be additive — a sum over segments, not an average or a rate. Speed fields (km/h) must be converted to travel time (length/speed) before use.
Adjacency — CSR representation. The graph is stored as a compressed sparse row (CSR) tuple $(indptr, indices, data)$ where:
- $indptr[i]$ marks the start of the adjacency list for node $i$
- $indices[j]$ is the destination node of the $j$-th adjacency entry
- $data[j]$ is the weight (cost) of the edge at position $j$
Because the graph is undirected, each edge $(u, v)$ produces two adjacency
entries: $(u \rightarrow v)$ and $(v \rightarrow u)$, both with the same weight.
The CSR format is directly consumable by SciPy's csgraph.dijkstra
for the C-accelerated fast path, and by PlanX's pure-Python heapq
Dijkstra kernel for the fallback — both producing numerically identical results.
Edge multiplicity. If two segments share the same endpoint
pair $(u, v)$ (parallel edges, e.g. dual carriageways digitised as separate
lines), both are retained as separate adjacency entries. The Dijkstra kernels
correctly handle parallel edges: during relaxation, each entry is considered
independently, and the one yielding the lower cumulative cost wins. The
predecessor-tracking variant (shortest_path_tree) records
which specific edge was traversed, enabling correct route reconstruction
even with parallel edges — a capability that distinguishes it from simpler CSR
Dijkstra implementations.
Complexity. With $m$ input polylines producing $n$ nodes and $e$ edges after splitting, the preparation runs in $O(m \log m + e)$ time dominated by the R-tree spatial-index construction and the intersection tests. For a typical urban network of 10,000 street segments, preparation completes in under 5 seconds on commodity hardware.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Road centreline layer. Must be in a projected CRS (metres). Crossing lines must share a node at the intersection — if they don't, use the snapping tolerance or split them first. |
Where to obtain: OpenStreetMap (via QuickOSM, Overpass
Turbo, or the OSM Downloader plugin), municipal GIS portals, national mapping
agencies. For OSM, download the highway key with values
motorway, trunk, primary, secondary, tertiary, residential, living_street,
pedestrian, footway, cycleway, path.
Preprocessing: Remove duplicate geometries, fix invalid
geometries (Fix Geometries tool), ensure lines are not multipart
(use Multipart to Singleparts). Dead-end stubs are fine; the graph
handles degree-1 nodes naturally.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector layer (Line) | — | Input street centreline layer. The tool expects simple linestrings; multipart geometries are not handled. |
COST_FIELD | Field (Numeric) | — (optional) | If provided, edge weights use this field instead of geometric length. Use for travel time (seconds) or impedance-weighted analysis. |
TOLERANCE | Double | 1.0 | Snapping tolerance in map units. Endpoints closer than this are merged into a single junction. Increase for messy data (2–5 m), decrease for precise data (0.1 m). Too large a tolerance collapses distinct intersections. |
OUTPUT | Vector layer (Line) | — | Prepared network with node IDs and segment lengths as attributes. |
Output Description
| Field | Type | Description |
|---|---|---|
node_a | Integer | Source node ID of the segment |
node_b | Integer | Target node ID of the segment |
length | Double | Geometric length of the segment in map units (typically metres) |
cost | Double | Travel cost (equals length unless a cost field was specified) |
Symbolic Representation
Style the output as a thin line (0.3 mm) in dark grey. Nodes (junctions)
can be visualised by extracting the unique endpoints and styling as small
circles (1 mm). Colour-code by node_a if you need to trace
connectivity. The prepared network is an intermediate product — its visual
quality matters less than its topological correctness.
Interpretation Guide
Verifying preparation quality
The prepared network is an intermediate product — its visual quality matters less than its topological correctness. Three diagnostic checks should be performed before proceeding to downstream analyses:
- Node degree histogram. In a typical urban grid, most junctions have degree 3 (T-intersection) or degree 4 (cross-intersection). Degree-2 nodes represent polyline vertices that were not split — they are interior points along a segment, not true intersections. Degree-1 nodes are dead-ends (cul-de-sac terminations or network-edge stubs). A histogram heavy on degree-1 nodes with no cul-de-sac geography suggests undersnapping — endpoints that should have merged but did not. A histogram with degree 5+ nodes suggests oversnapping — distinct intersections collapsed into one.
- Service area quick test. Run a single Service Areas analysis with a 500 m break on one centrally located facility. The resulting catchment should form a contiguous, roughly isotropic blob with no gaps or spikes. Gaps indicate disconnected segments within the buffer; spikes along a single street indicate the only connected corridor. If the catchment resembles a starburst along one road but ignores large adjacent areas, the snapping tolerance was too low — crossing streets look connected visually but are not in the graph.
- Edge count sanity check. The number of edges in the output should equal the number of input segments plus the number of intersection splits. If it grows by more than 10–15%, the input probably had many false crossings (unresolved grade separations); if it shrinks, duplicate geometries were present in the input.
Cost field selection
The choice between geometric length and a custom cost field is the single most important decision at the preparation stage, because it carries through to every downstream analysis. Length-based routing answers the question "how far is it on the map?" Time-based routing answers "how long does it take?" — and in urban environments with heterogeneous street types, the two can diverge dramatically:
- Walkability studies: use the
time_fwd_minfield from Walking Slope Comfort as the cost field. This accounts for slope-induced speed differences, so uphill walks are priced honestly and downhill walks get the speed bonus they confer in reality. - Vehicular analysis: use a travel-time field computed from posted speed limits. A 500 m motorway segment at 100 km/h costs 0.3 min; the same length on a 30 km/h residential street costs 1.0 min — a factor of three difference that geometric-length routing cannot capture.
- Transit access: use walking time to a stop, not Euclidean distance. A bus stop 200 m away as the crow flies but 600 m by the footpath network is effectively three times farther than it appears.
Common misinterpretations
- "The network is ready because the lines look connected." Visual inspection of a line layer tells you nothing about topological connectivity. Two lines that cross on screen but lack a shared node are not connected in the graph — Dijkstra will route around them, producing routes that jump nonsensically. This is the most frequent cause of "buggy" network analysis results in GIS, and Prepare Network exists precisely to eliminate it.
- "Larger tolerance = more robust." A snapping tolerance larger than about half the minimum block length will merge distinct intersections. In dense urban cores where blocks are 50–80 m wide, a tolerance of 25 m or more can collapse the entire neighbourhood's junctions into a single super-node, making the graph useless. Always start with the smallest plausible tolerance (0.5–1.0 m for urban data) and increase only if inspection reveals unsnapped crossings.
- "Cost = speed." The cost field must be additive — it
accumulates along a path as a sum. Speed (km/h) is not additive: the
average of two segment speeds is not the sum. If your data contains a speed
field, precompute
cost = length / speedin the attribute table and use that precomputed field.
Cross-references
The prepared network's node_a, node_b, and
cost fields are consumed by every downstream tool in Group 1
(Network Analysis) and Group 2 (Centrality & Space Syntax). The CSR graph
built during preparation is serialised internally and reused across sessions
when the input layer's file path and modification timestamp match — this cache
avoids repeated preparation of the same network. For slope-aware or
speed-aware routing, compute the cost field in a preprocessing step
(Walking Slope Comfort or an external field
calculator) and pass it to Prepare Network as COST_FIELD.
Academic References
Curtin, K.M. (2007). "Network Analysis in Geographic Information Science: Review, Assessment, and Projections." Cartography and Geographic Information Science, 34(2), 103–111. DOI: 10.1559/152304007781002163
Dijkstra, E.W. (1959). "A Note on Two Problems in Connexion with Graphs." Numerische Mathematik, 1(1), 269–271. DOI: 10.1007/BF01386390
Barabasi, A.-L. & Albert, R. (1999). "Emergence of Scaling in Random Networks." Science, 286(5439), 509–512. DOI: 10.1126/science.286.5439.509
Rodrigue, J.-P., Comtois, C. & Slack, B. (2017). The Geography of Transport Systems. 4th ed., Routledge. textbook, no DOI assigned] Available at: transportgeography.org
2. Centrality & Space Syntax
This group quantifies the structural position of every street segment within the network — how central or peripheral it is, how much through-movement it attracts, and how easily it can be reached. The two tools are complementary: Network Centrality works on the primal graph with metric (Euclidean/length) costs, computing the four canonical centrality measures — closeness, betweenness, straightness, and eigenvector. Space Syntax works on the segment dual graph with angular costs (turn degree ÷ 90), computing the Hillier space-syntax measures of angular integration (to-movement potential) and angular choice (through-movement potential), including the size-normalised NACH and NAIN indices.
Taken together, these two tools provide the configurational diagnosis of a street network — the single most influential analysis in the PlanX suite for master-plan evaluation, because street configuration, once built, persists for centuries.
Network Centrality
Processing ID: planx:networkcentrality
Overview
Computes four classic graph-centrality indices for every node in a prepared street network: closeness (how near a node is to all others), betweenness (how many shortest paths pass through a node), straightness (how direct routes from a node are, comparing Euclidean to network distance), and eigenvector centrality (how connected a node is to other well-connected nodes, via power iteration). Each measure can be computed at multiple metric radii to separate local from global structure.
The tool uses Brandes' (2001) $O(nm + n^2 \log n)$ algorithm for betweenness with radius limiting and optional source sampling for large networks. Closeness follows the Wasserman–Faust normalisation so that values are comparable across networks of different sizes.
Theoretical Background
Academic lineage
Centrality is one of the oldest and most studied concepts in network science. Its modern form traces to Alex Bavelas (1948), who first formalised the mathematical properties of group structures at MIT's Group Networks Laboratory under Kurt Lewin, showing that the position of a person within a communication network determined their influence and efficiency. Linton Freeman (1977) unified the proliferating measures into a coherent framework, establishing that three distinct structural properties — degree (activity), closeness (efficiency of access), and betweenness (control over flows) — capture fundamentally different dimensions of being "central." Phillip Bonacich (1972) introduced the eigenvector formulation: a node's centrality is proportional to the sum of its neighbours' centralities, capturing the recursive notion that being connected to a central node is more valuable than being connected to a peripheral one.
In urban studies, centrality measures translate directly into spatial quantities with economic meaning. Porta, Crucitti & Latora (2006a, 2006b) were the first to apply the full set of centrality indices to street networks at city scale under the label Multiple Centrality Assessment (MCA). Their landmark finding: self-organised (historically grown) cities exhibit scale-free centrality distributions similar to those found in biological and social networks, while planned cities do not — the planning act truncates the power-law tail. Sevtsuk & Mekonnen (2012) operationalised this as a GIS toolbox (Urban Network Analysis for ArcGIS), adding building-level weighting, so that two neighbouring buildings on the same street segment receive different reach scores if one has more residents. The PlanX implementation follows the same primal-graph, metric-cost paradigm but runs entirely within QGIS using the embedded Dijkstra and Brandes kernels.
Key assumptions
- Shortest-path behaviour. All four measures assume that movement, interaction, or influence follows shortest (least-cost) paths. This is a reasonable first approximation for vehicular and pedestrian movement in uncontested street networks, but it systematically underestimates centrality on streets that people use despite not being on the shortest path — scenic routes, historic streets, and shopping high streets that people deliberately detour to visit.
- Node-level aggregation. Centrality is computed at graph nodes (junctions), not at edges (segments). This means the result is a point layer, not a line layer. For segment-level analysis (e.g. "which street segments are most central?"), use Space Syntax, which operates on the segment dual graph.
- Undirected graph. The graph is treated as undirected — centrality does not distinguish inbound from outbound movement. For directional centrality (e.g. morning-peak inbound betweenness), the graph must be constructed with directed edges, which PlanX's primal graph does not currently support.
- Radius sensitivity. Radius choice is the most consequential parameter. A small radius (400 m) reveals neighbourhood centres; a large radius (5000+ m) reveals the metropolitan structural core. Running only the global radius ("n") conflates all scales and can mask a clear neighbourhood centre behind a weak global score.
- Sample approximation. When
SAMPLE < 1.0, betweenness is estimated from a random subset of source nodes and scaled proportionally. The estimate is unbiased (expected value equals the exact value) but has variance proportional to $1/\sqrt{k}$ where $k$ is the number of sampled sources. At 10% sampling, betweenness rank-order correlations are typically $r > 0.95$ with the exact values — sufficient for mapping and ranking, but insufficient for precise numerical thresholds.
When to use vs. when NOT to use
Use Network Centrality when: you need a multi-dimensional diagnosis of the network's structural organisation (not the demand-weighted consequences — use Link Criticality for that); when comparing the spatial structure of different cities or different neighbourhoods within a city; when identifying candidate locations for new services (high closeness nodes), new transit corridors (high betweenness edges), or bypasses (high betweenness nodes that are also bottlenecks).
Do NOT use when: (a) you need segment-level (not node-level) centrality — use Space Syntax; (b) you need demand-weighted criticality — use Link Criticality; (c) the network is very small (under 100 nodes) and the ranking is driven by edge effects rather than structure — buffer your study area with at least one neighbourhood's worth of extra network; (d) you need directed (in/out) centrality for transport planning — the undirected primal graph does not distinguish directions.
Mathematical Formulation
Closeness (Wasserman–Faust):
$$C_C(i) = \frac{N_r(i) - 1}{N - 1} \cdot \frac{N_r(i) - 1}{\sum_{j \in V_r(i)} d(i, j)} \tag{4}$$where $d(i,j)$ is the shortest-path distance, $V_r(i)$ is the set of nodes reachable from $i$ within radius $r$, and $N_r(i) = |V_r(i)|$. The first factor is the Wasserman–Faust correction for partial reachability; the second is the raw closeness (inverse mean distance).
Betweenness (Brandes, 2001):
$$C_B(v) = \sum_{\substack{s,t \in V \\ s \neq v \neq t \\ d(s,t) \leq r}} \frac{\sigma_{st}(v)}{\sigma_{st}} \tag{3}$$where $\sigma_{st}$ is the number of shortest paths from $s$ to $t$, and $\sigma_{st}(v)$ is the number of those paths that pass through $v$.
Straightness:
$$C_S(i) = \frac{1}{N_r(i) - 1} \sum_{j \in V_r(i),\, j \neq i} \frac{\|p_i - p_j\|_2}{d(i, j)} \tag{2}$$Eigenvector centrality:
$$C_E(i) = \frac{1}{\lambda} \sum_{j \in \mathcal{N}(i)} C_E(j) \tag{1}$$where $\lambda$ is the largest eigenvalue of the adjacency matrix $A + I$, and $\mathcal{N}(i)$ is the set of neighbours of node $i$. The power iteration converges when $\|x^{(k+1)} - x^{(k)}\|_\infty < 10^{-6}$.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Network | Vector lines (prepared) | Yes | Output of Prepare Network. Must have node_a, node_b, and cost fields. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector layer (Line) | — | Prepared street network from the Prepare Network tool. |
RADII | String | "n" | Metric radii as comma-separated values; "n" = global (no radius limit). Use 400–800 m for neighbourhood-scale, 2000+ m for city scale. |
SAMPLE | Double | 1.0 | Fraction of nodes used as betweenness sources (0–1). At 1.0 all nodes are sources (exact); at 0.1 a random 10% sample is used, giving an unbiased estimate at ~10× speed on large networks. |
OUTPUT | Vector layer (Point) | — | Node layer with centrality scores. One row per junction node. |
Output Description
| Field | Type | Description |
|---|---|---|
closeness_{r} | Double | Wasserman–Faust closeness. 0–1; higher = more accessible. Low values signal peripheral/isolated nodes. |
betweenness_{r} | Double | Brandes betweenness. Raw count; heavily right-skewed. Normalise by $(N-1)(N-2)$ for comparability. |
straightness_{r} | Double | Mean Euclidean/network ratio. 0–1; 1 = perfectly straight radial routes; <0.3 = highly circuitous. |
eigenvector_{r} | Double | Eigenvector centrality after power iteration. Relative scale; the absolute values are less important than the ranking. |
(One set per radius; suffix is the radius label, e.g. closeness_800, betweenness_n.)
Symbolic Representation
Map betweenness with a graduated renderer using a sequential multi-hue ramp (Viridis or Inferno) in natural-breaks classification (5–7 classes). Closeness benefits from the same treatment. Straightness works well with a diverging ramp (RdYlGn) centred at the median. Eigenvector centrality is best visualised with quantile classification (5 classes) to expose the rank structure — the top quintile marks the spatial core. Always set the minimum symbol size to 0.5 mm and scale to 3 mm at maximum, with 30–50% opacity to handle overplotting in dense areas.
Interpretation Guide
Numerical benchmarks
- Closeness (Wasserman–Faust). Values range [0, 1]. >0.6 = highly accessible node — likely the geometric centre, ideal for facilities that serve the entire city. 0.3–0.6 = typical neighbourhood junction. <0.15 = peripheral or isolated node — edges of the network, cul-de-sac terminations. On a global-radius run, the mean closeness in a compact orthogonal grid typically falls in 0.35–0.50; in suburban cul-de-sac subdivisions, it falls to 0.10–0.20 — a factor of ~3 difference in accessibility efficiency.
- Betweenness (raw count). This is the most right-skewed distribution in urban data — the top 1% of nodes often account for 30–50% of all betweenness. Raw counts are not comparable across networks of different sizes; normalise by dividing by $(N-1)(N-2)$ to obtain the probability that a random shortest path passes through the node. A node with normalised betweenness above 0.01 (1% of all paths) is a significant movement corridor; above 0.05 is a structural backbone segment.
- Straightness. Values range [0, 1]. >0.85 = the network radiates from this node nearly as efficiently as the crow flies (typical of nodes at the centre of a perfect grid). 0.6–0.85 = good radial connectivity. 0.4–0.6 = moderate circuitousness. <0.4 = highly circuitous — residents from this node must travel at least 2.5 times the crow-flight distance on average. This is the "cul-de-sac tax" in one number.
- Eigenvector centrality. Values typically range [0, 1] after normalisation by the maximum. Values are on a relative scale within each network — comparisons across networks require a shared normalisation scheme. The top quintile (top 20%) marks the spatial core; the top 5% marks the "core of the core" where the city's most interconnected streets converge.
Spatial pattern reading
- Monocentric city: a single high-closeness peak at the historic centre, with values decaying radially. Betweenness peaks on the radial arterials leading to the centre. This is the classic pre-automobile pattern.
- Polycentric city: multiple high-closeness peaks at sub-centres. Betweenness peaks on the orbital and radial connectors linking them. This pattern emerged with suburbanisation and is the target of most contemporary planning policy (e.g. the "15-minute city" concept).
- Grid city: closeness is broadly uniform across the grid (most nodes have similar access), but betweenness concentrates on a few longest straight avenues. This is a distinctive signature: a grid distributes closeness evenly but concentrates betweenness sharply.
- Dendritic (tree-like) suburb: closeness is low everywhere except the collector road that feeds the arterial. Betweenness concentrates on the single entry/exit point — the entire subdivision's traffic passes through one node, which is both a bottleneck and a single point of failure.
The four-measure matrix
Each measure answers a different planning question, and the four together provide a complete structural diagnosis:
| Measure | Planning question | High = good for | High = bad for |
|---|---|---|---|
| Closeness | "Where is the centre?" | Service siting, emergency response | (no downside — high closeness is always desirable) |
| Betweenness | "Where does movement concentrate?" | Retail, transit corridors, street life | Severance, noise, pollution (when extreme) |
| Straightness | "How direct are routes from here?" | Everywhere — low straightness is a tax on all trips | High straightness on one street at the cost of low everywhere else = severance by design |
| Eigenvector | "Where is the structural core?" | Land value, investment stability | Overconcentration of activity, heat island core |
Cross-references
Cross-reference with Space Syntax: metric betweenness correlates with angular choice (NACH), and metric closeness correlates with angular integration (NAIN). The correlation is typically $r \approx 0.7$–$0.85$ in grid cities, falling to $r \approx 0.5$ in cities with irregular geometry or organic street patterns. Discrepancies between the metric and angular pictures reveal where the geometry of the grid matters beyond simple distance — a long, straight boulevard may score high on metric closeness but low on angular integration if it turns sharply relative to the surrounding grid, forcing large angular costs at its ends.
Feed high-betweenness nodes into Link Criticality as OD origins/destinations to test how vulnerable the network's busiest corridors are. Overlay betweenness on Walkability Audit scores — streets with high betweenness but low walkability are the corridors where pedestrian infrastructure investment yields the highest safety return per metre.
Common misinterpretations
- "Higher centrality = better." Betweenness is a double-edged sword: a street with extremely high betweenness is a movement corridor, but also a severance barrier, a noise corridor, and an air-pollution hotspot. The top 1% of betweenness values often mark streets that need traffic calming or bypass construction, not celebration.
- "Eigenvector centrality replaces the others." Eigenvector centrality captures a different structural property — recursive prestige — that does not substitute for closeness or betweenness. A node can have high eigenvector centrality (connected to well-connected nodes) but low closeness (far from the geometric centre) and low betweenness (few paths pass through it). Each measure must be read separately.
- "Straightness near 1.0 means good connectivity." A node on a straight motorway through empty countryside can have straightness = 1.0 (because the motorway is straight) but low closeness (because there are no other nodes nearby to connect to). Straightness measures route directness, not route availability — always read it together with closeness.
Academic References
Bavelas, A. (1948). "A Mathematical Model for Group Structures." Human Organization, 7(3), 16–30. DOI: 10.17730/humo.7.3.f4033344851gl053
Bonacich, P. (1972). "Factoring and Weighting Approaches to Status Scores and Clique Identification." Journal of Mathematical Sociology, 2(1), 113–120. DOI: 10.1080/0022250X.1972.9989806
Brandes, U. (2001). "A Faster Algorithm for Betweenness Centrality." Journal of Mathematical Sociology, 25(2), 163–177. DOI: 10.1080/0022250X.2001.9990249
Crucitti, P., Latora, V. & Porta, S. (2006). "Centrality in Networks of Urban Streets." Chaos, 16, 015113. DOI: 10.1063/1.2150162
Freeman, L.C. (1977). "A Set of Measures of Centrality Based on Betweenness." Sociometry, 40(1), 35–41. DOI: 10.2307/3033543
Porta, S., Crucitti, P., & Latora, V. (2006). "The Network Analysis of Urban Streets: A Primal Approach." Environment and Planning B: Planning and Design, 33(5), 705–725. DOI: 10.1068/b32045
Sevtsuk, A. & Mekonnen, M. (2012). "Urban Network Analysis: A New Toolbox for ArcGIS." Revue Internationale de Geomatique, 22(2), 287–305. DOI: 10.3166/rig.22.287-305
Wasserman, S. & Faust, K. (1994). Social Network Analysis: Methods and Applications. Cambridge University Press. DOI: 10.1017/CBO9780511815478
Space Syntax (Segment Angular Analysis)
Processing ID: planx:spacesyntax
Overview
Performs segment angular analysis — the modern space syntax workflow — directly on road centreline segments. Unlike traditional axial-map space syntax, this method uses the segment dual graph: each street segment between junctions becomes a node, and connections between segments carry an angular cost equal to the turn angle in degrees divided by 90 (straight = 0, right angle = 1). Shortest paths minimise this angular cost, effectively finding the least-turning routes through the city.
For every specified radius, the tool computes six measures per segment: NC (node count reached), TD (angular total depth), MD (angular mean depth), NAIN (normalised angular integration — to-movement potential), CH (raw angular choice — through-movement count), and NACH (normalised angular choice). The normalised measures follow Hillier, Yang & Turner (2012) and are size-independent, enabling comparison across cities of different sizes.
Theoretical Background
Academic lineage
Space syntax theory, pioneered by Bill Hillier and colleagues at the Bartlett School of Architecture, University College London, since the early 1970s, posits that the spatial configuration of a city — the pattern of connections and barriers in its street network — is the primary generator of movement, land-use patterns, and social encounters. This is the "theory of natural movement" (Hillier et al., 1993): the grid itself, more than any land-use designation or planning policy, determines where people walk, drive, and gather. The founding text, The Social Logic of Space (Hillier & Hanson, 1984), demonstrated that buildings and settlements across cultures and centuries follow configurational rules that are mathematically describable — space is not a neutral container but an active structuring force.
The evolution of the method has three generations. Each generation solved a limitation of the previous one while introducing its own:
- Axial analysis (1970s–1990s). The fewest and longest lines of sight covering all open public space, connected at their intersections. The axial map is the line-of-sight representation: each axial line is a node in the dual graph, and connections carry unit cost. Axial depth — the number of axial steps from one line to another — was the first configurational measure. The method is elegant but suffers from two fundamental problems: it requires subjective judgement in drawing the axial lines (two practitioners drawing the same neighbourhood produce different maps), and it is resolution-dependent — denser areas generate more axial lines, which inflates integration scores, making cross-city comparison impossible.
- Segment angular analysis (Turner, 2001). Rather than
drawing the fewest-and-longest lines, the axial map is broken at every
intersection into segments — the street pieces between
junctions. Connections between segments are weighted by turn angle
divided by 90 degrees, so continuing straight costs 0, a right-angle turn
costs 1, and a U-turn costs 2. Shortest paths minimise this angular cost,
effectively finding the least-turning routes through the
city. This single change:
- Removes subjectivity — the segment map is determined by the geometry of intersections, not a practitioner's judgement,
- Captures the cognitive reality that people prefer straight routes and penalise sharp turns,
- Is resolution-independent — adding intermediate shape points along a straight segment does not change the angular cost,
- Subsumes axial analysis: if every turn costs 1 (regardless of angle), the result is the axial topology; if costs are proportional to turn angle, the result is the more nuanced angular model.
- Normalised measures — NACH and NAIN (Hillier, Yang & Turner, 2012). The raw measures from segment angular analysis — integration (inverse mean depth) and choice (angular betweenness) — are inherently size-dependent. A larger network has more segments, longer paths, and therefore systematically higher choice counts and systematically lower integration values, even if the structural pattern is identical. NACH and NAIN normalise away size by dividing choice and integration respectively by terms derived from the total depth. The constants (exponent 1.2 for NAIN, +1/+3 shift for NACH, +2/+2 for NAIN denominator) were calibrated by Hillier, Yang & Turner (2012) to maximise the correlation with observed pedestrian and vehicular movement rates across 50 cities worldwide. This made NACH and NAIN the first space-syntax measures that could be compared numerically across cities of different sizes — a landmark for quantitative urban morphology.
Key assumptions
- Angular-cost minimisation. The model assumes that route choice is governed by the minimisation of turn-angle cost, not by metric distance, travel time, or number of junctions. Empirical studies consistently find that angular choice correlates with vehicular and pedestrian flows at $r \approx 0.6$–$0.8$, outperforming metric betweenness by 10–20 percentage points. The cognitive basis is that people perceive straight routes as shorter and prefer to minimise the number of direction changes — even when this produces a slightly longer metric path.
- Segment dual graph. The analysis operates on the segment graph, not the primal junction graph. Each street segment between junctions is a node in the dual graph; adjacency is defined by sharing an endpoint. This means the output fields are per segment (line attributes), not per junction (point attributes). Segment-level output is generally more useful than node-level output for planning, because streets (not junctions) are the units of zoning, design, and investment.
- Edge effect. Segments near the edge of the study area have artificially low NACH and NAIN values because the radius "sees" fewer segments beyond the boundary than it would if the network extended further. This is the universal space-syntax edge effect and is not corrected by the tool. The standard mitigation is to include a buffer of at least one radius of extra network around the actual study area — i.e. analyse the city plus a 2 km ring, then clip the result to the city boundary for interpretation. The edge effect is most severe at the global radius ("n") and diminishes at smaller radii.
- Undirected traversal. The segment graph is undirected — turn costs are symmetric (turning left costs the same as turning right at the same angle). For one-way street systems, this means NACH may overestimate through-movement on segments that are one-way in the opposite direction. Filtering by one-way attributes in post-processing is possible but not automated.
- No land-use weighting. The analysis is purely configurational — it measures the potential for movement generated by the grid geometry alone, not the actual movement generated by land uses (a shopping centre on a configurational backwater will still attract people). For combined configurational + attractor-weighted analysis, overlay NACH/NAIN with land-use data and destination counts from the Walkability Audit or Access Score tools.
When to use vs. when NOT to use
Use Space Syntax when: you need the definitive configurational diagnosis of a street network — the structural complement to land-use, density, and demographic analyses; when comparing alternative masterplan layouts (run twice, difference the NACH/NAIN fields); when identifying the foreground movement grid (top 10–20% NACH) and the background residential fabric; when the question is about the spatial logic of the city — why does this street attract pedestrians while its parallel twin two blocks away does not.
Do NOT use when: (a) you need only metric (distance) measures of centrality — use Network Centrality; (b) the street network lacks a prepared topology — segments that cross without a shared node produce a disconnected segment graph, and the output will be nonsensical; always run Prepare Network first; (c) the study area is very small (under 100 segments) — edge effects dominate at this scale, and the NACH/NAIN normalisation was calibrated on city-scale networks of thousands of segments; (d) you are working entirely within a superblock or gated community where movement is constrained by gates and access controls that the configurational model cannot account for.
Mathematical Formulation
Segment dual graph. Given $n$ street segments with
coordinates, the segment graph is built by the engine
(engine/graphs.py). Two segments $(u, v)$ are adjacent if they
share an endpoint. The angular cost of turning from segment $u$ to segment $v$
is:
where $\theta_{uv} \in [0^\circ, 180^\circ]$ is the deflection angle between the last direction vector of $u$ and the first direction vector of $v$ (taking the smaller angle, since the graph is undirected). Internal polyline curvature within each segment is also accumulated — the angular cost along a segment equals the sum of turn angles between its consecutive sub-segments divided by 90°.
Angular shortest paths. For each source segment $s$, a modified Dijkstra algorithm computes the minimum angular-cost path to every other segment $t$ within metric radius $r$ (if specified). The result is the angular distance matrix $d_{ang}(s, t)$.
Angular total depth (TD) and node count (NC):
$$TD(s) = \sum_{t \in V_r(s)} d_{ang}(s, t) \qquad NC(s) = |V_r(s)| \tag{5}$$Angular mean depth (MD):
$$MD(s) = \frac{TD(s)}{\max(NC(s) - 1, 1)} \tag{4}$$Angular choice (CH) — raw betweenness:
$$CH(s) = \sum_{u \neq s \neq v} \frac{\sigma_{uv}^{ang}(s)}{\sigma_{uv}^{ang}} \tag{3}$$where $\sigma_{uv}^{ang}$ is the number of least-angular-cost paths between $u$ and $v$, and $\sigma_{uv}^{ang}(s)$ counts those passing through $s$. Since the graph is undirected, each unordered pair $(u,v)$ is counted twice; the engine divides by 2 to obtain pair-based choice.
NAIN — Normalised Angular INtegration (to-movement potential):
$$NAIN(s) = \frac{(NC(s) + 2)^{1.2}}{TD(s) + 2} \tag{2}$$The constants +2 in numerator and denominator prevent division by zero for isolated segments. The exponent 1.2 was calibrated by Hillier, Yang & Turner (2012) to maximise correlation with observed movement rates across 50 cities. High NAIN = easy to arrive at — the segment is a destination magnet.
NACH — Normalised Angular CHoice (through-movement potential):
$$NACH(s) = \frac{\log_{10}(CH(s) + 1)}{\log_{10}(TD(s) + 3)} \tag{1}$$The constants +1 and +3 keep the ratio real and finite (choice can be zero; total depth is at least 1). High NACH = heavily used as a through route — the segment is in the foreground movement grid.
Both NACH and NAIN are dimensionless and approximately invariant to system size — a segment in a small town and a segment in a metropolis with the same configurational role will have similar NACH/NAIN values.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines (prepared) | Yes | Must be pre-processed with Prepare Network first. Crossing lines must share nodes. Must be in a projected CRS (metres) — radii are measured in map units. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector layer (Line) | — | Street network, output of Prepare Network. Lines must share nodes at intersections or the segment graph will be disconnected. |
RADII | String | "800, n" | Comma-separated metric radii in map units. n (or global, inf) = no radius limit — global analysis. Typical values: 400–800 m (pedestrian/neighbourhood), 1200–2000 m (cycling/district), 5000+ m or n (city-region). Multiple radii let you read the multi-scale structure: a main street that is strong at all radii is resilient; one strong only at 800 m is a neighbourhood centre; one strong only at n is a car-oriented arterial. |
OUTPUT | Vector layer (Line) | — | Street segments with syntax attributes. The output has the original street geometry plus all per-radius fields. |
n) on
networks with more than ~20,000 segments may be slow — the engine issues a
warning. For very large networks, use metric radii or subset the study area.
Always include at least one radius of network beyond your actual study area:
segments near the edge have artificially low values because the radius
"sees" fewer segments than it would if the network extended further. This
edge effect is a universal space-syntax issue — the tool does
not correct for it.Output Description
| Field | Type | Typical Range | Description |
|---|---|---|---|
connectivity | Integer | 1–8 | Number of segments connected to this segment at each endpoint (degree of the segment node in the dual graph). |
Per radius (suffix is the radius label, e.g. _800, _n):
| Field | Type | Typical Range | Description |
|---|---|---|---|
NC_{r} | Double | 1–N | Node count: how many other segments are reachable within this radius. Low NC at small radius = isolated cul-de-sac. |
TD_{r} | Double | ≥0 | Angular total depth: sum of least-turn costs to all reachable segments. Raw diagnostic; prefer MD, NAIN. |
MD_{r} | Double | 0–~10 | Angular mean depth: average angular cost to reachable segments. Low MD = straight, continuous routes radiate from here. |
NAIN_{r} | Double | 0–~2.5 | Normalised Angular INtegration: to-movement potential. High = easy to arrive at — centres, destinations. The city mean is typically 0.4–0.8. |
CH_{r} | Double | 0–~N² | Raw angular choice (pair-based betweenness). Heavy-tailed right skew — map NACH instead. Diagnostic only. |
NACH_{r} | Double | 0–~1.6 | Normalised Angular CHoice: through-movement potential. City mean ~0.7–1.1; max ~1.2–1.6 (Hillier, Yang & Turner 50-city benchmarks). Values above 1.4 are the foreground super-grid. |
Symbolic Representation
NACH and NAIN are the two primary map products.
- NACH map: Graduated renderer, sequential multi-hue (Viridis or Plasma), quantile classification with 7–10 classes. The top 10–20% of values (the foreground) should be visually dominant — thicken these lines to 0.6–0.8 mm; background lines at 0.2 mm. The quantile classification is critical because NACH is still somewhat right-skewed; natural breaks will lump most segments into the bottom class.
- NAIN map: Same approach, but use a warm sequential ramp (OrRd or YlOrRd) — integration reads as "heat" (activity concentration). The top 10% are the city's cores; expect them to align with historic centres and high streets.
- Joint NACH+NAIN interpretation map: Bivariate colour scheme — or, more practically, two side-by-side map panels with synchronised extents. QGIS map themes make this straightforward.
- Legend format: Two decimal places (e.g. "0.95 – 1.12"). Do not include unit symbols — NACH and NAIN are dimensionless.
- Scale dependency: Show the full network at city scale; at neighbourhood scale (1:5,000–1:10,000), filter to the top 50% of NACH to declutter.
Interpretation Guide
The dual reading: NACH × NAIN
The real power of space syntax lies in reading NACH and NAIN together on the same segment. The cross-classification yields four urban typologies:
| High NAIN (easy to arrive) | Low NAIN (hard to reach) | |
|---|---|---|
| High NACH (heavy through-movement) |
Live high street — the city's signature mixed-use corridor. People pass through AND stop. Retail, restaurants, street life. Planning action: protect and enhance the public realm; widen footpaths; restrict cars at peak pedestrian hours. | Pass-through corridor — a movement channel that nobody uses as a destination. Traffic pressure, severance risk, noise, poor air quality. Often a major arterial or ring road. Planning action: add pedestrian crossings; plant street trees; rezone adjacent parcels for active frontage to convert it toward a live street over time. |
| Low NACH (light through-movement) |
Calm local centre — a neighbourhood square, local high street, or community hub. Easy to reach but only by those who intend to. Planning action: preserve the intimate scale; add seating and planting; resist chain retail that would drive up NACH and erode the calm. | Residential background / enclave — the quiet fabric where people live. This is the city's largest spatial type by length. Planning action: monitor NAIN — if it stays low at every radius, the neighbourhood is an enclave and needs better connections to the surrounding grid; if NAIN rises at larger radii, it is locally quiet but regionally accessible — a desirable balance. |
Multi-radius reading
Run at least three radii (e.g. 400, 1200, n) and compare the
same segment across radii:
- Strong at all radii = a resilient main street — the urban spine. Rare and valuable.
- Strong only at small radius (400–800) = a neighbourhood centre — locally important but not part of the city-scale structure.
- Strong only at large radius (
n) = a car-oriented arterial — functions as a regional connector but has no local centre quality. - Weak at all radii = isolated fabric — potentially an enclave. Check whether this is deliberate (gated community) or problematic (neglected social housing estate).
Masterplan evaluation
Run Space Syntax twice — once on the existing network, once on the proposed masterplan network — and compute the difference in NACH and NAIN per segment (or per spatial unit). Segments whose NAIN rises significantly are winners — the masterplan connects them. Segments whose NAIN drops are losers — the masterplan severs or bypasses them. A quarter whose NAIN stays low at every radius in the proposed network will persist as an enclave regardless of land-use mix or density — the spatial configuration itself prevents integration.
Benchmarks from the 50-city study
Hillier, Yang & Turner (2012) established these approximate ranges from their analysis of 50 urban systems worldwide:
| Metric | Low | Typical | High |
|---|---|---|---|
| City-mean NACH | ~0.7 (disconnected sprawl) | ~0.85–1.0 | ~1.1 (dense orthogonal grid) |
| Maximum NACH | ~1.2 | ~1.4 | ~1.6 (super-grid arteries) |
| Mean NAIN | ~0.3 | ~0.5–0.7 | ~0.9 |
Your city's values will differ — these are comparative benchmarks, not normative targets. An organic medieval centre and a planned modernist grid can both be excellent places to live despite very different scores.
Academic References
Hillier, B. & Hanson, J. (1984). The Social Logic of Space. Cambridge University Press. DOI: 10.1017/CBO9780511597237
Hillier, B., Penn, A., Hanson, J., Grajewski, T., & Xu, J. (1993). "Natural Movement: Or, Configuration and Attraction in Urban Pedestrian Movement." Environment and Planning B: Planning and Design, 20(1), 29–66. DOI: 10.1068/b200029
Turner, A. (2001). "Angular Analysis." In: Peponis, J., Wineman, J. & Bafna, S. (eds.), Proceedings of the 3rd International Space Syntax Symposium, Atlanta, GA, pp. 30.1–30.11. conference proceedings] Available at: UCL Discovery
Hillier, B. & Iida, S. (2005). "Network and Psychological Effects in Urban Movement." In: Cohn, A.G. & Mark, D.M. (eds.), Spatial Information Theory (COSIT 2005), LNCS 3693, pp. 475–490. Springer. DOI: 10.1007/11556114_30
Crucitti, P., Latora, V. & Porta, S. (2006). "Centrality Measures in Spatial Networks of Urban Streets." Physical Review E, 73, 036125. DOI: 10.1103/PhysRevE.73.036125
Porta, S., Crucitti, P. & Latora, V. (2006). "The Network Analysis of Urban Streets: A Dual Approach." Physica A, 369(2), 853–866. DOI: 10.1016/j.physa.2005.12.063
Hillier, B., Yang, T., & Turner, A. (2012). "Normalising Least Angle Choice in Depthmap — and How It Opens Up New Perspectives on the Global and Local Analysis of City Space." Journal of Space Syntax, 3(2), 155–193. journal does not assign DOIs] Available at: UCL Discovery
OD Cost Matrix
Processing ID: planx:odmatrix
Overview
Computes the full origin–destination cost matrix over the street network using the embedded Dijkstra engine — no external routing plugin or server. For every origin–destination pair, it reports the shortest-path network cost, the straight-line (Euclidean) distance, and the detour ratio (network ÷ Euclidean). Optional desire lines render the matrix as straight-line glyphs styled by cost or detour.
This is the foundational input for gravity models, accessibility studies, facility siting, and any analysis that needs to know "how far is A from B on the real network."
Theoretical Background
Academic lineage
The OD cost matrix is the most basic product of a transportation network model: it answers the question "how far apart are these places?" for every pair of interest. The concept originates in traffic analysis zone (TAZ) planning, formalised during the post-war boom in urban transportation modelling. The landmark Chicago Area Transportation Study (CATS, 1955–1962) established the four-step travel-demand model (trip generation, distribution, modal split, assignment) that remains the framework for metropolitan transport planning worldwide. The OD cost matrix feeds the distribution step — trip distribution models (gravity, intervening opportunities, and later entropy-maximising and logit-based formulations) all require a cost or impedance matrix as their primary input (Ortuzar & Willumsen, 2011). Wilson's (1967) entropy-maximising derivation of the doubly-constrained gravity model was a theoretical breakthrough, showing that the gravity model is the most probable trip distribution consistent with known constraints — not merely an analogy to Newtonian physics.
In GIS, the OD cost matrix was for many years computed by external routing
engines (ESRI Network Analyst, pgRouting, Google Distance Matrix API). PlanX
brings this capability inside QGIS using the same Dijkstra engine that powers
all other network tools. The many-to-many shortest-path
computation runs one Dijkstra tree per origin, reusing the tree to reach all
destinations simultaneously — far more efficient than running Dijkstra once per
OD pair. This exact approach is implemented in the engine's
many_to_many kernel (see engine/paths.py), which
passes the CSR adjacency directly to SciPy's csgraph.dijkstra when
available and falls back to a pure-Python heapq implementation
otherwise, with identical results verified by unit tests.
Key assumptions
- Shortest-path behaviour. The OD matrix assumes travellers always choose the shortest-path (least-cost) route. This is a reasonable approximation for walking and cycling where distance minimisation dominates, but it systematically underestimates the diversity of vehicular routes — drivers trade off distance against congestion, signal count, and road class. For multi-criteria routing, the OD Routes tool with reconstructed geometry allows post-hoc inspection of which paths Dijkstra actually chose.
- Snapping fidelity. Each origin and destination snaps to its nearest network node. For a point 50 m inside a park, the nearest node may be 50 m away on a perimeter road — the route cost includes that 50 m snap distance. If the snap point lies on a different street than the one you intended (e.g. a building centroid snaps to a rear alley instead of the front street), the OD row will be misleadingly long. Always inspect a few snap points visually before trusting the matrix.
- Additive costs. The cost field must be additive per segment — a sum, not an average or a rate. Speed (km/h) must be pre-converted to travel time = length / speed. NULL costs are treated as zero (free segment), which can produce unrealistically short routes if cost data is incomplete.
- Unreachable pairs. Pairs where the destination is disconnected from the origin (no path in the graph, or the shortest path exceeds the cutoff) are absent from the output, not reported with a sentinel value. This is deliberate: counting absent rows per origin is the quickest way to identify disconnected pockets in the network.
When to use vs. when NOT to use
Use OD Cost Matrix when: you need a complete pairwise impedance matrix for gravity models, accessibility indices, facility location optimisation, or statistical analysis of travel costs. The detour ratio makes it a powerful barrier-effect screening tool — the OD pair with the highest detour ratio often pinpoints the single best location for a new bridge or street link.
Do NOT use when: (a) you need actual route geometries —
use OD Routes instead; (b) you are computing a single
origin's catchment — use Service Areas which
provides partial-edge trimming and pedshed ratios; (c) you need
assignment-aware routing (each traveller affects congestion) — this requires
an iterative traffic-assignment model, which PlanX does not provide; (d) the
OD set is very large (thousands of origins x thousands of destinations) with
no cutoff — the output table grows as $O(m \cdot n)$ and will overwhelm QGIS.
Always set a CUTOFF for large OD sets, or aggregate origins and
destinations to zone centroids first.
Mathematical Formulation
Network cost. For each origin $i$ and destination $j$, the engine computes the shortest-path distance $d_{net}(i,j)$ by Dijkstra's algorithm on the primal graph $G = (V, E)$ with edge weights $w(e)$ (geometric length or a user-specified additive cost field). Each origin snap point is mapped to its nearest network node $n_i^O$; similarly each destination snap point maps to $n_j^D$. The many-to-many kernel then runs Dijkstra from each unique origin node, producing a full shortest-path tree per origin:
$$d_{net}(i,j) = \min_{\text{path}(n_i^O \to n_j^D)} \sum_{e \in \text{path}} w(e) \tag{4}$$The engine adds the straight-line snap distance $d_{snap}$ from the original point coordinates to the network node, so the total cost from origin geometry to destination geometry is:
$$D_{ij} = d_{snap}(O_i \to n_i^O) + d_{net}(n_i^O, n_j^D) + d_{snap}(n_j^D \to D_j) \tag{3}$$Euclidean distance (as the crow flies) between the original point coordinates:
$$d_{euc}(i,j) = \sqrt{(x_i - x_j)^2 + (y_i - y_j)^2} \tag{2}$$Detour ratio: the dimensionless measure of how much farther the network forces travel compared to the straight line:
$$detour(i,j) = \frac{D_{ij}}{d_{euc}(i,j)} \tag{1}$$Many-to-many computational kernel. The engine function
paths.many_to_many(indptr, adj, weights, n, sources, cutoff)
implements the computation. For each source node $s$, it runs a single Dijkstra
pass that computes distances to all $n$ nodes. For $m$ unique origin nodes, the
cost is $O(m \cdot (n \log n + e))$ in the SciPy fast path and
$O(m \cdot (n \log n + e))$ in the heapq fallback — the difference is a
constant factor (~5-10x), not the asymptotic complexity. The cutoff parameter
prunes the search: expansion stops when the cumulative cost exceeds the cutoff,
which both accelerates the computation and limits memory use for large networks.
All-pairs special case. When no separate destination layer is provided, the origins also serve as destinations. Self-pairs $(i, i)$ are automatically excluded (a point's distance to itself is not meaningful for gravity models and would introduce a zero diagonal that biases calibration).
Unreachable handling. A destination $j$ is unreachable from origin $i$ if: (a) the source and destination nodes belong to different connected components of the graph, or (b) the shortest path exceeds the cutoff and expansion was pruned. In either case, the pair is not included in the output — the matrix is sparse by design, containing only reachable pairs within the cutoff. The count of missing pairs per origin is a direct measure of network fragmentation.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Prepared network recommended. Projected CRS (metres). |
| Origins | Vector (any geometry) | Yes | Point/centroid locations. Each snaps to nearest network node. |
| Destinations | Vector (any geometry) | No | If empty, origins serve as destinations (all-pairs among origins). |
| Cost field | Numeric field | No | Must be additive per segment (travel time, not speed). NULL = 0 = free segment. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. Prepared network recommended. |
ORIGINS | Vector (Any) | — | Origin features. Use population centroids, building points, or zone centres. |
ORIGIN_ID | Field | — | Field uniquely identifying each origin (appears in output as origin_id). |
DESTINATIONS | Vector (Any) | (optional) | Destination features. Leave empty to compute all pairs among origins. |
DEST_ID | Field | (optional) | Field identifying each destination. Falls back to origin ID field. |
COST_FIELD | Field (Numeric) | (empty = length) | Additive per-segment cost column. Use a time field (minutes) for travel-time matrices. Must be ≥ 0 and complete. |
CUTOFF | Double | 0 (unlimited) | Maximum cost; pairs exceeding this are excluded. 0 = no limit. Essential for large OD sets to keep output manageable. |
MATRIX | Table output | — | OD matrix table (no geometry). |
LINES | Vector (Line) | (optional) | Straight desire lines between OD pairs. Useful for visualisation. |
Output Description
| Field | Type | Description |
|---|---|---|
origin_id | String | Origin identifier from the ID field |
dest_id | String | Destination identifier |
net_cost | Double | Shortest-path cost (metres, or cost-field units). The operative number. |
euclid_m | Double | Straight-line distance in metres |
detour | Double | Network ÷ Euclidean ratio. ~1.0–1.2 direct; ≥1.4 = major barrier. Only meaningful with length cost (not time). |
Symbolic Representation
Desire lines styled by detour ratio with a diverging colour
ramp (RdYlGn, reversed: green = direct, red = circuitous) and natural-breaks
classification (5 classes) produce the most immediately informative map. Style
by net_cost with a sequential ramp (Viridis) for a raw-distance
view. Line width proportional to the inverse of detour (thick = efficient
connections). At city scale, set line opacity to 20–30% to prevent
overplotting.
Interpretation Guide
Numerical benchmarks
- detour < 1.15: the network is highly efficient for this pair — the route is nearly as direct as the crow flies. Typical of orthogonal grid streets within the same neighbourhood.
- detour 1.15–1.35: normal urban fabric — the route takes a few turns but no major detour. This is the expected range for most intra-city pairs in well-connected grids.
- detour 1.35–1.60: moderate barrier effect — a river bend, a railway line, a superblock perimeter, or a missing street link forces a noticeable detour. Target these pairs for connectivity interventions.
- detour > 1.60: severe barrier — the network forces a route more than 60% longer than the crow flies. This almost always indicates a physical barrier (river with few crossings, motorway with no pedestrian underpass) or a topological dead-end (cul-de-sac subdivision where the only exit is far from the destination). The single pair with the highest detour in a study area typically pinpoints the most cost-effective new link.
- Missing pairs per origin: 0 = fully connected within cutoff; 1–5 = minor gaps (isolated cul-de-sacs, edge effects); >10 = significant disconnection — check whether this origin is physically separated (island, gated community, or disconnected component in the graph).
Spatial pattern reading
Visualise the matrix as a desire-line map: each OD pair is a straight line coloured by detour ratio. The spatial pattern reveals:
- Radial convergence: many lines radiating from outlying origins toward a central destination cluster — classic monocentric city pattern. The detour on radial lines is typically low (grids are efficient at radiating); the detour on orbital lines (origin-to-origin) is typically higher, revealing the missing orbital connectivity that a circumferential transit line would serve.
- Barrier shadows: a band of high-detour lines all crossing the same geographic corridor — this is the shadow cast by a linear barrier (river, motorway, railway). Count the number of crossing points in that corridor — if there is only one bridge every 800 m, each additional bridge reduces the detour bill for thousands of OD pairs.
- Isolated clusters: a group of origins whose lines to destinations are all absent or all high-detour — these origins belong to a disconnected or poorly connected component. Check whether a single missing link (one street segment) would connect the cluster to the main graph.
Cross-references
The OD cost matrix is the primary impedance input for the
Gravity Distribution model (the $c_{ij}$ term in the
gravity formula), for the Mode Split tool's distance
decay functions, and for any Location-Allocation analysis where
a precomputed cost matrix avoids repeated routing. The net_cost
values can also be used as a standalone accessibility indicator: the mean
net_cost to a category of destinations (e.g. all hospitals) is a
simpler but coarser alternative to the Multi-Amenity
Access Score for single-category access studies.
Common misinterpretations
- "A detour ratio below 1.0 is impossible." True — but floating-point noise can produce ratios of 0.999... for very short segments where the snap distance adds to the Euclidean too. These are not bugs.
- "The detour ratio is comparable across different cost types."
The detour ratio is only geometrically meaningful when cost = length (metres).
When cost = time, the denominator is still in metres but the numerator is in
minutes, making the ratio dimensionally inconsistent. For time-based matrices,
use
net_costdirectly and compare to a time threshold, not a detour ratio. - "All pairs matter equally." The OD matrix gives each pair equal weight, but in planning some pairs matter vastly more than others. Weight pairs by population at origin x employment at destination, or filter to the pairs relevant to your policy question (e.g. children to schools, elderly to clinics), before ranking detour ratios.
Academic References
Ortuzar, J. de D. & Willumsen, L.G. (2011). Modelling Transport. 4th ed., Wiley. DOI: 10.1002/9781119993308
Dijkstra, E.W. (1959). "A Note on Two Problems in Connexion with Graphs." Numerische Mathematik, 1(1), 269–271. DOI: 10.1007/BF01386390
Wilson, A.G. (1967). "A Statistical Theory of Spatial Distribution Models." Transportation Research, 1(3), 253–269. DOI: 10.1016/0041-1647(67)90035-4
Rodrigue, J.-P., Comtois, C. & Slack, B. (2017). The Geography of Transport Systems. 4th ed., Routledge. textbook, no DOI assigned] Available at: transportgeography.org
OD Routes (Shortest Paths)
Processing ID: planx:odroutes
Overview
Computes actual shortest-path route geometries over the street network from origins to destinations. Unlike the OD Cost Matrix (which returns only costs), this tool reconstructs the precise sequence of street segments traversed — turn by turn — for every origin–destination pair. Each route includes the network cost, Euclidean distance, detour ratio, and the number of edges traversed. Optional straight desire lines complement the route geometries.
The tool supports k-nearest destination filtering and a cost cutoff to keep output manageable for large OD sets.
Theoretical Background
Academic lineage
Route reconstruction from a shortest-path tree is the standard
predecessor-tracking technique — a natural extension of
Dijkstra's algorithm (1959) and an integral part of every routing engine since
the first in-vehicle navigation systems of the 1980s. During Dijkstra's
algorithm, each node records which predecessor node and which edge were used to
reach it with the minimum cost. After the tree is built, a path from source
$s$ to target $t$ is reconstructed by walking backwards from $t$ through the
predecessor chain to $s$, collecting the edge IDs along the way. The PlanX
implementation uses the shortest_path_tree kernel in
engine/paths.py, which is deliberately a pure-Python heapq
implementation — the SciPy accelerated kernel cannot track which specific
parallel edge was taken, so predecessor tracking uses the guarantee of
identical distances but with full edge-identity preservation.
The route-reconstruction problem gains practical significance at urban scale because of parallel edges — dual carriageways, service roads, and slip lanes that share the same endpoint pair $(u, v)$ but have different geometry, different names, and different attributes. A Dijkstra implementation that only records predecessor nodes cannot distinguish which parallel edge was traversed; one that records predecessor edges can. The PlanX engine records both, ensuring that every reconstructed route follows the exact geometry of the streets it traverses.
Key assumptions
- Unique shortest-path resolution. When multiple paths have identical cost (a tie), Dijkstra's relaxation rule resolves deterministically: a strictly lower cost replaces the predecessor; an equal cost does not. This means the first-discovered path of minimum cost wins. The choice is deterministic but not necessarily the path a person would choose — between two equal-cost routes, a person might prefer the one with fewer turns, better scenery, or less traffic, none of which the cost field captures.
- Edge geometry orientation. Edges in the graph have no inherent direction — they are undirected. During route assembly, the polyline of each edge is oriented so its first coordinate is closest to the previous edge's last coordinate, producing a contiguous linestring. If the edge's native coordinate order opposes the travel direction, the full polyline is reversed. This orientation logic is geometric (based on endpoint proximity), not topological (based on the graph edge direction).
- k-nearest stability. The k-nearest filter sorts
destinations by
net_costand keeps the $k$ smallest. Ties (equal cost) are broken by the destination's row index in the input layer — not by any spatial or attribute criterion. This is deterministic but may produce counter-intuitive results when two destinations are equidistant: the one listed first in the attribute table always wins. For human-interpretable results, ensure that destination IDs are ordered meaningfully (e.g. facility priority order) before analysis.
When to use vs. when NOT to use
Use OD Routes when: you need the actual street-level itinerary, not just the cost; when visualising movement corridors through route bundling; when k=1 routing to the nearest facility with full path geometry (functionally equivalent to Nearest Facility with routes enabled); when the analysis requires turn-by-turn inspection of which specific streets a trip uses.
Do NOT use when: (a) you need only the cost matrix without geometry — use OD Cost Matrix which is faster and produces a smaller output; (b) the OD set is very large (thousands of pairs) without a cutoff — each route is a multi-segment linestring that bloats the output; (c) k-nearest is set to a large value — for k >= 10, the route count per origin explodes and the map becomes unreadable.
Mathematical Formulation
Shortest-path tree. For each origin $s$, Dijkstra's algorithm computes:
- $dist[t]$ — minimum cost from $s$ to every node $t$
- $pred\_node[t]$ — the predecessor node on the shortest path to $t$
- $pred\_edge[t]$ — the edge ID connecting $pred\_node[t]$ to $t$
Path reconstruction. Starting from target node $t$:
- Push edge $pred\_edge[t]$ onto the edge list
- Set $t \leftarrow pred\_node[t]$
- Repeat until $t = s$ (source reached) or predecessor is invalid
- Reverse the edge list to obtain travel order from origin to destination
Route geometry assembly. For each edge in the ordered list, the polyline coordinates are oriented so the first vertex is closest to the current position. Consecutive edges share the junction node, producing a contiguous linestring.
$$length\_m = \sum_{e \in route} \ell_e \tag{1}$$Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Prepared network recommended. Projected CRS. |
| Origins | Vector (any) | Yes | Origin locations snapped to nearest network node. |
| Destinations | Vector (any) | No | Empty = origins serve as destinations. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. |
ORIGINS | Vector (Any) | — | Origin features with ID field. |
ORIGIN_ID | Field | — | Unique identifier for each origin. |
DESTINATIONS | Vector (Any) | (optional) | Destination features. Leave empty for all-pairs among origins. |
DEST_ID | Field | (optional) | Destination ID field. |
COST_FIELD | Field (Numeric) | (empty = length) | Additive per-segment cost. Use time_min for slope-aware routing. |
CUTOFF | Double | 0 (unlimited) | Maximum route cost. Essential for large networks. |
K_NEAREST | Integer | 0 (all) | Keep only the k nearest destinations per origin. k=1 = nearest-service routes. |
OUT_ROUTES | Vector (Line) | — | Reconstructed street-level routes. |
OUT_LINES | Vector (Line) | (optional) | Straight desire lines for OD visualisation. |
Output Description
| Field | Type | Description |
|---|---|---|
origin_id | String | Origin identifier |
dest_id | String | Destination identifier |
k | Integer | Rank of this destination for this origin (1 = nearest, 2 = second-nearest, …) |
net_cost | Double | Shortest-path cost along the route |
euclid_m | Double | Straight-line distance in metres |
detour | Double | Network ÷ Euclidean ratio |
n_edges | Integer | Number of street segments in the route |
Symbolic Representation
Route geometries styled by flow bundling (overlaying many
routes at low opacity, 15–30%) reveal the de-facto movement corridors — the
demand-side complement to betweenness centrality. Use a sequential ramp
(Viridis) on net_cost for a time/distance view. For k=1 output,
style by dest_id as a categorical renderer to see de-facto
catchment boundaries (the nearest-destination Voronoi equivalent on the
network). Route line width 0.3–0.5 mm with 20% opacity works well for
bundling.
Interpretation Guide
- Route bundles that converge on a narrow set of streets reveal the corridors where most trips concentrate — these are your priority sidewalk, cycle, and transit corridors.
- Overlay route flows with Cycling Stress or Walkability Audit scores to target safety improvements on the streets that people actually use.
- Setting k=1 yields assignment-like nearest-service routes, functionally equivalent to Nearest Facility but with full path geometry.
- Long detour routes (detour ≥ 1.5) visualise the barrier effect — the actual path people are forced to take around a river, rail line, or superblock.
- Feed
net_costinto Gravity Model or Mode Split as the impedance matrix.
Academic References
Dijkstra, E.W. (1959). "A Note on Two Problems in Connexion with Graphs." Numerische Mathematik, 1(1), 269–271. DOI: 10.1007/BF01386390
Bast, H., Delling, D., Goldberg, A., Muller-Hannemann, M., Pajor, T., Sanders, P., Wagner, D. & Werneck, R.F. (2016). "Route Planning in Transportation Networks." In: Kliemann, L. & Sanders, P. (eds.), Algorithm Engineering, LNCS 9220, pp. 19–80. Springer. DOI: 10.1007/978-3-319-49487-6_2
Service Areas (Isochrones)
Processing ID: planx:serviceareas
Overview
Computes true network catchments around facilities with exact partial-edge reach: walking budgets end mid-street, so streets are trimmed at the precise point where the cost budget runs out. For each break distance, the tool produces trimmed street pieces (coloured by cost band), service area polygons (buffer, concave hull, or convex hull), and straight-line circles for comparison. The pedshed ratio (network catchment area ÷ circle area) is the classic measure of how much the street layout shrinks the reach promised by a given radius.
Theoretical Background
Academic lineage
Service area (isochrone) analysis is the spatial implementation of catchment-based planning standards: a regulation states that every residence must be within 500 m of a park, 800 m of a primary school, or 400 m of a bus stop. The straight-line (crow-flies) buffer that most GIS users draw to check compliance is systematically optimistic — it ignores the street network entirely. The systematic error was first quantified by Porta & Renne (2005), who introduced the pedshed ratio (catchment area divided by circle area) as a network-efficiency metric for walkability assessment. The concept was further formalised by Curtin (2007), who demonstrated that the network buffer — trimming streets at the exact budget point rather than at the nearest junction — is not a cosmetic refinement but a quantitative necessity at walking-scale budgets (below approximately 1,500 m).
The computational approach — multi-source Dijkstra — builds on the observation that labelling every reachable point with its nearest facility is mathematically equivalent to inserting a virtual super-source node connected to all facility entry points with zero-cost edges. This was first described for GIS by Dreyfus (1969) as an extension of Dijkstra's algorithm and became the standard approach with the rise of desktop GIS in the 1990s. PlanX's implementation extends this with partial-edge trimming: after the per-node costs are known, each edge is tested for partial reachability between its endpoints. For an edge $(u, v)$ where $d_u \leq B < d_v$, the reachable portion is the fraction $(B - d_u) / (d_v - d_u)$ of the edge length from $u$. This eliminates the block-length quantisation error that node-only isochrones suffer from.
Key assumptions
- Nearest-facility wins. In merged mode, each point on the network is assigned to the facility with the lowest cost. In per-facility mode, each facility's catchment is computed independently and may overlap. A point at equal cost from two facilities is assigned to the first one in the input order — this is deterministic but may split a street arbitrarily if two facilities are equidistant.
- Cost fidelity at small budgets. For budgets below 200 m, the snap distance from the facility point to the nearest point on the network may be a significant fraction of the total budget — a facility 30 m from the road in a 200 m catchment spends 15% of its budget just reaching the road. The tool includes the snap distance in the cost, so this is correctly accounted for, but the morphology of the catchment may be dominated by the snap geometry. For small-budget analysis, digitise facility points precisely on the network.
- Polygon method trade-off. The three polygon methods (Street Buffer, Concave Hull, Convex Hull) represent a trade-off between cartographic precision and interpretability. Street Buffer produces the most accurate representation (the envelope of trimmed street pieces) but yields complex, irregular polygons that look unfamiliar. Concave Hull produces the familiar "isochrone blob" aesthetic but may fill large areas that are genuinely unreachable (e.g. a park with no paths). Convex Hull is the fastest and most generous — it always overestimates, but provides a conservative upper bound for compliance checking ("if the convex hull misses it, the network certainly does").
When to use vs. when NOT to use
Use Service Areas when: auditing compliance with distance-based planning standards; visualising the reach of a proposed facility site; computing the pedshed ratio as a network-efficiency indicator; producing masterplan exhibits with clear "served" vs. "unserved" delineation.
Do NOT use when: (a) you need demand-weighted allocation counts — use Nearest Facility instead; (b) the question is about the fastest (time-based) route rather than the shortest distance — use a time cost field from Walking Slope Comfort; (c) the radius is very large (over 5000 m) — the polygon may cover most of the study area and the pedshed ratio approaches 1.0 regardless of network quality, making it non-diagnostic; (d) you need individual routes for every origin-destination pair — use OD Routes.
Mathematical Formulation
Multi-source Dijkstra with entry costs. Each facility $f$ enters the network at its nearest point on the nearest edge $(e_f, t_f)$ where $t_f \in [0,1]$ is the position along the edge. Two node-offset entries are created for the edge's endpoints with the approach cost added:
$$cost_{entry}(a) = d_{snap} + t_f \cdot \ell_{e_f} \tag{4}$$ $$cost_{entry}(b) = d_{snap} + (1 - t_f) \cdot \ell_{e_f} \tag{3}$$where $d_{snap}$ is the straight-line snap distance (added to the budget when cost is length). Dijkstra runs once from all facility entries simultaneously, producing per-node costs and winning-facility labels.
Partial-edge reach intervals. For an edge $(u, v)$ with cost $\ell$ and node costs $d_u, d_v$, the reachable portion within budget $B$ is the interval $[t_{min}, t_{max}]$ where the interpolated cost at position $t$ is ≤ $B$:
$$cost(t) = \min(d_u + t\ell,\; d_v + (1-t)\ell) \leq B \tag{2}$$Pedshed ratio:
$$pedshed = \frac{A_{catchment}}{A_{circle}} = \frac{\text{network catchment area}}{\pi \cdot B^2} \tag{1}$$Pedshed ≥ 0.6 = well-connected grid; 0.4–0.6 = average; < 0.4 = poor — the network delivers less than half the promised radius.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Prepared network required. Projected CRS. |
| Facilities | Vector (any) | Yes | Facility point locations. Each snaps to nearest point on nearest edge. |
| Cost field | Numeric field | No | Additive per-segment cost for time-based catchments. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Prepared street network. |
FACILITIES | Vector (Any) | — | Facility locations. Use school points, park entrances, transit stops. |
FACILITY_ID | Field | (optional) | Label field for per-facility output. Without it, facilities are numbered. |
COST_FIELD | Field (Numeric) | (empty = length) | Use for time-based catchments (minutes). When cost ≠ length, circles read breaks as map-unit radii and pedshed mixes units. |
BREAKS | String | "250, 500, 1000" | Comma-separated distances/costs. Multiple breaks produce nested bands. Standard walking: 250, 500, 1000 m. |
COMBINE | Enum | Merged only | "Merged only" = one combined catchment (nearest facility wins). "Per facility + merged" adds individual facility catchments. |
METHOD | Enum | Street buffer | Polygon method: Street buffer (hugs network, cartographic precision); Concave hull (familiar isochrone blob); Convex hull (fastest, most generous). |
BUFFER | Double | 30.0 | Street buffer width in map units. Wider = smoother but less precise at corners. |
HULL_DETAIL | Double | 0.3 | Concave hull tightness: 0 = tightest (follows streets), 1 = convex. Only used with Concave hull method. |
RINGS | Boolean | False | If true, outputs difference rings (outer band minus inner) for clean band cartography. |
EDGES | Vector (Line) | — | Reached streets trimmed and coloured by cost band. |
AREAS | Vector (Polygon) | — | Service area polygons (catchment geometry). |
CIRCLES | Vector (Polygon) | — | Straight-line catchments (circles of break radius) for comparison. |
SUMMARY | Table | — | Pedshed summary with circle area, network area, ratio, and reached street length per break per facility. |
Output Description
| Output | Key Fields | Description |
|---|---|---|
| Edges | facility, band, cost_from, len_m | Street pieces trimmed at budget. band = break value; len_m = actual piece length. |
| Areas | facility, break, rank, area | Catchment polygons. rank = break index (1 = smallest). |
| Circles | facility, break, area | Straight-line circles of radius = break. |
| Summary | facility, break, circle_area, net_area, pedshed, street_len | pedshed = net_area / circle_area. street_len = total reached street length. |
Symbolic Representation
Overlay Circles (hollow, dashed outline, 0.5 mm stroke) on
top of Areas (solid fill, 30–40% opacity, sequential colour by
break). The gaps between circle and area are the visual story — they show
exactly where the paper radius fails on the ground. This is the single
strongest exhibit for a standards review. Use blue for circles and warm
colours (OrRd) for catchments to emphasise the deficit. For the edges output,
colour by band with a sequential ramp for a served-street map.
The summary table's pedshed column ranks facilities by catchment
efficiency — style as a bar chart in the QGIS layout.
Interpretation Guide
- Pedshed ≥ 0.6: well-connected, walkable grid — the network delivers most of the promised reach.
- Pedshed 0.4–0.6: average urban fabric — some severance. Target the gaps for new street connections.
- Pedshed < 0.4: poor — the network delivers less than half the radius. The gaps between circle and catchment are streets that look close but are unreachable. These gaps pinpoint where pedestrian bridges, underpasses, or street links are most needed.
- Per-facility comparison: facilities with the lowest pedshed ratios at the same break are the best candidates for access-improvement interventions. Rerun with a proposed link added and compare pedshed gains to build the business case.
- Use Rings mode for clean band cartography in master-plan exhibits — each band is a distinct colour with no overlap.
Academic References
Curtin, K.M. (2007). "Network Analysis in Geographic Information Science: Review, Assessment, and Projections." Cartography and Geographic Information Science, 34(2), 103–111. DOI: 10.1559/152304007781002163
Porta, S. & Renne, J.L. (2005). "Linking Urban Design to Sustainability: Formal Indicators of Social Urban Sustainability Field Research in Perth, Western Australia." Urban Design International, 10, 51–64. DOI: 10.1057/palgrave.udi.9000136
Handy, S.L. & Niemeier, D.A. (1997). "Measuring Accessibility: An Exploration of Issues and Alternatives." Environment and Planning A, 29(7), 1175–1194. DOI: 10.1068/a291175
Nearest Facility Allocation
Processing ID: planx:nearestfacility
Overview
Assigns every demand point (building, household, parcel centroid) to its nearest facility over the street network and reports each facility's total load. A single multi-source Dijkstra run resolves all assignments at once — every demand point is simultaneously claimed by its closest facility. Outputs include the allocated demand layer (with assigned facility label and network cost), optional spider/allocation lines, reconstructed network-path routes, and a per-facility load summary with demand count, mean cost, and maximum cost.
Theoretical Background
Academic lineage
Nearest-facility allocation solves the Voronoi problem on a network: instead of partitioning space into Euclidean regions (as a standard Thiessen/Voronoi diagram would), it partitions it by shortest-path distance. The concept extends the classical planar Voronoi diagram (Dirichlet, 1850; Voronoi, 1908) to graphs, where the "distance" is the shortest-path cost on the network rather than the Euclidean norm. The de-facto catchment boundaries — the lines where the nearest facility changes — rarely align with administrative boundaries, census tracts, or straight-line catchment circles. This is the fundamental insight of network-based accessibility planning: the street network, not the radius, determines who goes where (Talen & Anselin, 1998).
The computational technique — multi-source Dijkstra — was first described
by Dreyfus (1969) as an extension of Dijkstra's algorithm: insert a virtual
super-source node connected to all facility nodes with zero-cost edges, then
run a single Dijkstra pass. All reachable nodes are labelled with the facility
that first reached them (the one with the minimum cost). The implementation
in engine/paths.py as multi_source uses a
priority-queue initialised with all facility nodes at cost zero, each carrying
its facility label. The relaxation rule is strict improvement
only: if two facilities reach a node at exactly equal cost, the one
already settled keeps it — the assignment is deterministic but the
first-settled bias favours facilities appearing earlier in the input order.
The approach is $O((n + f) \log n + e)$ where $f$ is the number of facilities — a single Dijkstra pass replaces $f$ independent single-source passes. This makes nearest-facility allocation dramatically cheaper than OD routing: assigning 5,000 demand points to 50 facilities requires one Dijkstra pass, not 5,000.
Key assumptions
- Nearest = most preferred. The model assumes that every demand point uses the facility with the lowest network cost. In reality, people may choose a farther facility because of quality, waiting time, familiarity, or insurance coverage. The allocation is a supply-side model of what is possible, not a demand-side model of what people actually do.
- No capacity constraints. Facilities have unlimited capacity — assigning 500 demand points to one facility and 5 to another produces a valid result. For capacity-constrained assignment, use Capacitated Allocation which iteratively reassigns demand when a facility reaches its limit, using a penalty-based reallocation algorithm.
- Deterministic tie-breaking. When two facilities are at identical cost from a demand point, the one appearing first in the input feature order wins. This can produce counter-intuitive results along a symmetry axis (e.g. the exact midpoint between two identical facilities on a straight road). The strip of ambiguity is at most one grid cell wide, but for publication-grade maps at large scale, manually inspect the assignment along equidistance boundaries.
- Snap truncation. Demand points farther from the network than the cutoff distance are automatically unallocated — even if they are geographically close to a facility. A building 300 m inside a park with its centroid 300 m from the nearest road will be unallocated at a 500 m cutoff because the snap distance alone consumes 300 m. For building-level analysis, ensure demand points are on or very near the network.
When to use vs. when NOT to use
Use Nearest Facility when: auditing school catchment
assignment, healthcare service area planning, emergency-service station
coverage analysis, or any application where the question is "which facility
serves this location?" and facilities do not have hard capacity limits.
Combine with the SUMMARY output to identify overloaded facilities
(demand_n far above the mean) and underserved service gaps
(facility = "").
Do NOT use when: (a) facilities have strict capacity limits — use Capacitated Allocation; (b) you need only the cost to the nearest facility, not the allocation label — the Multi-Amenity Access Score is faster for per-category proximity without spatial assignment; (c) the question is about optimal facility locations, not the allocation from existing facilities — use the Facility Location Optimizer.
Mathematical Formulation
Given $n$ demand locations and $f$ facility locations, each snapped to network nodes, the algorithm computes:
$$label(d) = \arg\min_{k \in \{1,\ldots,f\}} d_{net}(k, d) \tag{5}$$ $$cost(d) = \min_{k \in \{1,\ldots,f\}} d_{net}(k, d) \tag{4}$$where $d_{net}(k,d)$ is the shortest-path distance from facility $k$ to demand $d$ on the graph. If multiple facilities share a node, the first one in the input order wins — assignments are deterministic.
Facility load:
$$load(k) = |\{d : label(d) = k\}| \tag{3}$$ $$mean\_cost(k) = \frac{1}{load(k)} \sum_{d: label(d)=k} cost(d) \tag{2}$$ $$max\_cost(k) = \max_{d: label(d)=k} cost(d) \tag{1}$$Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Prepared network. Projected CRS. |
| Demand points | Vector (any) | Yes | Locations to be allocated. Building centroids, parcel points, population-weighted points. |
| Facilities | Vector (any) | Yes | Facility locations. Points snap to nearest network node. |
| Cost field | Numeric field | No | Additive per-segment cost for time-based allocation. Walking Slope Comfort's time_fwd_min gives slope-aware catchments. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. |
DEMAND | Vector (Any) | — | Demand point locations. |
FACILITIES | Vector (Any) | — | Facility locations with ID field. |
FACILITY_ID | Field | — | Field identifying each facility in the output. |
COST_FIELD | Field (Numeric) | (empty = length) | Additive per-segment cost. Use for time-based allocation. |
CUTOFF | Double | 0 (unlimited) | Maximum cost; demand beyond this is unallocated (facility = "", cost = −1). |
OUTPUT | Vector (Point) | — | Allocated demand with facility label and cost. |
SPIDER | Vector (Line) | (optional) | Straight allocation lines from each demand to its facility. |
ROUTES | Vector (Line) | (optional) | Reconstructed street-level routes. Slower but gives actual travel paths. |
SUMMARY | Table | — | Per-facility load summary. |
Output Description
| Output | Fields | Description |
|---|---|---|
| Allocated demand | facility, net_cost | Assigned facility label and network cost. facility = "" and net_cost = −1 = unreachable. |
| Allocation lines | facility, net_cost | Straight lines from demand to facility. Long bundles crossing other catchments = missing facility or network barrier. |
| Allocation routes | demand_i, facility, net_cost, length_m | Actual street-level paths. length_m = geometric length of the reconstructed route. |
| Facility summary | facility, demand_n, mean_cost, max_cost | demand_n = load. max_cost = worst-case trip (the number standards care about). |
Symbolic Representation
Colour demand points by facility with a
categorical renderer (random colours or a predefined palette) to see de-facto
catchment boundaries — these are the network Voronoi regions. Style
unallocated points (cost = −1) as red X markers to highlight service gaps.
Allocation lines coloured by facility, with 30–40% opacity, reveal the spatial
extent of each catchment. For the summary table, a bar chart of
demand_n by facility identifies overloaded facilities at a glance.
Interpretation Guide
- Unallocated demand (cost = −1) = the service gaps. Map these first — they are people with zero access within the cutoff.
- demand_n far above the average marks where the next
facility would relieve the most load. Rerun with a candidate site added and
compare
max_costanddemand_nshifts. - max_cost is the worst trip anyone must make — the number that planning standards (e.g. "no resident more than 800 m from a GP") care about.
- mean_cost compares overall convenience between facilities of the same type.
- Spider lines that cross multiple other catchments indicate a missing facility or a network barrier forcing demand past closer options.
- For capacity-constrained assignment (where facilities have limited capacity), use Capacitated Allocation instead.
Academic References
Talen, E. & Anselin, L. (1998). "Assessing Spatial Equity: An Evaluation of Measures of Accessibility to Public Playgrounds." Environment and Planning A, 30(4), 595–613. DOI: 10.1068/a300595
DOI: 10.1080/01944361003766766Dreyfus, S.E. (1969). "An Appraisal of Some Shortest-Path Algorithms." Operations Research, 17(3), 395–412. DOI: 10.1287/opre.17.3.395
Link Criticality (Network Robustness)
Processing ID: planx:linkcriticality
Overview
Ranks every street segment by how badly the network would suffer if that segment were lost — the road-network vulnerability view based on the Network Robustness Index (Scott et al., 2006; Jenelius et al., 2006). For a given origin–destination demand set, the tool first routes every pair on the intact network, then removes each segment in turn and re-routes, reporting the extra travel cost each removal forces plus any demand it cuts off entirely. Only segments that carry at least one shortest path are re-tested — the rest cannot change any route and score zero, which prunes the computation significantly.
Theoretical Background
Academic lineage
Network robustness analysis emerged from the intersection of transportation engineering and complex network theory in the early 2000s. The pivotal event was the 2001 Nisqually earthquake in Washington State, which damaged bridges and severed key road links, demonstrating that modern cities depend on a small number of critical links whose failure cascades far beyond the immediate damage zone. This spurred the first formal methodologies: the Network Robustness Index (NRI) by Scott, Novak, Aultman-Hall & Guo (2006), which introduced the concept of OD-weighted consequence measurement, and the importance/exposure framework of Jenelius, Petersen & Mattsson (2006), which separated link criticality into an importance component (how much travel uses the link) and an exposure component (how much travel is affected when it fails).
The field draws on two distinct intellectual traditions. The first is graph-theoretic vulnerability, rooted in the Erdős–Rényi and Barabási–Albert random-graph models: it asks which nodes or edges, when removed, maximally increase the average path length or fragment the network. The second is transport-system consequence analysis: it asks, for a given demand (the actual trips people make), which link failures impose the highest total detour cost. The two traditions sometimes conflict — a topologically central edge that carries few real trips ranks high by betweenness but low by NRI, and vice versa. The PlanX implementation follows the second tradition (consequence analysis) because planning decisions about bridge replacement and emergency routing should be driven by actual travel demand, not abstract topology.
Mattsson & Jenelius (2015) consolidated the field in their comprehensive
review, distinguishing vulnerability (the susceptibility to
disruption) from resilience (the ability to recover function
after disruption). The NRI implemented in PlanX measures vulnerability; the
n_disconnected field captures the most extreme form — total
severance. These authors also highlighted that the most impactful single-step
improvement to a vulnerability analysis is rarely a new algorithm but placing the
OD demand on the trips that actually matter: emergency vehicle access routes,
hazardous material corridors, and evacuation paths produce more actionable
rankings than generic all-pairs matrices.
Key assumptions
- Single-link failure. The tool removes one edge at a time and measures its consequence. It does not test simultaneous multi-link failures (e.g. an earthquake damaging multiple bridges). For multi-link scenarios, run the single-link analysis and then test the top-N critical links in combination manually.
- Deterministic shortest-path routing. After link removal, travellers are assumed to re-route along the new shortest path. In reality, drivers may not know the new optimum immediately (information lag), may choose suboptimal alternatives (bounded rationality), or may abandon the trip entirely. The NRI is therefore a lower bound on the true disruption — real-world detour costs are typically higher.
- No capacity constraints. The surviving links are assumed to carry all re-routed traffic without congestion delay. In a real failure, re-routed traffic can saturate parallel links, slowing them and further increasing travel cost. PlanX does not model capacity; for congestion-aware analysis, an external traffic-assignment model is required.
- OD demand is fixed. The set of trips is invariant — people do not cancel trips, change destination, or switch mode because a link is gone. For evacuation or emergency scenarios where behaviour changes dramatically, the OD matrix should be re-specified (e.g. all trips to the nearest hospital or shelter) rather than reused from a commuter matrix.
- Candidate pruning. Only edges on at least one intact
shortest path (
used_by > 0) are removal-tested. In dense grids, the typical pruning rate is 60–90%, making the computation feasible for networks of up to ~20,000 segments. However, if the OD set is very small (e.g. 5 origins x 5 destinations = 25 pairs), most edges carry no shortest path and are pruned — the analysis then tells you about those trips' vulnerabilities, not the network's intrinsic redundancy.
When to use vs. when NOT to use
Use Link Criticality when: screening a road network for
bridges, tunnels, and main arteries whose failure would impose the greatest
detour cost; preparing a resilience investment priority list; identifying
single points of failure (n_disconnected > 0) that warrant
duplication or hardening; evaluating a proposed new link by comparing
criticality scores before and after it is added — the links whose criticality
drops most are those that the new link relieves.
Do NOT use when: (a) the analysis requires multi-link failure scenarios (earthquake damage to multiple bridges) — the tool tests one edge at a time; (b) you need a generic, demand-independent structural ranking of the network — use Network Centrality (betweenness) instead; (c) the network is very small (under 50 segments) and all-pairs routing is trivial — the tool's computational overhead is wasted; (d) you need real-time or near-real-time vulnerability assessment on a live traffic network — the exhaustive removal-test approach is designed for offline planning analysis, not operational use.
Mathematical Formulation
Baseline routing. For every OD pair $(o,d)$ in the demand set, compute $d_{net}(o,d)$ on the intact graph $G$. The base total is:
$$T_{base} = \sum_{o,d} d_{net}(o,d) \tag{3}$$An edge $e$ is a candidate if it lies on at least one intact shortest path: $used\_by(e) = |\{(o,d) : e \in path(o,d)\}| > 0$.
Removal test. For each candidate edge $e$, route all OD pairs on $G \setminus \{e\}$:
$$extra\_cost(e) = \sum_{o,d} \max(0,\; d_{net}^{(e)}(o,d) - d_{net}(o,d)) \tag{2}$$Note: removal can only lengthen paths, so $extra\_cost(e) \geq 0$. If the removal severs an OD pair entirely, $d_{net}^{(e)}(o,d)$ is infinite and the pair contributes to $n\_disconnected(e)$.
Criticality (NRI):
$$criticality(e) = \frac{extra\_cost(e)}{T_{base}} \tag{1}$$Criticality is dimensionless, typically in $[0, 0.1]$ — losing a single segment rarely adds more than 10% to total travel, though extreme values occur for bridges and single-access connectors.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Prepared network. Projected CRS. More segments = more removal tests. |
| Origins | Vector (any) | Yes | Demand origins. Place on the trips that matter (population to hospitals, depots to demand). |
| Destinations | Vector (any) | No | Empty = origins serve as destinations (all-pairs). |
| Cost field | Numeric field | No | Additive per-segment cost. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. |
ORIGINS | Vector (Any) | — | Origin demand points. |
DESTINATIONS | Vector (Any) | (optional) | Destination demand points. Empty = all-pairs among origins. |
COST_FIELD | Field (Numeric) | (empty = length) | Additive per-segment cost column. |
CUTOFF | Double | 0 (unlimited) | Maximum cost for baseline routing. Pairs beyond cutoff are excluded from the demand set. |
CRITICAL | Vector (Line) | — | Street segments with criticality scores. |
used_by > 0). For a 10,000-segment network with 2,000 candidates
and 500 origins, this is ~2,000 Dijkstra runs. Use a modest origin set
(20–100 points) placed on the trips that actually matter for your resilience
analysis — population centroids to hospital locations, for instance — rather
than the entire building stock.Output Description
| Field | Type | Description |
|---|---|---|
edge_id | Long | Unique edge identifier in the graph |
criticality | Double | NRI: extra_cost / base_total. 0 = fully redundant. Top few percent = critical links. |
extra_cost | Double | Absolute detour cost summed over all OD pairs (metres or cost-field units) |
n_disconnected | Long | Number of OD pairs severed by removing this edge. Nonzero = genuine cut-edge. |
used_by | Long | Number of intact shortest paths using this edge. High use + low criticality = well-served redundancy. |
length_m | Double | Geometric length of the segment in metres |
Symbolic Representation
A graduated renderer on criticality with a sequential
multi-hue ramp (Inferno or Plasma), natural-breaks classification (5–7
classes), and line width 0.3–0.8 mm scaled by criticality percentile. Edges
with n_disconnected > 0 should use a distinct colour (red,
2 mm stroke) — these are the true single points of failure. The top 5% by
criticality warrant labels with the edge ID. At city scale, filter to
criticality ≥ 0.001 to declutter.
Interpretation Guide
- criticality is the headline: the fraction of total baseline travel cost added by losing this one segment. Sort descending to identify the network's structural vulnerabilities.
- n_disconnected > 0 flags a genuine cut-edge — a bridge, single tunnel, or lone connector whose loss isolates demand entirely. These are usually more urgent than any detour — duplicate, protect, or provide a bypass.
- used_by combined with criticality yields a four-way classification: high-use + high-criticality = bottleneck (add parallel capacity); high-use + low-criticality = well-served corridor (redundancy exists); low-use + high-criticality = vulnerable local link (sole access to a community); low-use + low-criticality = non-essential.
- Place your origins/destinations on the trips that matter — population to hospitals, emergency depots to demand zones — so the ranking reflects real exposure, not just geometry. A segment critical for emergency access may score zero if the OD set includes only commuters.
Academic References
Scott, D.M., Novak, D.C., Aultman-Hall, L., & Guo, F. (2006). "Network Robustness Index: A New Method for Identifying Critical Links and Evaluating the Performance of Transportation Networks." Journal of Transport Geography, 14(3), 215–227. DOI: 10.1016/j.jtrangeo.2005.10.003
Jenelius, E., Petersen, T. & Mattsson, L.-G. (2006). "Importance and Exposure in Road Network Vulnerability Analysis." Transportation Research Part A, 40(7), 537–560. DOI: 10.1016/j.tra.2005.11.003
Mattsson, L.-G. & Jenelius, E. (2015). "Vulnerability and Resilience of Transport Systems — A Discussion of Recent Research." Transportation Research Part A, 81, 16–34. DOI: 10.1016/j.tra.2015.06.002
10. Walkability
The Walkability group translates the walkable-city agenda into four interconnected GIS tools. Walkability Audit scores every street segment 0–100 using the classic Frank et al. (2010) ingredients: intersection density, land-use mix, destinations, block length, and slope — each normalised with documented breakpoints and combined with editable weights. Walking Slope Comfort samples a DEM along each street and computes Tobler's-hiking-function travel times. Street Environment Comfort scores streets by the assets (trees, benches, lighting) and barriers (blank walls, vacant lots) around them using kernel-density estimates. Pedestrian Route Quality re-routes over the comfort-weighted network, reporting the detour, the length-weighted quality score, and the low-score share — the difference between the shortest path and the pleasantest one.
Walkability Audit
Processing ID: planx:walkability
Overview
Scores every street segment 0–100 for walkability using five classic ingredients from the walkability-index literature: intersection density (connectivity), land-use mix (normalised Shannon entropy of buffer areas), destination counts (POIs within radius), block length (mean street-segment length as a block-size proxy), and slope (segment gradient from an optional DEM). Each ingredient is normalised 0–100 with documented breakpoints; missing inputs are renormalised away so the tool degrades gracefully with partial data. The output is the definitive "existing conditions" exhibit for a pedestrian master plan.
Theoretical Background
The walkability index traces its lineage to urban planning's D-variables framework (Ewing & Cervero, 2010): Density, Diversity (land-use mix), Design (street connectivity), Destination accessibility, and Distance to transit. Frank et al. (2010) operationalised four of these for the Neighborhood Quality of Life Study. PlanX adapts this to the street-segment level — walkability is fundamentally a network property: a street is walkable not in isolation but by virtue of what it connects to. Breakpoints default to a comfortably walkable European urban fabric: 120 junctions/km², 80 m block length, 25 POIs, and 0% slope all score 100.
Mathematical Formulation
Intersection density. Junctions (degree ≥ 3) counted within radius $r$ of each segment midpoint:
$$int\_km2(s) = \frac{|\{j : \|p_j - m_s\| \leq r\}|}{\pi r^2 / 10^6} \qquad s\_inters(s) = 100 \cdot \min(1, int\_km2(s) / 120) \tag{2}$$Land-use mix. Normalised Shannon entropy of buffer land-use areas:
$$mix(s) = \frac{-\sum_c p_c \ln p_c}{\ln N_{cat}} \in [0,1] \qquad s\_mix(s) = 100 \cdot mix(s) \tag{1}$$Destinations. POI count within radius: $s\_dest(s) = 100 \cdot \min(1, n\_pois(s) / 25)$.
Block length (smaller-is-better): $s\_block(s) = 100 \cdot \max(0, \min(1, (400 - blk\_len(s)) / (400 - 80)))$.
Slope: $slope\_pct(s) = |z_{end} - z_{start}| / \ell_s \cdot 100$, then $s\_slope(s) = 100 \cdot \max(0, 1 - slope\_pct(s) / 10)$.
Composite: $walk\_score(s) = \sum w_c \cdot s_c(s) / \sum w_c$ over available components, with missing weights renormalised.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Prepared, projected CRS (metres). Audit radius is in map units. |
| Land-use polygons | Vector polygons | No | Needs category field. Without it, mix is skipped. |
| Destinations/POIs | Vector points | No | Shops, schools, stops, parks. Counted within radius. |
| DEM | Raster | No | 10–30 m resolution adequate. Sampled at segment endpoints. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. Exploded segments. |
LANDUSE | Vector (Polygon) | (optional) | Land-use for mix component. |
CATEGORY_FIELD | Field | (optional) | Land-use category field. |
POIS | Vector (Point) | (optional) | Destination points. |
DEM | Raster | (optional) | DEM for slope. |
RADIUS | Double | 400.0 | Audit radius in map units. 400 m = ~5-min walk. |
WEIGHTS | String | "intersections=0.3, mix=0.25, destinations=0.25, blocklength=0.1, slope=0.1" | Component weights. Renormalised over available components. |
OUT_SEGMENTS | Vector (Line) | — | Walkability-scored segments. |
Output Description
| Field | Type | Range | Description |
|---|---|---|---|
walk_score | Double | 0–100 | Composite. 70+ walkable; 50–70 friction; <40 car-dependent. |
s_inter | Double | 0–100 | Intersection density sub-score |
s_mix | Double | 0–100 | Land-use mix sub-score (null if no data) |
s_dest | Double | 0–100 | Destination sub-score (null if no data) |
s_block | Double | 0–100 | Block length sub-score |
s_slope | Double | 0–100 | Slope sub-score (null if no DEM) |
int_km2 | Double | 0–200+ | Raw junction density (junctions/km²) |
mix_ent | Double | 0–1 | Raw Shannon entropy |
n_pois | Integer | 0–N | Raw POI count |
blk_len | Double | 20–500 | Raw mean block length (m) |
slope_pct | Double | 0–15+ | Raw slope (%) |
Symbolic Representation
Map walk_score with a diverging RdYlGn ramp (5 classes: 0–20, 20–40, 40–60, 60–80, 80–100). Green = walkable; red = car-dependent. Line width 0.5 mm. Map sub-scores as small multiples to reveal which deficiency drives each low-scoring corridor: low s_inter = coarse network (add cut-throughs); low s_mix = monofunctional zoning; low s_dest = nothing to walk TO; low s_block = oversized blocks; low s_slope = topography. Rank low-score corridors by adjacent population for the investment priority list.
Interpretation Guide
Walkability bands map to different remedies: low s_inter → new links and cut-throughs; low s_mix → permit corner commercial uses; low s_dest → ground-floor activation, kiosks, stops; low s_block → mid-block crossings; low s_slope → topography (route around, not fixable by zoning). A high-scoring segment next to very low ones reads as an island — walkability is a NETWORK property. Rerun after proposed interventions and difference the scores to show exactly which streets improve and by how much. Feed walk_score into Pedestrian Route Quality to find the pleasantest path, not just the shortest.
Academic References
Frank, L.D., Sallis, J.F., Saelens, B.E., Leary, L., Cain, K., Conway, T.L., & Hess, P.M. (2010). "The Development of a Walkability Index: Application to the Neighborhood Quality of Life Study." British Journal of Sports Medicine, 44(13), 924–933. DOI: 10.1136/bjsm.2009.058701
Ewing, R. & Cervero, R. (2010). "Travel and the Built Environment: A Meta-Analysis." Journal of the American Planning Association, 76(3), 265–294. DOI: 10.1080/01944361003766766
Appendix D: Complete Bibliography
Barabasi, A.-L. & Albert, R. (1999). "Emergence of Scaling in Random Networks." Science, 286(5439), 509–512. DOI: 10.1126/science.286.5439.509
Bast, H., Delling, D., Goldberg, A., Muller-Hannemann, M., Pajor, T., Sanders, P., Wagner, D. & Werneck, R.F. (2016). "Route Planning in Transportation Networks." In: Kliemann, L. & Sanders, P. (eds.), Algorithm Engineering, LNCS 9220, pp. 19–80. Springer. DOI: 10.1007/978-3-319-49487-6_2
Bavelas, A. (1948). "A Mathematical Model for Group Structures." Human Organization, 7(3), 16–30. DOI: 10.17730/humo.7.3.f4033344851gl053
Bonacich, P. (1972). "Factoring and Weighting Approaches to Status Scores and Clique Identification." Journal of Mathematical Sociology, 2(1), 113–120. DOI: 10.1080/0022250X.1972.9989806
Brandes, U. (2001). "A Faster Algorithm for Betweenness Centrality." Journal of Mathematical Sociology, 25(2), 163–177. DOI: 10.1080/0022250X.2001.9990249
Crucitti, P., Latora, V. & Porta, S. (2006). "Centrality Measures in Spatial Networks of Urban Streets." Physical Review E, 73, 036125. DOI: 10.1103/PhysRevE.73.036125
Crucitti, P., Latora, V. & Porta, S. (2006). "Centrality in Networks of Urban Streets." Chaos, 16, 015113. DOI: 10.1063/1.2150162
Curtin, K.M. (2007). "Network Analysis in Geographic Information Science: Review, Assessment, and Projections." Cartography and Geographic Information Science, 34(2), 103–111. DOI: 10.1559/152304007781002163
Dijkstra, E.W. (1959). "A Note on Two Problems in Connexion with Graphs." Numerische Mathematik, 1(1), 269–271. DOI: 10.1007/BF01386390
Dreyfus, S.E. (1969). "An Appraisal of Some Shortest-Path Algorithms." Operations Research, 17(3), 395–412. DOI: 10.1287/opre.17.3.395
Ewing, R. & Cervero, R. (2010). "Travel and the Built Environment: A Meta-Analysis." Journal of the American Planning Association, 76(3), 265–294. DOI: 10.1080/01944361003766766
Frank, L.D., Sallis, J.F., Saelens, B.E., Leary, L., Cain, K., Conway, T.L., & Hess, P.M. (2010). "The Development of a Walkability Index: Application to the Neighborhood Quality of Life Study." British Journal of Sports Medicine, 44(13), 924–933. DOI: 10.1136/bjsm.2009.058701
Freeman, L.C. (1977). "A Set of Measures of Centrality Based on Betweenness." Sociometry, 40(1), 35–41. DOI: 10.2307/3033543
Handy, S.L. & Niemeier, D.A. (1997). "Measuring Accessibility: An Exploration of Issues and Alternatives." Environment and Planning A, 29(7), 1175–1194. DOI: 10.1068/a291175
Hillier, B. & Hanson, J. (1984). The Social Logic of Space. Cambridge University Press. DOI: 10.1017/CBO9780511597237
Hillier, B., Penn, A., Hanson, J., Grajewski, T., & Xu, J. (1993). "Natural Movement: Or, Configuration and Attraction in Urban Pedestrian Movement." Environment and Planning B: Planning and Design, 20(1), 29–66. DOI: 10.1068/b200029
Hillier, B. & Iida, S. (2005). "Network and Psychological Effects in Urban Movement." In: Cohn, A.G. & Mark, D.M. (eds.), Spatial Information Theory (COSIT 2005), LNCS 3693, pp. 475–490. Springer. DOI: 10.1007/11556114_30
Hillier, B., Yang, T., & Turner, A. (2012). "Normalising Least Angle Choice in Depthmap — and How It Opens Up New Perspectives on the Global and Local Analysis of City Space." Journal of Space Syntax, 3(2), 155–193. journal does not assign DOIs] Available at: UCL Discovery
Jenelius, E., Petersen, T. & Mattsson, L.-G. (2006). "Importance and Exposure in Road Network Vulnerability Analysis." Transportation Research Part A, 40(7), 537–560. DOI: 10.1016/j.tra.2005.11.003
Mattsson, L.-G. & Jenelius, E. (2015). "Vulnerability and Resilience of Transport Systems — A Discussion of Recent Research." Transportation Research Part A, 81, 16–34. DOI: 10.1016/j.tra.2015.06.002
Ortuzar, J. de D. & Willumsen, L.G. (2011). Modelling Transport. 4th ed., Wiley. DOI: 10.1002/9781119993308
Porta, S. & Renne, J.L. (2005). "Linking Urban Design to Sustainability: Formal Indicators of Social Urban Sustainability Field Research in Perth, Western Australia." Urban Design International, 10, 51–64. DOI: 10.1057/palgrave.udi.9000136
Porta, S., Crucitti, P., & Latora, V. (2006). "The Network Analysis of Urban Streets: A Primal Approach." Environment and Planning B: Planning and Design, 33(5), 705–725. DOI: 10.1068/b32045
Porta, S., Crucitti, P. & Latora, V. (2006). "The Network Analysis of Urban Streets: A Dual Approach." Physica A, 369(2), 853–866. DOI: 10.1016/j.physa.2005.12.063
Scott, D.M., Novak, D.C., Aultman-Hall, L., & Guo, F. (2006). "Network Robustness Index: A New Method for Identifying Critical Links and Evaluating the Performance of Transportation Networks." Journal of Transport Geography, 14(3), 215–227. DOI: 10.1016/j.jtrangeo.2005.10.003
Sevtsuk, A. & Mekonnen, M. (2012). "Urban Network Analysis: A New Toolbox for ArcGIS." Revue Internationale de Geomatique, 22(2), 287–305. DOI: 10.3166/rig.22.287-305
Talen, E. & Anselin, L. (1998). "Assessing Spatial Equity: An Evaluation of Measures of Accessibility to Public Playgrounds." Environment and Planning A, 30(4), 595–613. DOI: 10.1068/a300595
Turner, A. (2001). "Angular Analysis." In: Peponis, J., Wineman, J. & Bafna, S. (eds.), Proceedings of the 3rd International Space Syntax Symposium, Atlanta, GA, pp. 30.1–30.11. conference proceedings] Available at: UCL Discovery
Wasserman, S. & Faust, K. (1994). Social Network Analysis: Methods and Applications. Cambridge University Press. DOI: 10.1017/CBO9780511815478
Wilson, A.G. (1967). "A Statistical Theory of Spatial Distribution Models." Transportation Research, 1(3), 253–269. DOI: 10.1016/0041-1647(67)90035-4
Walking Slope Comfort
Processing ID: planx:walkingslope
Overview
Profiles every street segment against a Digital Elevation Model (DEM) to compute
slope statistics, comfort classes, and direction-aware walking times. The engine
samples elevations at regular intervals along each segment and applies Tobler's
hiking function — the canonical empirical model relating walking speed to terrain
gradient. For each segment, it reports the length-weighted mean absolute slope,
maximum slope, total vertical climb and descent, and estimated forward and reverse
walking travel times. The output's time_fwd_min column is designed as
a drop-in cost field for all PlanX network routing tools, enabling slope-aware
catchments that price uphill walks honestly. The reverse time captures the
directional asymmetry that flat-network models ignore.
The comfort classification uses editable breakpoints on the mean absolute slope percentage. The defaults (5%, 8%, 12%) map to established terrain-accessibility standards: 5% is the maximum running slope permitted for an accessible route under ADA/ABA guidelines without landings; 8.33% is the maximum for a short ramp with landings; and 12% is the threshold above which stairs or mechanical assistance is generally preferred. These are illustrative defaults — local standards and terrain conditions should override them.
Theoretical Background
Walking speed as a function of terrain gradient has been studied for over a century, from Naismith's rule-of-thumb (1892) for Scottish mountaineering to modern GPS-instrumented studies. The canonical empirical function in GIScience is Tobler's hiking function (Tobler, 1993):
$$v(m) = 6 \cdot \exp\left(-3.5 \cdot |m + 0.05|\right) \quad [\text{km/h}] \tag{5}$$where $m$ is the signed slope gradient as a fraction ($m = dz/dx$, so $m = +0.10$ is a 10% uphill, $m = -0.05$ a 5% downhill). The function is empirically calibrated from hiker data and has three key properties:
- Peak speed: 6.0 km/h at $m = -0.05$ (a gentle 5% downhill), faster than level walking because gravity assists without braking.
- Asymmetry: downhill speeds exceed uphill speeds for the same absolute gradient — the function is not symmetric about $m = 0$.
- Exponential decay: speeds drop rapidly for steep grades. At $m = 0.10$ (10% uphill), speed is ~3.5 km/h; at $m = 0.20$ (20%), ~1.5 km/h — halving distance at double the time.
This asymmetry has profound implications for accessibility analysis. Consider a hill between a residential area and a train station: the uphill journey (home to station) takes substantially longer than the downhill return, yet standard network-cost models assume a symmetric edge weight. A catchment drawn with a flat-network budget of 800 m will systematically overestimate the reach from uphill origins and underestimate it from downhill origins. Walking Slope Comfort provides the direction-aware travel times needed to correct this error.
The method of profiling — sampling a raster at regular intervals along a polyline and computing length-weighted grade statistics — is standard in trail analysis and has been applied to urban networks by Iverson (1975) and others. The length-weighted mean ($\sum |dz| / \sum dx$) is preferred over the arithmetic mean because it correctly accounts for segments of varying length: a short, steep section contributes proportionally less to the mean than a long, gentle one.
The comfort classification breakpoints are grounded in accessibility standards but are illustrative. The Americans with Disabilities Act (ADA, 2010) specifies 5% (1:20) as the maximum running slope for an accessible route and 8.33% (1:12) for short ramps with landings. The UN Convention on the Rights of Persons with Disabilities (CRPD) uses similar thresholds internationally. At 12% mean slope, most jurisdictions would require stairs or mechanical assistance (lift, funicular). These breakpoints are user-editable: a municipality with steeper terrain (e.g., San Francisco, Istanbul) may adopt a more permissive classification calibrated to local topography.
Mathematical Formulation
Profile sampling. Given a polyline of length $L$ and a sample step $\Delta s$, the tool generates sample distances $d_k = k \cdot \Delta s$ for $k = 0, 1, \ldots, \lceil L / \Delta s \rceil$, with the final sample at $d = L$. At each distance, a point is interpolated along the geometry and the DEM is sampled at that coordinate:
$$z_k = \text{DEM}(x(d_k), y(d_k)) \tag{4}$$Samples falling outside the DEM extent or on NoData cells are discarded. If fewer than two valid samples are obtained, the segment is treated as flat.
Grade statistics. For consecutive samples $k, k+1$, the signed grade (fraction) over interval $i$ is:
$$m_i = \frac{z_{i+1} - z_i}{d_{i+1} - d_i} \tag{3}$$The length-weighted mean absolute grade is:
$$\bar{m} = \frac{\sum_{i} |m_i| \cdot \Delta d_i}{\sum_{i} \Delta d_i} \tag{2}$$where $\Delta d_i = d_{i+1} - d_i$. The maximum absolute grade is $m_{\max} = \max_i |m_i|$. Total climb and descent ($\sum \max(0, \Delta z_i)$ and $\sum \max(0, -\Delta z_i)$ respectively) are reported in metres.
Direction-aware travel time. The forward travel time is computed segment by segment using Tobler's speed:
$$t_{\text{fwd}} = \sum_i \frac{\Delta d_i / 1000}{v(m_i)} \cdot 60 \quad [\text{minutes}] \tag{1}$$where $v(m_i)$ is Tobler's speed in km/h for the signed grade $m_i$. The
reverse travel time is computed identically but with the grade sign flipped and
the intervals processed in reverse order: $t_{\text{rev}} = \sum_i
(\Delta d_{n-i} / 1000) / v(-m_{n-i}) \cdot 60$. The effective mean speed from
the Tobler profile is reported as tobler_fwd_kmh and
tobler_rev_kmh — these differ from the flat-network assumption of
constant walking speed and are the key diagnostics for slope-aware routing.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Exploded street segments in a projected CRS (metres). Multipart geometries are handled via the PlanX source_polylines utility which tessellates them. |
| Digital Elevation Model | Raster | Yes | DEM at 5–30 m resolution. Coarser DEMs (30 m SRTM, ASTER) produce acceptable segment-mean slopes but miss short ramps. LiDAR-derived DEMs (1–2 m) capture kerb cuts and short grades. Must be in the same projected CRS as the network, or the tool will reproject on the fly. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. Projected CRS required. Exploded segments (one row per street block) give the cleanest per-segment results. |
DEM | Raster | — | Digital elevation model. Required — without it, the tool cannot proceed. |
SAMPLE_STEP | Double | 10.0 | Profile sample spacing in map units (typically metres). Smaller values (2–5 m) capture short ramps but increase runtime; 10 m is adequate for segment-mean slope on urban blocks. At 2 m, a 200 m segment generates ~100 sample pairs. |
BREAKS | String | "5,8,12" | Comma-separated mean absolute slope % breakpoints for comfort classification. Must be strictly ascending. The tool produces len(breaks) + 1 classes. With the default three breakpoints, classes 1–4 receive labels: Comfortable, Moderate, Steep, Severe. With a different number of breakpoints, generic "Class N" labels are used. |
OUTPUT | Vector (Line) | — | Slope-profiled street segments with all derived fields. |
Output Description
| Field | Type | Range | Description |
|---|---|---|---|
slope_pct | Double | 0–30+ | Length-weighted mean absolute slope in percent. 0–5% is comfortable walking; 5–8% is noticeable but manageable; 8–12% is steep; >12% is stairs-preferred terrain. |
max_pct | Double | 0–50+ | Maximum absolute slope across any sample interval. Even a single steep ramp within an otherwise gentle segment will raise this value — use it to identify discrete barriers. |
climb_m | Double | 0–100+ | Total vertical climb in metres (sum of positive elevation changes). For a segment that undulates, climb + descent can exceed the net elevation difference. |
descent_m | Double | 0–100+ | Total vertical descent in metres (sum of absolute negative elevation changes). |
tobler_fwd_kmh | Double | 0–6 | Effective forward walking speed from the Tobler profile in km/h. The ratio of segment length to forward travel time. |
tobler_rev_kmh | Double | 0–6 | Effective reverse walking speed. Equal to forward speed only on perfectly flat segments. |
time_fwd_min | Double | 0–60+ | Forward walking time in minutes using Tobler's hiking function. Use this as the cost field for slope-aware routing. |
time_rev_min | Double | 0–60+ | Reverse walking time. If time_fwd_min and time_rev_min differ substantially (e.g., 5 min forward, 3 min reverse on a 200 m segment), the grade is significant and directional routing is warranted. |
comfort_class | Integer | 1–4+ | Comfort class index starting at 1 (best). With default breaks: 1 = Comfortable (slope_pct ≤ 5), 2 = Moderate (≤ 8), 3 = Steep (≤ 12), 4 = Severe (>12). |
class_label | String | — | Human-readable label for the comfort class. With default three breaks: "Comfortable", "Moderate", "Steep", "Severe". With custom breakpoints: "Class 1", "Class 2", etc. |
Symbolic Representation
Map slope_pct with a sequential multi-hue ramp (YlOrRd, 5 classes,
natural breaks). Red segments (>8%) are walking barriers — these should be the
narrowest line weight (0.3 mm) to avoid visual dominance. Map
comfort_class as a categorical renderer with green (1), yellow (2),
orange (3), red (4) for a standards-compliance heat map. For publication exhibits,
use a two-panel layout: slope_pct on one map,
time_fwd_min / time_rev_min ratio on the other to show the asymmetry
effect.
Interpretation Guide
Primary uses
- Slope-aware catchments. Feed
time_fwd_minas the cost field into OD Cost Matrix, Nearest Facility Allocation, Service Areas, or the 15-Minute City Access Score. This is the single most important step in calibrating a walking accessibility model for hilly cities. A catchment drawn with flat-network costs can overestimate uphill reach by 30–50% on steep terrain. - Accessibility compliance audit. Map
comfort_class ≥ 3segments against the pedestrian network. These are the locations where wheelchair, stroller, or mobility-impaired continuity breaks. Overlay with census data on disability prevalence to identify the most exposed streets. - Intervention prioritisation. Rank segments by $\text{climb\_m} \times \text{pedestrian\_volume}$ (from OD matrix bundles or pedestrian counts). A segment with 10 m climb and 1000 daily pedestrians is a higher priority for ramps, handrails, or a funicular than a 30 m climb segment with 10 pedestrians.
Diagnostic patterns
- time_fwd_min > time_rev_min by 50%+: the segment has a significant sustained grade. The uphill direction (forward, by the line's digitising direction) is penalised. If the digitising direction is arbitrary (OSM conventions vary), treat both directions as candidate uphill costs.
- max_pct > 3x slope_pct: the segment has one or more discrete steep spots (a short ramp, an underpass approach) within an otherwise gentle profile. These are point-fix targets — a ramp regrade or a short staircase — rather than whole-segment interventions.
- climb_m + descent_m > net elevation change: the segment undulates (rolling terrain). This pattern, common in older organic street networks that follow topography, adds energy cost without visual steepness. Long undulating segments can be more tiring than a steady grade because the walker repeatedly accelerates and decelerates.
- All comfort class ≥ 3 at the perimeter of a city centre: the city grew from a flat basin up into surrounding hills. The steepest segments are at the periphery, where lower-income neighbourhoods often concentrate. This pattern is an equity concern — terrain compounds transport poverty.
Cross-references with other PlanX tools
- Walkability Audit: the slope component there uses
segment-endpoint differencing for a quick estimate; Walking Slope Comfort gives
the full profile. For a definitive audit, replace the Walkability Audit's slope
scores with Walking Slope Comfort's
slope_pct. - Pedestrian Route Quality: use
time_fwd_minas the base cost and the comfort score as the quality overlay — the router will price uphill segments for their Tobler time and avoid them further if the comfort score is also low. - Accessibility Equity (Gini/Theil): if the equity analysis
shows high between-group inequality in walking access to transit, overlay
comfort_class ≥ 3segments on the underserved group's neighbourhood — terrain may be the mechanism. - GTFS Import / Transit Access: when computing walk-to-transit
times, use Walking Slope Comfort's
time_fwd_minas the edge weight in the street-network graph. The resulting transit access times will account for the terrain that flat-network models ignore.
Pitfalls
- DEM resolution vs. segment length. A 30 m DEM sampled every 10 m on a 50 m segment oversamples — the same DEM pixel is queried multiple times. The grade between two identical elevations reads as zero. Use a DEM at least 2–3x finer than the segment length for meaningful within-block grade variation.
- Digitising direction. The forward/reverse assignment follows the geometry's digitising order. In OSM extracts, this order is arbitrary and does not correspond to any real-world convention. Never interpret "forward = uphill" — check the actual elevation profile.
- Tobler is empirical, not physiological. Tobler's function was calibrated on hikers, not urban walkers in everyday clothing. It likely underestimates the penalty of steep urban grades (carrying groceries, pushing strollers) and overestimates speeds on flat terrain (crowds, crossings, signals intervene). Treat the times as comparative, not as literal door-to-door predictions.
- Insufficient DEM coverage. If fewer than 2 samples are valid along a segment, the tool treats it as flat and emits a warning. A large warning count means the DEM does not cover the network — check extents and CRS alignment.
Academic References
Tobler, W. (1993). "Three Presentations on Geographical Analysis and Modeling: Non-Isotropic Geographic Modeling; Speculations on the Geometry of Geography; and Global Spatial Analysis." NCGIA Technical Report, 93-1. University of California, Santa Barbara. technical report, no DOI assigned] Available at: eScholarship
Iverson, W.D. (1975). "Assessing terrain conditions for hiking and mountain recreation." Journal of Leisure Research, 7(1), 37–45.
Naismith, W.W. (1892). "Excursions. Cruach Ardran, Stobinian, and Ben More." Scottish Mountaineering Club Journal, 2(3), 136. historical mountaineering journal, no DOI assigned]
ADA Standards for Accessible Design (2010). Title III, 28 CFR Part 36, Section 405: Ramps. U.S. Department of Justice. regulatory standard, no DOI assigned] Available at: ada.gov
Moughtin, C. & Shirley, P. (2005). Urban Design: Green Dimensions. 2nd ed., Architectural Press. (Section 4.2: "Gradients and pedestrian movement" — practical urban-design treatment of slope thresholds.)
Street Environment Comfort
Processing ID: planx:streetcomfort
Overview
Scores every street segment 0–100 by aggregating the micro-scale environmental qualities that pedestrians experience at the street level. The tool models perception as a spatial kernel: assets and barriers do not affect only the point where they sit, but radiate influence over a distance — the bandwidth $h$ — that represents the pedestrian's awareness radius. Comfort assets (trees, benches, street lighting, active shopfronts) raise the score; comfort barriers (potholes, blank walls, vacant lots, construction hoardings) lower it. Optional raster layers (winter sun hours, heat risk index, road noise) add climatic and sensory dimensions.
Each component is aggregated via a kernel density estimate (KDE) at sample points along each segment, then min-max normalised to [0, 1] and orientation- flipped (higher density of barriers = lower comfort). The final index is a weighted mean of the oriented components, scaled 0–100. Missing components are gracefully excluded and weights renormalised; constant components (e.g., all segments have the same tree density) are dropped with a warning.
The index is relative to the study area: it ranks streets against each other, not against an absolute standard. A comfort score of 70 means the segment is in the 70th percentile of local conditions, not that it meets any external benchmark. This makes the tool an ideal comparative diagnostic for identifying the best and worst streets in a network, but unsuitable for compliance checking against a fixed standard.
Theoretical Background
Street-level environmental quality has been studied under several overlapping frameworks. Jan Gehl's decades of observational research in Copenhagen and elsewhere (Gehl, 2011) established that the "space between buildings" — the micro-scale qualities of pavements, facades, street furniture, and planting — determines whether a street invites lingering or merely permits passage. The concept of environmental affordance (Gibson, 1979; applied to urban design by Heft, 1988) argues that the physical environment does not determine behaviour but offers possibilities: a bench affords sitting, a tree affords shade, a blank wall affords nothing. The comfort score aggregates these affordances into a single continuous metric.
The kernel-density approach draws on spatial statistics (Silverman, 1986) and has been applied to urban perception in two influential papers. Ewing & Handy (2009) used expert panel ratings of street-view imagery to identify five urban design qualities — imageability, enclosure, human scale, transparency, and complexity — and then operationalised each with measurable spatial variables. Harvey et al. (2015) extended this with a streetscore algorithm that rated perceived safety from street-level images using a combination of computer vision features and crowd-sourced training data. The PlanX tool follows the same logic but uses vector-based KDE rather than image classification, making it applicable to any city with point-layer inventories (trees, lamps, benches) regardless of whether street-level imagery is available.
The kernel bandwidth $h$ is the critical calibration parameter. At $h = 50$ m (the default), a bench affects comfort out to roughly one block length — the range at which a pedestrian can see and decide to walk toward it. At $h = 25$ m, only very local assets count (the "immediate sidewalk" view). At $h = 100$ m, assets at the far end of a long block still contribute — relevant for assessing visual amenity rather than immediate physical comfort. The kernel shape controls how the influence decays with distance: Uniform (equal weight to $h$), Triangular (linear decay), Epanechnikov (quadratic decay, default — most statistical efficiency), Gaussian (exponential decay, tail extending beyond $h$ but truncated for computational practicality).
Mathematical Formulation
Kernel weights. For a candidate feature at distance $d$ from a sample point, with bandwidth $h > 0$ and normalised distance $u = d/h$:
$$K_{uniform}(u) = 1,\quad K_{tri}(u) = 1 - u,\quad K_{epan}(u) = 1 - u^2,\quad K_{gauss}(u) = e^{-4.5 u^2} \tag{5}$$All kernels are truncated at $u = 1$ ($d > h \Rightarrow K = 0$). The Gaussian kernel uses $\sigma = h/3$, so that $h$ acts as an approximate $3\sigma$ cutoff.
Segment density. For a segment with sample points $\{\mathbf{s}_1, \ldots, \mathbf{s}_m\}$ and a candidate feature set $\{\mathbf{p}_1, \ldots, \mathbf{p}_k\}$ with weights $w_j$, the segment-level density for this component is:
$$\rho_{\text{seg}} = \frac{1}{m} \sum_{i=1}^{m} \sum_{j=1}^{k} w_j \cdot K\!\left(\frac{\|\mathbf{s}_i - \mathbf{p}_j\|_2}{h}\right) \tag{4}$$Candidates are pre-filtered by a spatial index (QgsSpatialIndex) on the bounding box of the segment grown by $h$ — only features within reach are evaluated. Sample points are placed at regular intervals (default 10 m) with midpoint offset: the first sample is at $step/2$ from the segment start, avoiding endpoint duplication at shared junctions.
Min-max normalisation and orientation. For component $c$ with raw values $\rho_c(s)$ across $n$ segments, the normalised and oriented value is:
$$\hat{\rho}_c(s) = \begin{cases} \dfrac{\rho_c(s) - \min_s \rho_c}{\max_s \rho_c - \min_s \rho_c} & \text{if direction = +1 (comfort asset)} \\[10pt] 1 - \dfrac{\rho_c(s) - \min_s \rho_c}{\max_s \rho_c - \min_s \rho_c} & \text{if direction = -1 (barrier)} \end{cases} \tag{3}$$If $\max = \min$ (the component is constant), it is dropped. Raster components are sampled at each sample point and the segment mean is used as $\rho_c(s)$.
Weighted comfort index. For used components $\mathcal{C}$ with weights $w_c$:
$$\text{comfort}(s) = 100 \cdot \frac{\sum_{c \in \mathcal{C}} w_c \cdot \hat{\rho}_c(s)}{\sum_{c \in \mathcal{C}} w_c} \quad \in [0, 100] \tag{2}$$Component weights default to 1.0 each (equal) and are user-editable via a
name=value syntax (e.g., positive=2, negative=1 doubles
the asset weight). Absent components are renormalised away:
The min-max normalisation makes the index scale-dependent on the study area extent. A comfort score of 50 means the segment is at the median of the observed range — if the entire area is pleasant, "median" is still pleasant. For cross-city comparison, use the same component layers and a consistent bandwidth.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Projected CRS. Does not need to be prepared (no graph operations). |
| Comfort assets | Vector points (multi-layer) | No | One or more point layers. Each layer contributes to the positive component. Tree points, lamp posts, benches, waste bins, drinking fountains — any feature that improves the pedestrian experience. Each layer may have an optional weight field. |
| Comfort barriers | Vector points (multi-layer) | No | One or more point layers. Potholes, graffiti locations, construction sites, blank-wall centroids. With weight field, a larger or more severe barrier can count more. |
| Positive raster | Raster | No | Raster where higher values are better for comfort (e.g., winter sun hours, vegetation index). |
| Negative raster | Raster | No | Raster where higher values are worse for comfort (e.g., heat risk index, road noise dB, air pollution). |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. Projected CRS required. |
POSITIVE | Multiple vector layers (Point) | (optional) | Comfort asset layers. Each layer's points are pooled; if multiple layers are given, all contribute to the positive component with the same bandwidth and kernel. |
NEGATIVE | Multiple vector layers (Point) | (optional) | Comfort barrier layers, pooled identically. |
WEIGHT_FIELD | String | "" (empty) | Name of a numeric field (must exist in the layer) providing per-feature weights. If empty or the field is absent, weight 1.0 is used. A large pothole (weight = 5) is five times as impactful as a small one (weight = 1). |
RASTER_PLUS | Raster | (optional) | Comfort-positive raster. |
RASTER_MINUS | Raster | (optional) | Comfort-negative raster. |
BANDWIDTH | Double | 50.0 | Kernel bandwidth in map units (metres). 50 m = one block. 25 m = immediate sidewalk. 100 m = visual amenity at the street scale. |
KERNEL | Enum | Epanechnikov (2) | Kernel shape: 0 = Uniform, 1 = Triangular, 2 = Epanechnikov, 3 = Gaussian. Epanechnikov is the MSE-optimal choice for KDE; Gaussian for smoother transitions. |
SAMPLE_STEP | Double | 10.0 | Spacing between sample points along each segment in map units. Smaller = finer resolution, slower. Midpoint offset prevents double-counting at junctions. |
WEIGHTS | String | "" (equal) | Component weight string: positive=2, negative=1, raster_plus=1, raster_minus=1. Weights must be > 0. Absent components are renormalised out; weights for absent components are warned and ignored. |
OUTPUT | Vector (Line) | — | Comfort-scored street segments. |
Output Description
| Field | Type | Range | Description |
|---|---|---|---|
comfort | Double | 0–100 | Weighted comfort index. Higher = more comfortable. Mean and low-count (<25) are reported in the log. |
pos_den | Double | 0+ | Raw density of comfort assets (kernel-weighted sum of asset weights at each sample, averaged over samples). Null if no positive layers given. |
neg_den | Double | 0+ | Raw density of comfort barriers. Null if no negative layers given. |
rplus_mean | Double | variable | Mean value of the positive raster at segment sample points. Null if no raster given or all samples fall outside the raster. |
rminus_mean | Double | variable | Mean value of the negative raster. Null similarly. |
n_samples | Integer | 1+ | Number of sample points evaluated on this segment. Short segments (< step) get one midpoint sample. |
Symbolic Representation
Map comfort with a diverging RdYlGn ramp (5 quantile classes).
Green = pleasant; red = hostile. Line width 0.4–0.7 mm scaled by the absolute
deviation of comfort from the network median — the best and worst streets are the
widest lines. The raw density fields (pos_den, neg_den)
are diagnostic: map neg_den in red alone to see the barrier
landscape, then overlay high-pos_den segments in green to identify
streets where assets and barriers coexist — a complex reading that the composite
score alone would average away.
Interpretation Guide
The two-factor diagnostic
Read comfort scores as a two-by-two matrix with pos_den and
neg_den:
| High pos_den (asset-rich) | Low pos_den (asset-poor) | |
|---|---|---|
| High neg_den (barrier-heavy) |
Contested street. A main road with trees AND noise, shops AND construction. The comfort score is middling but the street is not neutral — it is intense. Action: reduce barriers (noise barriers, construction management) to let the assets dominate. | Neglected corridor. A service alley, an underpass, a vacant-strip arterial. Nothing good, plenty bad. Action: barrier removal first (lighting, surface repair), then asset planting. |
| Low neg_den (barrier-light) |
Pleasant street. A tree-lined residential avenue with benches. The comfort score ceiling. Action: maintain; protect from infill that would remove assets. | Blank canvas. A clean but featureless street — no barriers but nothing to enjoy either. New developments often start here before planting matures. Action: add assets incrementally (street trees first — they deliver shade, beauty, and air quality in one intervention). |
Cross-references with other PlanX tools
- Walkability Audit: the walkability score captures the meso-scale structure (connectivity, mix, destinations); Street Environment Comfort captures the micro-scale experience. A street with a perfect walkability score can still score low on comfort if it is lined with blank walls and lacks shade. The two scores together give the complete pedestrian-quality picture.
- Pedestrian Route Quality: feed
comfortas the custom score field. The quality-weighted router will avoid comfort-poor streets just as it avoids low-walkability streets. Run with both scores independently and compare the route geometries — where they diverge, meso-scale and micro-scale quality disagree about which route is better. - Shadow Casting / Sun Hours: winter sun hours make an
excellent
RASTER_PLUSinput — a street that receives zero winter sun is perceptibly colder and darker, and the comfort score will reflect this. - Heat Island Risk Grid / Road Noise Screening: natural
RASTER_MINUSinputs. Heat and noise are the two sensory stressors that pedestrians feel most acutely.
Pitfalls
- Relative scale. The score ranks within the study area. A score of 80 in a well-maintained historic centre may represent a higher absolute quality than a score of 80 in a neglected peripheral estate. Do not compare scores across study areas with different component inventories.
- Data completeness. The tool relies on point-inventory layers.
If street trees have not been inventoried,
pos_denwill read zero everywhere — the tool cannot detect assets that are not in the data. Always audit the point layers against ground truth before interpreting comfort scores. - Constant components. If every segment has exactly the same value for a component (e.g., every street has one streetlight), that component is dropped and does not contribute to the score. This is correct — a constant cannot discriminate between streets — but it means the absolute comfort level may be higher (or lower) than the 0–100 scale suggests.
- Bandwidth sensitivity. At very small bandwidths (e.g., 5 m), only features exactly on the segment influence it — a tree 6 m away is invisible. At very large bandwidths (e.g., 500 m), all segments converge to the same score because every street sees the same set of features. Test 2–3 bandwidths and check that the ranking is stable before proceeding with analysis.
Academic References
Gehl, J. (2011). Life Between Buildings: Using Public Space. 6th ed., Island Press. (The foundational observational study of micro-scale urban qualities that predict pedestrian presence and stationary activity.) architecture/design monograph, no DOI assigned]
Ewing, R. & Handy, S. (2009). "Measuring the Unmeasurable: Urban Design Qualities Related to Walkability." Journal of Urban Design, 14(1), 65–84. DOI: 10.1080/13574800802451155
Harvey, C., Aultman-Hall, L., Hurley, S.E., & Troy, A. (2015). "Effects of Skeletal Streetscape Design on Perceived Safety." Landscape and Urban Planning, 142, 18–28. DOI: 10.1016/j.landurbplan.2015.05.007
Silverman, B.W. (1986). Density Estimation for Statistics and Data Analysis. Chapman & Hall. (The canonical text on kernel density estimation, including the MSE optimality of the Epanechnikov kernel.) DOI: 10.1007/978-1-4899-3324-9
Gibson, J.J. (1979). The Ecological Approach to Visual Perception. Houghton Mifflin. (The theory of affordances — that the environment offers possibilities for action — which underpins the entire concept of "environmental comfort" as a measurable property.)
Pedestrian Route Quality
Processing ID: planx:routequality
Overview
Routes pedestrians over quality-weighted streets and reports what the walk is actually like — the complement to every shortest-path tool in PlanX. While OD Routes answers "how far is it," Pedestrian Route Quality answers "how good is the walk." The tool takes a street network with a per-segment quality score (0–100, typically the Walkability Audit output or Street Environment Comfort score) and a quality penalty $p$, reweights each segment's cost as:
$$\text{cost}_e = \ell_e \cdot \left(1 + p \cdot \frac{100 - \text{score}_e}{100}\right) \tag{5}$$With penalty $p = 1$, a segment scoring 0 costs double its length; a segment scoring 50 costs 1.5x; a perfect-100 segment costs exactly its length. With $p = 0$, the quality-weighted cost collapses to the plain geometric length — the tool reproduces the shortest path. For every origin–destination pair, the tool reports the quality-optimal route's length, the plain shortest-path length, the detour ratio between them (the price of pleasantness), the length-weighted mean walk score along the route, the share of route length on low-scoring segments (below a user-set threshold), and the number of edges traversed.
The pairing mode offers two strategies: Nearest destination finds the best-quality route from each origin to its single nearest destination (by quality-weighted cost), the natural mode for "which facility would a quality-conscious pedestrian choose"; All pairs computes routes to every destination, the mode for catchment-quality profiling.
Theoretical Background
The concept of quality-weighted routing originates in the observation that pedestrians do not minimise distance alone. A large body of stated-preference and revealed-preference research (Guo & Loo, 2013; Borst et al., 2009; Agrawal et al., 2008) demonstrates that pedestrians accept detours — often 10–30% — to walk through pleasant, shaded, or active streets rather than along noisy arterials or through dark underpasses. The detour they accept is the revealed value of environmental quality: if pedestrians consistently walk 250 m extra to use a tree-lined street rather than a 750 m arterial, they value the environmental quality at roughly $250/750 = 0.33$ — a 33% premium on the shortest distance.
The quality-penalty formulation used here is a generalised cost model from transport economics (Ortúzar & Willumsen, 2011): each link's perceived cost is the sum of its objective cost (length) and a penalty proportional to its quality deficit. This is structurally identical to how congestion charges, tolls, or "traffic stress" penalties are added to link costs in multi-modal transport models. The penalty $p$ calibrates how much the pedestrian values quality relative to distance: $p = 0.5$ means a score-0 street costs only 1.5x its length (the pedestrian is only mildly quality-sensitive); $p = 2.0$ means a score-0 street costs 3x its length (the pedestrian is highly quality-averse and will detour substantially).
This approach differs from the more common composite index weighting in walkability studies (Frank et al., 2010; Leslie et al., 2007), which produce a single per-segment score but do not model route choice. PlanX separates the two steps: Walkability Audit (or Street Environment Comfort) produces the score; Pedestrian Route Quality answers the behavioural question — given these scores, where would people actually walk?
The connection to Safe Routes to School (SRTS) programmes is
direct and operational. SRTS programmes in the US (authorised under federal
transportation legislation since 2005) and similar "School Streets" initiatives in
the UK and Europe aim to identify and improve the routes children take to school.
The standard SRTS audit rates every block on ~10 safety and comfort criteria.
Pedestrian Route Quality operationalises this at city scale: run home-to-school
pairs (using building centroids or address points), rank routes by
low_share (the fraction of the route on streets scoring below, say,
50), and the worst-ranked routes are the SRTS priority list — every block on
these routes that falls below the threshold is a candidate for sidewalk widening,
crossing improvements, lighting, or traffic calming.
Mathematical Formulation
Quality-weighted edge cost. For edge $e$ with geometric length $\ell_e$ and quality score $\text{score}_e \in [0, 100]$:
$$w_{\text{quality}}(e) = \ell_e \cdot \left(1 + p \cdot \frac{100 - \text{score}_e}{100}\right) \tag{4}$$Edges without a score (NULL or missing) are treated as neutral: $\text{score}_e = 100$, so $w_{\text{quality}}(e) = \ell_e$ — they contribute their geometric cost and no penalty.
Quality-optimal path. Given origins $\{o_1, \ldots, o_m\}$ and destinations $\{d_1, \ldots, d_n\}$, the quality-optimal route from $o_i$ to $d_j$ minimises:
$$R_{quality}(i,j) = \arg\min_{path(i \to j)} \sum_{e \in path} w_{\text{quality}}(e) \tag{3}$$This is solved by Dijkstra's algorithm on the quality-weighted adjacency
matrix. The shortest-path (distance-only) route is solved on the original
(unweighted) adjacency matrix, using the same engine (engine/paths.py)
but with $\text{score}_e \equiv 100$ for all edges.
Detour ratio. For the quality-optimal route with total geometric length $L_{quality}$ and the shortest-path length $L_{shortest}$:
$$\text{detour} = \frac{L_{quality}}{L_{shortest}} \tag{2}$$$\text{detour} \geq 1.0$ always (the shortest path cannot be longer than any other path). $\text{detour} = 1.0$ means the shortest path is also the best- quality path — the ideal outcome. $\text{detour} = 1.5$ means the pedestrian walks 50% further to avoid poor-quality streets.
Length-weighted mean score. For a route comprising edges $\{e_1, \ldots, e_k\}$ with lengths $\ell_1, \ldots, \ell_k$ and scores $s_1, \ldots, s_k$:
$$\overline{s} = \frac{\sum_{i=1}^{k} \ell_i \cdot s_i}{\sum_{i=1}^{k} \ell_i} \tag{1}$$This is the experienced quality — unlike the simple mean over edges, a long edge with a low score weighs more heavily than a short edge.
Low-score share. The fraction of total route length on segments scoring below a user-defined threshold $s_{low}$ (default: 50):
$$\text{low\_share} = \frac{\sum_{i: s_i < s_{low}} \ell_i}{\sum_{i=1}^{k} \ell_i}$$Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Street network | Vector lines | Yes | Ideally the Walkability Audit output. Must be in a projected CRS. The network is passed through build_node_graph so it does not need to be a prepared network — the engine builds the graph on the fly. |
| Walk-score field | Numeric field | No | Per-segment quality score 0–100 from Walkability Audit, Street Environment Comfort, or a custom score. If empty, all segments score 100 (neutral) and the tool reproduces the shortest path. |
| Origins | Vector (any geometry) | Yes | Origin locations — home addresses, building centroids, zone centres. Snapped to nearest network node. |
| Destinations | Vector (any geometry) | Yes | Destination locations — schools, transit stations, parks, shops. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network with optional walk-score field. Projected CRS. |
SCORE_FIELD | Field (Numeric) | (optional) | 0–100 quality score per segment. Empty = all neutral (100). Use walk_score from Walkability Audit or comfort from Street Environment Comfort. |
ORIGINS | Vector (Any) | — | Origin features. Snapped to nearest network node via Euclidean proximity. |
DESTINATIONS | Vector (Any) | — | Destination features. Same snapping logic. |
PAIRING | Enum | Nearest (0) | 0 = each origin to its single nearest destination (by quality-weighted cost). 1 = all pairs (each origin to every destination). Use nearest for SRTS and service-access studies; use all pairs for catchment-quality profiling. |
PENALTY | Double | 1.0 | Quality penalty $p$. 0 = ignore quality (shortest path). 0.5 = mild quality-sensitivity. 1.0 = score-0 street costs double. 2.0 = strong aversion to poor streets. |
LOW_THRESHOLD | Double | 50.0 | Score below which a segment is "low quality" for the low_share calculation. Set higher (e.g., 60) for a more conservative definition; lower (e.g., 30) for the genuinely hostile segments only. |
OUT_ROUTES | Vector (Line) | — | Quality-optimal route geometries with quality attributes. |
Output Description
| Field | Type | Range | Description |
|---|---|---|---|
origin | Integer | 1–M | Index of the origin feature (1-based). |
dest | Integer | 1–N | Index of the destination feature (1-based). |
length_m | Double | 0+ | Geometric length of the quality-optimal route in metres. This is the distance the pedestrian would actually walk. |
shortest_m | Double | 0+ | Length of the shortest (distance-only) path for the same OD pair. The baseline. |
detour | Double | 1.0–~3.0 | length_m / shortest_m. The price of pleasantness. 1.0 = no price; 1.3+ = substantial detour. |
mean_score | Double | 0–100 | Length-weighted mean walk score along the quality-optimal route. The experienced quality. |
low_share | Double | 0–1 | Fraction of route length on segments scoring below LOW_THRESHOLD. 0 = the entire route is above threshold; 0.5 = half the route is on poor streets. |
n_edges | Integer | 1+ | Number of street segments in the route. |
Symbolic Representation
Map routes by detour with a diverging RdYlGn ramp (reversed:
green = detour ~1.0, red = detour ≥ 1.4). Line width 0.3 mm, opacity 40% for
bundling. The visual story is the divergence between the shortest and quality
paths — where many routes take the same detour onto a pleasant alternative, that
alternative street emerges as a thick green bundle even if the underlying street
network is thin. For the "all pairs" mode, filter to a single origin and colour
by dest categorically to see which destinations a quality-conscious
pedestrian at that origin would prefer.
Interpretation Guide
The three diagnostic regimes
| Regime | detour | low_share | Interpretation |
|---|---|---|---|
| Ideal | ~1.0 | ~0 | The shortest path is already high-quality. No intervention needed — the network serves this OD pair well. |
| Escapable | ≥1.3 | ~0 | The direct route is poor, but a good-quality alternative exists a reasonable detour away. The pedestrian can escape. Action: improve the direct route to close the quality gap — this is the highest-return investment because it eliminates the detour for every user on this corridor. |
| Trapped | ~1.0 | >0.3 | The direct route is poor AND there is no better alternative — every route from origin to destination forces the pedestrian onto low-quality streets. Action: this is the most urgent intervention case. The trapped routes identify missing-link investments: a new cut-through, a pedestrian bridge, or a street upgrade that creates a quality alternative where none exists. |
Cross-references with other PlanX tools
- Walkability Audit / Street Environment Comfort: the quality
score source. Run with both
walk_scoreandcomfortindependently and compare — where routes diverge, meso-scale walkability and micro-scale comfort disagree about the best path. - OD Cost Matrix / OD Routes: the plain shortest-path
baseline. The
shortest_mfield in this tool's output matchesnet_costin the OD Cost Matrix output for the same OD pair. - Link Criticality: cross-reference trapped-route corridor segments with criticality scores. A segment that is both a quality trap AND a single point of failure (high criticality) is the highest-risk pedestrian infrastructure in the network.
- Space Syntax: high-NACH segments that score low on walkability and appear as trapped routes suggest a configurational problem — the grid naturally funnels movement onto a segment that is hostile to pedestrians. This is the severance pattern (a major through-route dividing a neighbourhood) and requires a structural response (crossings, median refuges, traffic calming) rather than a cosmetic one.
Pitfalls
- Penalty calibration. There is no universal "correct" penalty. $p = 0.5$ models a mildly quality-sensitive pedestrian; $p = 2.0$ models someone who will go far out of their way to avoid poor streets. For planning purposes, test $p \in \{0.5, 1.0, 2.0\}$ and report the range: "between X% and Y% of school routes are trapped regardless of penalty." Stable findings across the range are robust; findings that flip at a threshold need sensitivity analysis.
- Score provenance. The quality score inherits all limitations
of the tool that produced it. If the Walkability Audit was run without a
land-use layer, the
s_mixcomponent was skipped andwalk_scoremay overrate streets in monofunctional areas. If Street Environment Comfort was run without tree-point data, it cannot penalise treeless streets. Audit the score's component completeness before interpreting routes. - Network completeness. A "trapped" finding may be an artefact of an incomplete network: if the only quality alternative uses a footpath that is not in the network, the router cannot find it and declares a trap where none exists on the ground. Always verify trapped findings with field observation or aerial imagery before recommending major investments.
- Edge effects. Routes near the network boundary may appear trapped because alternatives lie outside the study area. Buffer the network by at least one neighbourhood beyond the actual study area.
Academic References
Guo, Z. & Loo, B.P.Y. (2013). "Pedestrian Environment and Route Choice: Evidence from New York City and Hong Kong." Journal of Transport Geography, 28, 124–136. DOI: 10.1016/j.jtrangeo.2012.11.010
Agrawal, A.W., Schlossberg, M., & Irvin, K. (2008). "How Far, by Which Route and Why? A Spatial Analysis of Pedestrian Preference." Journal of Urban Design, 13(1), 81–98. DOI: 10.1080/13574800701804074
Leslie, E., Coffee, N., Frank, L., Owen, N., Bauman, A., & Hugo, G. (2007). "Walkability of Local Communities: Using Geographic Information Systems to Objectively Assess Relevant Environmental Attributes." Health & Place, 13(1), 111–122. DOI: 10.1016/j.healthplace.2005.11.001
Borst, H.C., de Vries, S.I., Graham, J.M.A., van Dongen, J.E.F., Bakker, I., & Miedema, H.M.E. (2009). "Influence of Environmental Street Characteristics on Walking Route Choice of Elderly People." Journal of Environmental Psychology, 29(4), 477–484. DOI: 10.1016/j.jenvp.2009.08.002
Ortúzar, J. de D. & Willumsen, L.G. (2011). Modelling Transport. 4th ed., Wiley. (Chapter 7: "Route Choice and Traffic Assignment" — the generalised-cost framework from which the quality-penalty model is derived.) DOI: 10.1002/9781119993308
3. Urban Morphology
The Urban Morphology group quantifies the physical form of the city at three scales: the building (shape metrics, orientation, courtyard index, shared-wall ratio), the plot (morphological tessellation as a cadastral proxy via Voronoi partitioning), and the block (Spacematrix density indicators GSI/FSI/OSR/L and street-network morphology via orientation entropy, meshedness indices, and junction typology).
Building Form Metrics
Processing ID: planx:buildingformmetrics
1. Theoretical Background
1.1 Academic Lineage
Building form metrics translate the geometric properties of individual footprint polygons into numerical descriptors of typology, construction era, and spatial organisation. The intellectual foundation draws from three traditions. First, classical Euclidean geometry contributed the isoperimetric inequality — the circle maximises area for a given perimeter, giving rise to the isoperimetric quotient (IPQ) as a compactness measure that has been used in urban morphology since at least the 1960s (Haggett & Chorley, 1969). Second, computational geometry furnished efficient algorithms for the minimum bounding rectangle via Toussaint's (1983) rotating calipers, enabling orientation and rectangularity to be computed in $O(k)$ time on a convex hull of $k$ vertices. Third, Batty & Longley (1994) demonstrated that fractal geometry could quantify the complexity of building footprints — their observation that organic urban fabric yields higher fractal dimensions than planned modernist fabric remains the standard interpretive frame.
1.2 Methodology Evolution
The systematic computation of building-level morphology metrics was catalysed by the release of open building footprint datasets (OpenStreetMap, national cadastral agencies) and the development of the momepy toolkit (Fleischmann, 2019). Prior to momepy, researchers computed these metrics in ad-hoc scripts; momepy standardised the vocabulary and computation. Fleischmann, Romice & Porta (2020) later provided the theoretical framework connecting single-building metrics to multi-scale urban form analysis, arguing that "spatial signatures" — combinations of metrics across scales — are the proper unit of morphological comparison rather than any single indicator.
1.3 Key Assumptions and Limitations
All metrics operate on the largest part of multi-polygon footprints, discarding detached annexes. Metrics are scale-invariant (ratios of areas and lengths) except area and perimeter which are absolute. The shared-wall computation uses a simple spatial index intersection test; it does not detect topological adjacency from a common cadastral polygon, so it may over-count walls separated by narrow gaps. The fractal dimension formula $D = 2\ln(P/4)/\ln(A)$ is valid for simple closed shapes but produces unreliable values for highly irregular perimeters below ~1 m². All metrics require a projected CRS; results in geographic coordinates are meaningless.
1.4 Use Cases
- Building typology classification: cluster on (compact, elongation, sharedwall, court_idx) to produce unsupervised typology maps.
- Energy modelling: IPQ and elongation are strong predictors of heating/cooling load per m² — complex envelopes lose more energy.
- Historical fabric detection: fractal dimension and corner count identify organic pre-industrial fabric versus planned grid fabric.
- Data quality audit: anomalously high corner counts on simple buildings flag over-digitised data; missing courtyards flag incomplete data.
- Plan analysis: compare mean metrics between existing fabric and proposed fabric to quantify morphological change.
2. Mathematical Formulation
Let $R = \{(x_1, y_1), \ldots, (x_n, y_n)\}$ denote the exterior ring of a building footprint, with $x_{n+1} = x_1$ and $y_{n+1} = y_1$ for closure. Let interior rings (courtyards) be denoted $I_1, \ldots, I_m$. All metrics are computed in projected map units (metres).
where $A_{hull}$ is the area of the convex hull computed via Andrew's monotone chain algorithm; $L$ and $W$ are the length and width of the minimum-area rotated rectangle obtained by the rotating calipers method on the convex hull; the orientation $\theta \in [0, 180)$ is the angle of $L$ from the positive $x$-axis; $D_{fractal}$ is set to 0 when the logarithm arguments are invalid; $\partial B_i$ denotes the boundary of building $i$; $N(i)$ is the set of neighbour buildings whose bounding box intersects building $i$; and $\ell$ measures the intersection length of boundary curves.
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
BUILDINGS | Vector (Polygon) | Yes | — | Building footprints. Must use a projected CRS with metric units. Multi-polygons supported; metrics are computed on the largest part only. |
OUTPUT | Vector (Polygon) | — | — | Output layer with original attributes plus all 12 computed shape indicators. |
4. Output Description
| Field | Type | Range | Description |
|---|---|---|---|
area_m2 | Double | $\geq 0$ | Net building area (exterior minus courtyards) in square metres |
perim_m | Double | $\geq 0$ | Exterior perimeter in metres |
compact | Double | $[0, 1]$ | Isoperimetric quotient. 1 = perfect circle, ~0.785 = square, decreasing with complexity |
convexity | Double | $[0, 1]$ | Ratio of exterior area to convex hull area. 1 = convex polygon |
rectang | Double | $[0, 1]$ | Ratio of exterior area to minimum rotated bounding rectangle area. ~1 = near-rectangular slab |
elongation | Double | $[0, 1)$ | $1 - W/L$. 0 = square plan; approaching 1 = long thin bar (row housing, industrial sheds) |
orient_deg | Double | $[0, 180)$ | Orientation of the long axis in degrees from east (positive x). 0 = east-west; 90 = north-south |
court_m2 | Double | $\geq 0$ | Total courtyard area (sum of interior ring areas), in square metres |
court_idx | Double | $[0, 1)$ | Courtyard area / exterior area. > 0.05 = significant courtyard typology |
fractal | Double | $\sim$[1.0, 1.5] | Fractal dimension. 1.0 = simple rectangle; > 1.3 = highly complex perimeter |
corners | Integer | $\geq 3$ | Number of vertices whose deflection angle exceeds 10° |
sharedwall | Double | $[0, 1]$ | Fraction of perimeter intersecting neighbouring buildings. 0 = detached; > 0.3 = attached fabric |
5. Interpretation Guide
5.1 Benchmark Ranges
| Metric | Detached Villa | Row House | Perimeter Block | Slab Tower | Industrial Shed |
|---|---|---|---|---|---|
| compact | 0.4–0.7 | 0.6–0.8 | 0.3–0.5 | 0.7–0.85 | 0.8–0.95 |
| elongation | 0.2–0.5 | 0.6–0.85 | 0.1–0.3 | 0.1–0.3 | 0.7–0.95 |
| sharedwall | 0.0–0.05 | 0.2–0.5 | 0.1–0.4 | 0.0 | 0.0–0.1 |
| court_idx | 0.0 | 0.0–0.02 | 0.05–0.3 | 0.0 | 0.0 |
| fractal | 1.05–1.15 | 1.02–1.08 | 1.05–1.20 | 1.01–1.05 | 1.01–1.03 |
5.2 Spatial Patterns
- Orientation clustering: strong uni-modal peaks in
orient_degat street-parallel angles indicate grid-aligned fabric; uniform distributions indicate free-form layouts (post-war estates, organic growth). Styleorient_degwith a categorical colour ramp to detect fabric boundaries where the prevailing grain shifts. - Compactness core-periphery: historic cores typically show low
compact(complex footprints, wings and annexes); post-war suburbs show highcompact(simple rectangular slabs). A gradient from low to high compactness moving outward marks the morphological frontier between pre-modern and modern fabric. - Shared-wall gradients: continuous high
sharedwallin a district = attached terraced fabric; sudden drops to zero = morphological boundary (gap sites, detached infill, or a new development regime).
5.3 Cross-References
- Feed
area_m2andperim_minto energy models (envelope-to-floor ratio = perim / area, a proxy for heat loss per m²). - Combine
orient_degwith Street Network Morphology orientation order: buildings with orientation diverging from the street grid identify morphological outliers. - Use
sharedwallwith Morphological Tessellation cell area to distinguish organic medieval fabric (small cells, high sharedwall) from modernist estates (large cells, zero sharedwall). - Feed the full metric set into Spacematrix Density as building attributes; the typology classification adds a qualitative layer to the quantitative GSI/FSI/OSR indicators.
5.4 Common Pitfalls
- Geographic CRS: using lat/lon produces area and perimeter values in decimal-degree units, which are meaningless. The tool emits a warning but does not block execution.
- Over-digitised data: hundreds of corners on a simple rectangular house indicate a CAD import that preserved every curve vertex. Filter using
corners < 6 AND rectangularity > 0.95: buildings passing this test should have 4 corners; any with > 20 corners are over-digitised. - Multi-polygon buildings: only the largest part is measured. Detached garages and outbuildings are ignored. If these are critical, split the building into separate features first.
- Shared-wall false positives: walls separated by < 1 mm due to digitising tolerance will register as shared. Check anomalously high sharedwall on detached villas by inspecting the source data.
6. Symbolic Representation
Recommended QGIS styling:
- compact: Graduated, 5 classes (Jenks), green (high) to red (low). Low compactness = complex footprints = higher envelope cost.
- elongation: Graduated, blue ramp. High elongation = long bars. Add a rotation marker symbol sized by elongation, rotated by
orient_deg, to visualise grain. - sharedwall: Categorised: 0 = grey (detached), 0–0.1 = light blue (touching), 0.1–0.3 = medium blue (semi-detached), >0.3 = dark blue (attached/terraced).
- court_idx: Graduated, 0 = transparent, >0.05 = orange. Identifies courtyard-typology buildings at a glance.
- orient_deg: Categorised into 8 compass sectors (N, NE, E, SE, S, SW, W, NW) using a qualitative colour scheme (Set3 or Pastel1).
7. Literature
✓ Fleischmann, M. (2019). "momepy: Urban Morphology Measuring Toolkit." Journal of Open Source Software, 4(43), 1807. DOI: 10.21105/joss.01807
✓ Fleischmann, M., Romice, O. & Porta, S. (2020). "Measuring urban form: Overcoming terminological inconsistencies for a quantitative and comprehensive morphologic analysis of cities." Environment and Planning B, 48(8), 2133–2150. DOI: 10.1177/2399808320910444
✓ Toussaint, G.T. (1983). "Solving geometric problems with the rotating calipers." Proceedings of IEEE MELECON '83, Athens, A10.02/1–4.
✓ Batty, M. & Longley, P. (1994). Fractal Cities: A Geometry of Form and Function. Academic Press. ISBN: 978-0124555709.
✓ Haggett, P. & Chorley, R.J. (1969). Network Analysis in Geography. Edward Arnold. ISBN: 978-0713154597.
✓ Steadman, P. (2014). "Building types and built forms." Journal of Space Syntax, 5(1), 1–22.
Morphological Tessellation
Processing ID: planx:morphologicaltessellation
1. Theoretical Background
1.1 Academic Lineage
Morphological tessellation addresses a fundamental data problem in urban morphology: cadastral plot boundaries are often unavailable, proprietary, or inconsistent across jurisdictions, yet they are the natural analysis unit for density, coverage, and typology studies. The method implemented here follows the momepy toolkit (Fleischmann, 2019), which in turn builds on the concept of "spatial proximity polygons" from computational geometry. The core idea — partitioning space so that every point is assigned to its nearest building — originates from Voronoi (1908) but gained urban application through the work of Boffet & Rocca Serra (2001) on "morphological envelopes" and was systematised by Fleischmann, Romice & Porta (2020) into the standard momepy workflow: shrink buildings to prevent gap competition, densify boundaries to generate smooth partitioning lines, construct the Voronoi diagram, dissolve cells per building, and clip to a study area boundary.
1.2 Methodology and Key Decisions
Three design choices critically affect the output. Shrink distance: buildings are buffered inward before seeding to prevent adjacent buildings whose footprints nearly touch from competing over the narrow gap between them — without shrinking, the tessellation boundary bisects the gap, producing implausibly thin cells. A typical shrink of 0.4 m works for modern cadastral data; increase to 1–2 m for hand-digitised historic maps where buildings bleed into each other. Densify spacing: the Voronoi diagram is computed from boundary seed points, not from building centroids, so the cell boundaries can follow the shape of the building. Denser seeds produce cells that more closely approximate a setback-based plot proxy but increase computation time quadratically. Clip mask: cells at the study area edge are artificially truncated. For any cell-level statistic (mean area, Gini of cell sizes), exclude the outer ring of border-touching cells, or supply a study area generously larger than the analysis area.
1.3 Use Cases and Limitations
- Plot-proxy construction: the primary use — enable plot-level analysis (GSI, FSI, coverage ratios) when cadastral data is unavailable.
- Grain analysis: cell area distribution quantifies urban grain. Uniform small cells = organic medieval or fine-grained gridded fabric; a few giant cells amid many small = campus or estate typology; uniform large cells = modernist superblock planning.
- Limitations: (a) tessellation cannot detect administrative plot boundaries — two buildings on one legal plot will be separated; (b) buildings very close together (< 2x shrink distance) may produce degenerate cells; (c) the method assumes buildings are the primary spatial organisers — large open spaces (parks, brownfields, water) must be supplied via the mask layer; (d) industrial sheds with complex footprints produce fragmented seed patterns; increase densify spacing for these.
2. Mathematical Formulation
Let $B = \{b_1, \ldots, b_n\}$ be the set of building footprint polygons in a projected CRS. For each building $b_k$, let $\partial b_k$ denote its exterior ring. The workflow proceeds in five stages:
Let $P = \bigcup_{k=1}^{n} S_k$ be the set of all seed points, with each point $p \in P$ tagged by its originating building index $k(p)$. The standard Voronoi tessellation assigns each point in the plane to its nearest seed:
Cells belonging to the same building are dissolved (union), then clipped to the study area mask $M$:
where the study area mask $M$ is either a user-supplied boundary polygon or the convex hull of all building seed points buffered by $d_{limit}$:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
BUILDINGS | Vector (Polygon) | Yes | — | Building footprints. Must be in a projected CRS with metric units. At least 3 buildings required. |
STUDY_AREA | Vector (Polygon) | No | — | Boundary polygon to clip cells. When omitted, the convex hull of all buildings buffered by LIMIT is used. Supply a boundary generously larger than the analysis area to avoid edge artefacts. |
SHRINK | Double | — | 0.4 | Inward buffer distance for building footprints in map units (metres). Prevents adjacent buildings from competing over narrow gaps. Increase for hand-digitised data; set to 0 for perfectly separated modern footprints. Minimum: 0.0. |
DENSIFY | Double | — | 2.0 | Maximum spacing between seed points along building boundaries in map units. Smaller values produce smoother, more accurate cell boundaries at the cost of longer computation. Minimum: 0.1. |
LIMIT | Double | — | 100.0 | Buffer distance added to the auto-generated study area (convex hull of all buildings). Ignored when STUDY_AREA is provided. Minimum: 1.0. |
OUTPUT | Vector (Polygon) | — | — | Tessellation cells with original building attributes, cell_id, and cell_m2. |
4. Output Description
| Field | Type | Description |
|---|---|---|
cell_id | Long | Index of the generating building (0-based). Used to join tessellation cells back to buildings. |
cell_m2 | Double | Cell area in square metres after clipping to study area. Edge cells will have smaller values than interior cells. |
| (inherited) | — | All attributes from the source building layer are copied to the corresponding cell. |
5. Interpretation Guide
5.1 Benchmark Patterns
- Uniform small cells (50–300 m²): fine-grained organic or grid fabric, buildings closely spaced, narrow gaps. Typical of historic centres.
- Uniform medium cells (300–1000 m²): planned gridded fabric, regular setbacks. Typical of 19th–early 20th century expansion districts.
- Mixed small + a few giant cells (> 5000 m²): campuses, shopping centres, or estate buildings in an otherwise fine-grained context. The giant cells flag institutional or commercial land-uses.
- Uniform large cells (1000–5000 m²): modernist superblock planning with generous setbacks. Low coverage ratios expected.
5.2 Cross-References
- Feed cells directly into Spacematrix Density as the BLOCKS input: tessellation cells + Spacematrix = plot-level GSI/FSI without cadastral data.
- Combine
cell_m2with Building Form Metricsarea_m2to compute cell-level coverage ratio (area_m2/cell_m2), a proxy for plot coverage. - Use cells as the denominator for dasymetric population distribution — more accurate than administrative units because cells respect building geometry.
- Feed cell geometry into Street Network Morphology contextual analysis: cell size variance between districts quantifies morphological grain.
5.3 Common Pitfalls
- Edge effect: cells intersecting the study area boundary are artificially truncated. Always identify and exclude border cells before computing cell area statistics. A practical rule: exclude cells whose
cell_m2is less than 50% of the median interior cell area. - Too many seeds: with small densify spacing and large building footprints, seed counts can exceed 100,000. The QGIS Voronoi implementation may fail silently. Start with the default 2.0 m and only reduce if cell boundaries are visibly jagged.
- Degenerate shrink: buildings smaller than 2x shrink distance may disappear after shrinking. The tool falls back to the original geometry, but such buildings will produce disproportionately large cells.
- Multi-part buildings: each part is processed independently. A building with detached annexes will generate multiple cells. This is typically desired behaviour but be aware when computing per-building statistics.
6. Symbolic Representation
Recommended QGIS styling:
- cell_m2: Graduated, 5 classes (Natural Breaks), light yellow (small) to dark brown (large). Small cells = fine grain; large cells = coarse grain. Add 50% transparency to see the underlying buildings.
- Coverage ratio (calculated): Graduated, 5 classes, green (low coverage, porous) to red (high coverage, compact). Over 0.5 = dense urban; under 0.15 = suburban or campus.
- Edge detection: select cells where
cell_m2< 0.5 * median cell area; style these with a dashed outline to flag them for exclusion from statistics.
7. Literature
✓ Fleischmann, M. (2019). "momepy: Urban Morphology Measuring Toolkit." Journal of Open Source Software, 4(43), 1807. DOI: 10.21105/joss.01807
✓ Fleischmann, M., Romice, O. & Porta, S. (2020). "Measuring urban form: Overcoming terminological inconsistencies for a quantitative and comprehensive morphologic analysis of cities." Environment and Planning B, 48(8), 2133–2150. DOI: 10.1177/2399808320910444
✓ Boffet, A. & Rocca Serra, S. (2001). "Identification of spatial structures within urban blocks for town characterisation." Proceedings of the 20th International Cartographic Conference, Beijing, 1974–1983.
✓ Voronoi, G. (1908). "Nouvelles applications des parametres continus a la theorie des formes quadratiques." Journal fur die Reine und Angewandte Mathematik, 134, 198–287.
✓ Aurenhammer, F. (1991). "Voronoi diagrams — a survey of a fundamental geometric data structure." ACM Computing Surveys, 23(3), 345–405. DOI: 10.1145/116873.116880
Spacematrix Density
Processing ID: planx:spacematrixdensity
1. Theoretical Background
1.1 Academic Lineage
The Spacematrix method was developed by Meta Berghauser Pont and Per Haupt at TU Delft, first published in their 2010 book Spacematrix: Space, Density and Urban Form and revised in an open-access 2023 edition. The method addresses a long-standing problem in urban planning: density is typically regulated through a single number (Floor Area Ratio, FAR, or Floor Space Index, FSI), but a given FSI can describe completely different urban forms depending on how much ground the building occupies (GSI) and how tall it is (L). By jointly analysing FSI, GSI, OSR (Open Space Ratio), and L (mean number of floors), the Spacematrix captures four independent degrees of freedom that together define the built density typology of any urban fabric.
1.2 The Spacematrix Diagram
The method's central analytical device is the Spacematrix diagram: a scatter plot with GSI on the horizontal axis and FSI on the vertical axis. Any built form occupies a single point. Lines of constant L radiate from the origin (FSI = L * GSI). Curves of constant OSR are hyperbolic. The diagram reveals that planning codes which only specify FSI and GSI implicitly fix L (since L = FSI/GSI), and vice versa: a plan demanding FSI 2.0 at GSI 0.2 silently demands 10 storeys (L = 10), which may conflict with height limits or neighbourhood character policies. OSR = (1 - GSI)/FSI measures the open space cost of each built square metre: OSR < 0.5 signals pressure on public space; OSR > 1.5 signals spacious suburban fabric.
1.3 Typology Classification
The 10-class Spacematrix label combines a height category (Low-rise: L < 3; Mid-rise: 3 <= L <= 6; High-rise: L > 6) with a coverage category (compact: GSI >= 0.35; moderate: 0.15 <= GSI < 0.35; spacious: GSI < 0.15). The three by three grid produces nine built classes plus "Unbuilt" for blocks with no intersection area. The labels provide a standardised vocabulary: "Mid-rise compact" describes the classic European perimeter block (4-6 storeys, 40-60% coverage); "High-rise spacious" describes tower-in-park Modernist schemes; "Low-rise spacious" describes detached suburban housing.
1.4 Key Assumptions and Limitations
- Intersection splitting: buildings that cross block boundaries are split proportionally by area. This is correct for area-based metrics (GSI, FSI) but introduces slight error in distributed building counts.
- Single floor count: each building has one floor count value. Mixed-use buildings with different floor counts per part should be split before processing.
- Block geometry: the tool assumes blocks are non-overlapping polygons. Overlapping or nested blocks produce double-counted area.
- CRS requirement: all area computations use the CRS of the blocks layer, which must be projected with metric units.
2. Mathematical Formulation
Let $B = \{b_1, \ldots, b_N\}$ index a set of building footprint polygons, each with known floor count $n_i$. Let $A_k$ be the area of block (analysis unit) $k$. Let $A_{i,k}^{int} = \text{Area}(b_i \cap \text{block}_k)$ be the intersection area of building $i$ with block $k$. The Spacematrix indicators for block $k$ are:
The Spacematrix class label $C_k$ is determined by discretising GSI and L:
where $f(\text{GSI}) = \text{"compact"}$ if $\text{GSI} \geq 0.35$, $\text{"moderate"}$ if $0.15 \leq \text{GSI} < 0.35$, and $\text{"spacious"}$ if $\text{GSI} < 0.15$.
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
BUILDINGS | Vector (Polygon) | Yes | — | Building footprints. Must be in a projected CRS. Multi-polygons supported; area is computed on the geometry as stored. |
LEVELS_FIELD | Field (Numeric) | No | — | Field containing the number of floors per building. When empty, DEFAULT_LEVELS is used for all buildings. |
DEFAULT_LEVELS | Double | — | 2.0 | Default floor count applied when LEVELS_FIELD is empty or for buildings with invalid values. Minimum: 0.0. Use 1.0 for single-storey fabric; 2.0 for typical detached housing. |
BLOCKS | Vector (Polygon) | Yes | — | Analysis unit polygons. Can be administrative blocks, census tracts, Morphological Tessellation cells, or any custom polygon layer. Must be in a projected CRS. Non-overlapping recommended. |
OUTPUT | Vector (Polygon) | — | — | Blocks with Spacematrix indicators and class labels appended. |
4. Output Description
| Field | Type | Range | Description |
|---|---|---|---|
b_count | Integer | $\geq 0$ | Number of buildings intersecting the block (may be fractional if buildings cross multiple blocks) |
fp_m2 | Double | $\geq 0$ | Total building footprint area within the block, in square metres |
gfa_m2 | Double | $\geq 0$ | Total gross floor area = $\sum$ footprint area $\times$ floors, in square metres |
gsi | Double | $[0, 1]$ | Ground Space Index = footprint area / block area. Coverage ratio. 0.35+ = compact urban fabric |
fsi | Double | $\geq 0$ | Floor Space Index (equivalent to FAR) = gross floor area / block area. Dimensionless density measure |
osr | Double | $\geq 0$ | Open Space Ratio = $(1-\text{GSI})/\text{FSI}$. m² of open space per m² of floor area. < 0.5 = pressure on public space |
levels | Double | $\geq 0$ | Mean number of floors = FSI/GSI. The average height implied by the combined density and coverage |
smx_class | String | — | 10-class Spacematrix label: {Low, Mid, High}-rise {compact, moderate, spacious} + "Unbuilt" |
5. Interpretation Guide
5.1 Benchmark Typologies
| Typology | GSI | FSI | L | OSR | Label |
|---|---|---|---|---|---|
| Detached suburban | 0.05–0.15 | 0.1–0.3 | 1.5–2.5 | 1.5–5.0 | Low-rise spacious |
| Row housing | 0.20–0.40 | 0.5–1.2 | 2.5–3.5 | 0.5–1.5 | Low/Mid-rise compact |
| Perimeter block (European) | 0.35–0.55 | 1.5–3.0 | 4–6 | 0.2–0.5 | Mid-rise compact |
| Slab estate (Modernist) | 0.10–0.25 | 0.8–2.0 | 6–12 | 0.4–1.2 | High-rise moderate |
| Tower in park | 0.03–0.10 | 1.0–3.0 | 15–40 | 0.3–1.0 | High-rise spacious |
| Historic core | 0.50–0.80 | 2.0–5.0 | 3–8 | 0.05–0.25 | Low/Mid-rise compact |
5.2 Reading the Spacematrix Diagram
Plot FSI versus GSI for all blocks in the study area. The arrangement of points reveals:
- Clustering along a ray from the origin: uniform height, varying coverage. Indicates a single building typology at different densities.
- Vertical scatter at fixed GSI: varying height on fixed footprints. Typical of areas where zoning fixes coverage but not height.
- Empty quadrants: typologies absent from the fabric. A plan that introduces them represents a morphological departure.
- Points above L = 6 + GSI > 0.35: high-density compact — often the most walkable and infrastructure-efficient typology, but also the most challenged for daylight and open space.
5.3 Cross-References
- Use Morphological Tessellation cells as the BLOCKS input for plot-level Spacematrix without cadastral data.
- Combine with Building Form Metrics: cluster buildings by (compact, elongation, sharedwall), then compute Spacematrix per cluster to quantify the density of each typology.
- Feed OSR into Heat Island Risk Grid context: low OSR + low green fraction = high heat risk from lack of both open space and vegetation.
- Compare proposed plan FSI/GSI pairs against existing fabric benchmarks: a proposal whose (GSI, FSI) lies far outside the existing point cloud requires justification.
5.4 Common Pitfalls
- Zero FSI / zero GSI: blocks with no intersecting building area produce FSI = GSI = 0. OSR = 0/0 is set to 0.0. These blocks are labelled "Unbuilt" regardless of their actual open-space function.
- Including streets in blocks: blocks defined as street-bounded polygons naturally include the street area in the denominator. GSI and FSI will be lower than plot-level values. Use tessellation cells for plot-level equivalents.
- Floor count field empty or invalid: values that fail to parse as float silently fall back to
DEFAULT_LEVELS. A building with 10 storeys recorded as text "10F" will be treated as 2-storey. Verify the field type before running.
6. Symbolic Representation
Recommended QGIS styling:
- smx_class: Categorised, 10 classes. Use a diverging colour scheme: blues for spacious, greens for moderate, oranges/reds for compact. "Unbuilt" in light grey with 50% transparency.
- fsi: Graduated, 5 classes (Quantile), light yellow (low density) to dark red (high density). Useful as a standalone density map.
- gsi: Graduated, 5 classes, light green (low coverage) to dark brown (high coverage). Reveals the footprint of built form independent of height.
- Spacematrix diagram: Use QGIS Data Plotly or export to Python for a GSI vs FSI scatter with L isolines.
7. Literature
✓ Pont, M.B. & Haupt, P. (2023). Spacematrix: Space, Density and Urban Form (Revised ed.). TU Delft OPEN Publishing. DOI: 10.59490/mg.38
✓ Berghauser Pont, M. & Haupt, P. (2010). Spacematrix: Space, Density and Urban Form. NAi Publishers, Rotterdam. ISBN: 978-9056627423.
✓ Berghauser Pont, M. & Haupt, P. (2007). "The relation between urban form and density." Urban Morphology, 11(1), 62–65.
✓ Dovey, K. & Pafka, E. (2014). "The urban density assemblage: Modelling multiple measures." Urban Design International, 19(1), 66–76. DOI: 10.1057/udi.2013.13
✓ Boyko, C.T. & Cooper, R. (2011). "Clarifying and re-conceptualising density." Progress in Planning, 76(1), 1–61. DOI: 10.1016/j.progress.2011.07.001
✓ Fleischmann, M. (2019). "momepy: Urban Morphology Measuring Toolkit." Journal of Open Source Software, 4(43), 1807. DOI: 10.21105/joss.01807
Street Network Morphology
Processing ID: planx:streetnetworkmorphology
1. Theoretical Background
1.1 Academic Lineage
Street network morphology quantifies the structural properties of the street graph — bearing orientations, connectivity, and node typology — in a single analytical pass. The intellectual foundation draws from two traditions. First, graph theory provides the meshedness indices ($\alpha$, $\beta$, $\gamma$) developed by Kansky (1963) for transport network analysis and refined for planar graphs. These indices answer the question: how close is this network to being maximally connected, given its number of nodes? Second, Boeing (2019) introduced orientation entropy and orientation order as a systematic method to quantify how "grid-like" a street network is, using information theory: entropy measures the diversity of street bearings, and order normalises this against the theoretical limits of a perfect four-direction grid ($H_g = \ln 4$) and a completely uniform distribution ($H_{max} = \ln 36$ for 36 directional bins).
1.2 Methodology
Street bearings are computed as the compass angle of each edge's start-to-end vector, made bidirectional ($\theta$ and $\theta + 180^\circ$) because streets are undirected for morphological purposes. The bidirectional bearings are binned into 36 sectors of $10^\circ$ each, centred on $0^\circ$ (North). Boeing weights each bearing by its edge length, so long arterial segments contribute more to the orientation profile than short cul-de-sac stubs. The length-weighted histogram is converted to a probability distribution $p_b$, and Shannon entropy is computed. The orientation order $\phi$ normalises this entropy to $[0, 1]$: $\phi = 1$ for a perfect orthogonal grid (all edges in exactly 4 directions), $\phi \approx 0$ for a network whose bearings are uniformly distributed (random or organic).
Meshedness is measured by three classic planar-graph ratios. $\alpha$ (alpha index) measures the ratio of actual to maximum possible cycles (circuitry): an $\alpha$ of 0 means a tree (no cycles), while $\alpha$ approaching 1 means a maximally circuited planar network. $\beta$ (beta index) is edges per node — values below 1 indicate disconnected components, values near 2 indicate a fully connected planar grid. $\gamma$ (gamma index) measures the ratio of actual to maximum possible edges in a planar graph.
1.3 Use Cases and Limitations
- Neighbourhood comparison: profile different districts and compare their morphological signatures — a high-$\phi$, high-$\alpha$ district is gridded and well-connected; a low-$\phi$, low-$\alpha$ district is organic and tree-like.
- Plan tracking: run on each iteration of a street layout to trend $\alpha$ and intersection density — objective evidence that connectivity is improving or degrading.
- Data quality: more than one connected component = the network is disconnected. Run Prepare Network first to fix topology before morphological analysis.
- Limitations: indices are highly scale-dependent — comparing a 1 km² neighbourhood to a 100 km² city requires normalisation by area. The orientation order is sensitive to the bin count; 36 bins is standard for degree-scale resolution. Curved streets approximated as single line segments lose intermediate bearing information; densify the network first for organic street patterns.
2. Mathematical Formulation
Let $G = (V, E)$ be a planar graph representing the street network, with $n = |V|$ nodes and $e = |E|$ edges. Let $p$ be the number of connected components of $G$. Edge $j$ has length $\ell_j$ and bidirectional bearing $\theta_j \in [0, 360)$.
where $A_{hull}$ is the area (in km²) of the convex hull of all network nodes, used as the denominator for intersection density. Connected components are identified via depth-first search on the adjacency representation. $\alpha$ is clamped to $[0, \infty)$ and $\gamma$ to $[0, \infty)$; negative values (possible when $n$ is very small) are set to 0.
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
NETWORK | Vector (Line) | Yes | — | Street network line layer. Must be in a projected CRS. Topologically connected (run Prepare Network first). |
NODES | Vector (Point) | — | — | Output: junction point layer with degree and typology classification. |
SUMMARY | Vector (Table) | — | — | Output: attribute-less table with 15 network-wide indicators as (metric, value) rows. |
4. Output Description
4.1 Junction Layer (NODES)
| Field | Type | Description |
|---|---|---|
node_id | Integer | Zero-based node index |
degree | Integer | Number of edges incident at this node. 1 = dead-end; 2 = continuation; 3+ = intersection |
node_type | String | "cul-de-sac" (degree=1), "continuation" (degree=2), or "intersection" (degree>=3) |
4.2 Summary Table (SUMMARY)
| Metric | Description | Example Value |
|---|---|---|
nodes | Total distinct intersection/endpoint nodes | 1247 |
edges | Total street segments (edges in the graph) | 1893 |
components | Number of disconnected sub-graphs. 1 = fully connected network | 1 |
total_length_km | Sum of all edge lengths in kilometres | 142.6 |
avg_segment_length_m | Mean edge length in metres. ~80-120 m supports pedestrian permeability | 95.3 |
avg_node_degree | Mean degree across all nodes. ~1.4 = suburban tree; ~2.0 = dense grid | 1.87 |
intersections_deg3plus | Count of true intersections (degree >= 3) | 412 |
culdesac_count | Count of dead-end nodes (degree = 1) | 287 |
culdesac_ratio | Fraction of nodes that are dead-ends | 0.23 |
intersection_density_km2 | True intersections per km² of convex hull area | 35.6 |
alpha_meshedness | Alpha index: degree of circuitry. 0 = tree; higher = more looped/redundant | 0.182 |
beta_index | Beta index: edges per node. ~1.0 = tree; ~2.0 = fully gridded | 1.52 |
gamma_index | Gamma index: ratio of edges to maximum planar edges | 0.51 |
orientation_entropy_nats | Shannon entropy of length-weighted bearing distribution. ln(4)~1.386 = grid; ln(36)~3.584 = uniform | 2.14 |
orientation_order | Normalised orientation order [0,1]. ~1 = perfect grid; ~0 = random/organic | 0.62 |
5. Interpretation Guide
5.1 Benchmark Values
| Indices | Tree-like Suburb | Organic Medieval | 19th-C Grid | Modernist Superblock | Dense Downtown Grid |
|---|---|---|---|---|---|
| $\alpha$ | 0.00–0.05 | 0.05–0.15 | 0.15–0.25 | 0.05–0.12 | 0.20–0.35 |
| $\beta$ | 1.05–1.20 | 1.30–1.55 | 1.55–1.80 | 1.25–1.45 | 1.70–1.95 |
| $\phi$ | 0.10–0.30 | 0.05–0.25 | 0.70–0.95 | 0.20–0.50 | 0.65–0.90 |
| Cul-de-sac ratio | 0.30–0.60 | 0.05–0.15 | 0.02–0.10 | 0.10–0.25 | 0.02–0.08 |
| Int. density/km² | 5–15 | 30–80 | 50–120 | 10–25 | 80–200 |
5.2 Spatial Patterns
- $\phi$ jump at district boundary: two planning eras meeting. The boundary itself may be a morphological seam — a ring road, railway, or institutional barrier.
- Cul-de-sac clusters + high $\phi$: planned suburban "loops and lollipops" — gridded at the collector scale, dendritic at the local scale. The high $\phi$ comes from the collector grid; the cul-de-sac ratio reveals the local structure.
- $\alpha$ < 0.05 + $\phi$ < 0.15: unplanned or topographically constrained fabric. Could be informal settlement, steep terrain, or pre-automobile organic growth. Not necessarily bad — historic organic fabric often has high pedestrian permeability despite low vehicle-network meshedness.
5.3 Cross-References
- Combine with Network Centrality: a well-meshed network ($\alpha$ > 0.2) with low betweenness centralisation distributes traffic evenly; a tree-like network concentrates it on a few arterials.
- Feed
avg_segment_length_minto walkability assessment: segments > 200 m indicate blocks too large for pedestrian permeability, regardless of network connectivity. - Compare orientation order with Building Form Metrics
orient_degdistribution: aligned peaks = street-parallel buildings; offset peaks = buildings ignoring the grid (post-war estates).
5.4 Common Pitfalls
- Disconnected network: multiple components ($p$ > 1) usually indicates dangling segments or topological gaps. Run Prepare Network first. A single-component network is required for meaningful $\alpha$ and $\gamma$.
- Curvilinear streets as single edges: a curved crescent entered as one line produces a single bearing, understating orientation diversity. Densify the network if $\phi$ seems implausibly high for known organic fabric.
- Node degree 2 dominance: if most nodes are "continuation," the network has been digitised with breaks at every vertex. Simplifying or dissolving redundant nodes will sharpen the cul-de-sac/intersection classification.
6. Symbolic Representation
Recommended QGIS styling:
- Junction layer: Categorised by
node_type: cul-de-sac = red circle (size 3), continuation = grey circle (size 2, 50% transparent), intersection = blue circle (size 4). Intersection density becomes visible at small scale; cul-de-sac clusters at large scale. - Bearings polar histogram: use the QGIS "Diagram" overlay on the network layer with a pie chart showing edge bearing per segment, or export bearing data to Python for a rose diagram (length-weighted).
- Summary table: display as an attribute table in the layout; annotate each value with its benchmark range for the reader.
7. Literature
✓ Boeing, G. (2019). "Urban spatial order: street network orientation, configuration, and entropy." Applied Network Science, 4(1), 67. DOI: 10.1007/s41109-019-0189-1
✓ Marshall, S. (2004). Streets and Patterns. Routledge. DOI: 10.4324/9780203589397
✓ Kansky, K.J. (1963). "Structure of transportation networks." University of Chicago, Department of Geography, Research Paper No. 84.
✓ Porta, S., Crucitti, P., & Latora, V. (2006). "The Network Analysis of Urban Streets: A Primal Approach." Environment and Planning B, 33(5), 705–725. DOI: 10.1068/b32045
✓ Southworth, M. & Ben-Joseph, E. (2003). Streets and the Shaping of Towns and Cities. Island Press. ISBN: 978-1559639163.
4. Accessibility
Multi-Amenity Access Score (15-Minute City)
Processing ID: planx:multiamentiyaccess
1. Theoretical Background
1.1 Academic Lineage
The 15-minute city concept, popularised by Moreno et al. (2021) but with roots in Perry's (1929) "neighbourhood unit" and Doxiadis's (1968) "human community" scale, proposes that all daily needs — work, food, health, education, leisure, and culture — should be reachable within a 15-minute walk or cycle from home. The concept entered mainstream planning discourse during the COVID-19 pandemic, when restricted mobility revealed how unequally distributed local amenities are. This algorithm provides the quantitative indicator behind the concept: a composite score that measures, for every residential location, how many amenity categories are within walking distance on the real street network.
1.2 Methodology
The algorithm runs one multi-source Dijkstra shortest-path search per amenity category. All amenity points in a category are treated as source nodes with zero initial distance; the algorithm propagates outward on the street network, recording the shortest path distance from any amenity in that category to every network node. This is more efficient than running one-to-one Dijkstra for every origin-amenity pair and captures the "nearest facility of type X" semantics exactly. Travel time is computed as network distance divided by walking speed (default 4.8 km/h = 80 m/min, the conventional adult walking speed from transportation engineering). The composite score for each origin is the percentage of amenity categories whose nearest representative is within the time threshold.
1.3 The Composite Score
The score is intentionally simple: it counts categories, not amenities within categories. A location near one supermarket scores the same as a location near ten supermarkets for the "shops" category. This conservative design means the score measures minimum service diversity — the presence of each service type — rather than service abundance or quality. A score of 100 means every defined category has at least one representative within the threshold; it says nothing about capacity, quality, or choice. To capture abundance, run the tool separately with a shorter threshold or complement with the Facility Adequacy algorithm.
1.4 Key Assumptions and Limitations
- Network-based only: access is measured on the street network. Pedestrian paths, parks, and informal routes not in the network are invisible to the algorithm.
- Nearest amenity of each category: the tool finds the minimum travel time to any amenity in a category. It does not allocate demand to capacity — for that, use Facility Adequacy.
- Snapping tolerance: origins and amenities are snapped to the nearest network node. If an origin is 200 m from the nearest network edge, its travel times will be overestimated by that approach distance.
- Edge cost = length: all edges are assumed walkable at uniform speed. The tool does not model pedestrian crossing delays, gradient, footpath quality, or safety.
- 2x threshold reporting limit: times beyond double the threshold are reported as -1 (unreachable) to bound the Dijkstra search radius.
2. Mathematical Formulation
Let $\mathcal{C} = \{C_1, \ldots, C_K\}$ be the set of amenity categories, each with a point layer of amenity locations. Let $G = (V, E)$ be the street network graph with edge lengths as costs, and let $v_{walk} = 4.8$ km/h be the walking speed. The distance-to-time conversion is:
For category $C_k$, let $S_k \subset V$ be the set of network nodes nearest to amenity locations in $C_k$. A multi-source Dijkstra from $S_k$ yields the shortest-path distance from any node $v \in V$ to the nearest amenity of category $k$:
For origin $o$ with nearest network node $v_o$, the travel time to the nearest amenity of category $k$ is:
The number of categories reachable within threshold $T$ (default 15 minutes) and the composite score are:
The population-weighted mean score, when a population field is provided:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ORIGINS | Vector (Any) | Yes | — | Demand points (building centroids, address points, parcel centroids). Snapped to nearest network node. |
NETWORK | Vector (Line) | Yes | — | Street network. Must be in a projected CRS. Topologically connected (run Prepare Network first). |
AMENITIES | Multiple layers | Yes | — | One or more point/polygon layers, each representing one amenity category. Layer names become field tokens (t_schools, t_parks, etc.). |
POP_FIELD | Field (Numeric) | No | — | Population count per origin. When provided, the log outputs population-weighted mean score, share with full access, and share with zero access. |
SPEED | Double | — | 4.8 | Walking speed in km/h. 4.8 = healthy adult; 3.6 = elderly/child; 5.0 = brisk. Minimum: 0.5. |
THRESHOLD | Double | — | 15.0 | Time threshold in minutes. 15 = standard 15-minute city; 10 = dense urban core; 20 = suburban. Minimum: 1.0. |
OUTPUT | Vector (Point) | — | — | Output point layer with original attributes, per-category travel times, n_reach, and score. |
4. Output Description
| Field | Type | Range | Description |
|---|---|---|---|
t_<category> | Double | $-1$ to $2T$ | Walking minutes to the nearest amenity of that category. -1 = no amenity reachable within 2x threshold (abbreviated from layer name, e.g. t_schools) |
n_reach | Integer | $[0, K]$ | Number of amenity categories with travel time $\leq$ threshold |
score | Double | $[0, 100]$ | Percentage of categories within threshold. 100 = all categories; 0 = none within threshold |
| (inherited) | — | — | All attributes from the origin layer are preserved |
5. Interpretation Guide
5.1 Score Benchmarks
- Score = 100: complete 15-minute neighbourhood — every defined amenity category has at least one representative within the threshold. These locations are walkable for all daily needs.
- Score 60–80: liveable but incomplete. Identify the specific missing categories from the
t_*fields — the shortfall is a service gap, not a generalised "low access." - Score 20–40: heavily car-dependent. Residents cannot walk to most daily services. Check whether the missing categories are far (all
t_*> 2T) or just beyond threshold (one or two at 16-18 min). - Score = 0: no amenity of any category within 2x threshold. These locations are effectively unserviced by walking.
5.2 Diagnosing the Cause
- One category far everywhere: a systemic service gap (e.g. no clinics in the study area). The fix is a new facility, not a new street.
- All categories slightly over threshold (16–20 min): a network detour problem — origins are separated from amenities by barriers (highways, railways, water) that the network must route around. Check for missing pedestrian links.
- Sharp boundary in score: a physical or administrative barrier — a motorway, railway, or district boundary that the street network does not cross. These are the highest-priority locations for new pedestrian bridges or crossings.
5.3 Cross-References
- Feed the output into Accessibility Equity to test whether low scores concentrate in vulnerable population groups — the 15-minute city score identifies the gap; equity analysis identifies who lives in it.
- Combine with Walking Slope to add gradient realism: filter out origins whose paths exceed a slope threshold.
- Use with Facility Adequacy: a category may be within 15 minutes but overloaded. Access score + adequacy = complete service assessment.
- Test a proposed facility site by adding it as a new point in the relevant amenity layer and rerunning: the delta in
scoreper origin quantifies the benefit.
5.4 Common Pitfalls
- Too few categories: with only 2 categories, score jumps in 50-point increments, losing discrimination. Use at least 5 categories for meaningful scoring.
- Network disconnected from origins: origins far from network edges snap to the nearest node, but the straight-line approach distance is not walked. Check that all origins are within ~50 m of a network edge.
- Walking speed mismatch: 4.8 km/h assumes unimpeded adult walking. For elderly accessibility assessment, use 3.6 km/h. For cycling access, a separate bicycle network analysis is needed.
6. Symbolic Representation
Recommended QGIS styling:
- score: Graduated, 6 classes: 0 (dark red), 1–39 (red), 40–59 (orange), 60–79 (yellow), 80–99 (light green), 100 (dark green). This maps directly to the car-dependent / liveable / complete framework.
- n_reach: Categorised, one colour per integer 0 through K. Useful as an ordinal complement to the continuous score.
- Per-category minutes: Graduated, 5 classes (0-T, T-2T, over 2T), from green through yellow to grey (-1). Shows which specific service is missing where.
- Population-weighted map: size symbols by population, colour by score. The resulting map directly shows where the most people experience low access.
7. Literature
✓ Moreno, C., Allam, Z., Chabaud, D., Gall, C., & Pratlong, F. (2021). "Introducing the '15-Minute City': Sustainability, Resilience and Place Identity in Future Post-Pandemic Cities." Smart Cities, 4(1), 93–111. DOI: 10.3390/smartcities4010006
✓ Handy, S.L. & Niemeier, D.A. (1997). "Measuring Accessibility: An Exploration of Issues and Alternatives." Environment and Planning A, 29(7), 1175–1194. DOI: 10.1068/a291175
✓ Vale, D. & Lopes, A.S. (2023). "Accessibility inequality across Europe: a comparison of 15-minute pedestrian accessibility in cities with 100,000 or more inhabitants." npj Urban Sustainability, 3, 55. DOI: 10.1038/s42949-023-00133-w
✓ Perry, C.A. (1929). "The Neighborhood Unit." In: Regional Survey of New York and Its Environs, Vol. 7, pp. 22–140. Regional Plan of New York and Its Environs.
✓ Geurs, K.T. & van Wee, B. (2004). "Accessibility evaluation of land-use and transport strategies: review and research directions." Journal of Transport Geography, 12(2), 127–140. DOI: 10.1016/j.jtrangeo.2003.10.005
✓ Talen, E. & Anselin, L. (1998). "Assessing Spatial Equity: An Evaluation of Measures of Accessibility to Public Playgrounds." Environment and Planning A, 30(4), 595–613. DOI: 10.1068/a300595
✓ Ewing, R. & Cervero, R. (2010). "Travel and the Built Environment: A Meta-Analysis." Journal of the American Planning Association, 76(3), 265–294. DOI: 10.1080/01944361003766766
5. Microclimate
Ten screening-quality environmental tools powered by an embedded NOAA solar position model (±0.5° accuracy) and UMEP-style array-shifting shadow casts. These are screening tools, not regulatory compliance models.
Shadow Casting (DSM)
Processing ID: planx:shadowcasting
1. Theoretical Background
1.1 Academic Lineage
Shadow casting from digital surface models (DSMs) is the computational core of urban solar-access analysis. The method implemented here follows Ratti & Richens (1999), who demonstrated that standard image-processing techniques — specifically iterative array shifting — could compute shadow patterns from raster DSMs orders of magnitude faster than ray-tracing, making city-scale shadow studies feasible on desktop computers. This approach was adopted by the Urban Multi-scale Environmental Predictor (UMEP) plugin (Lindberg et al., 2018), which remains the most widely used urban climate tool in QGIS. The solar position is computed using the NOAA simplified algorithm (Reda & Andreas, 2004), which achieves accuracy well under 0.5 degrees for the years 1900–2100 — more than sufficient for urban shadow studies where building height uncertainty is typically a larger error source.
1.2 The Array-Shifting Method
The algorithm works on the principle that a DSM cell $(x, y)$ is in shadow if any cell along the line of sight toward the sun, when projected forward, stands higher than the ground at $(x, y)$. Operationally, the DSM array is shifted toward the sun in discrete pixel steps. At step $i$, the shifted DSM is lowered by $i \cdot \Delta s \cdot \tan\alpha$, where $\Delta s$ is pixel size and $\alpha$ is solar altitude. If the lowered shifted surface at any step exceeds the original DSM at $(x, y)$, that cell is flagged as shadowed. The search radius is capped at $\min(\text{relief}/\tan\alpha,\; \text{raster\_diagonal})$ — beyond this distance, terrain features cannot cast a shadow on the cell because the ground itself intercepts the ray.
1.3 Use Cases and Limitations
- Rights-to-light: a single run at Dec 21 noon answers whether a proposed building casts shadow on a specific garden or window at the legally relevant moment.
- Public space audit: batch multiple hours to map shaded/sunlit plazas, playgrounds, and bus stops through the day.
- Before/after differencing: run on existing DSM, run on proposed DSM, subtract — the non-zero cells show exactly which terrain the new massing shadows.
- Limitations: (a) binary shadow/no-shadow; penumbra and diffuse light are not modelled; (b) DSM must include building heights — a DTM (bare earth) produces no building shadows; (c) the method assumes a flat ground between DSM cells — on very steep terrain with large pixels, shadow boundary accuracy degrades; (d) at solar altitudes below ~3°, the search radius becomes very large and the computation slow.
2. Mathematical Formulation
Let $\mathbf{D} \in \mathbb{R}^{H \times W}$ be the DSM array with pixel size $\Delta s$ (metres). Let $\alpha$ be the solar altitude (degrees above horizon) and $A$ the solar azimuth (degrees clockwise from north, measured as compass bearing — N = 0, E = 90, S = 180). The unit vector toward the sun in array coordinates is:
The maximum search distance (in pixel steps) is:
At each step $i = 1, \ldots, i_{max}$, the shifted and lowered DSM is:
The shadow mask $\mathbf{S}$ is the Boolean array where any shifted surface exceeds the original:
NaN cells in the DSM are excluded from the shadow computation. If $\alpha \leq 0$ (sun below horizon), all cells are flagged as shadow.
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
DSM | Raster | Yes | — | Digital Surface Model including terrain + buildings. Must be in a projected CRS with metric pixel size. NaN cells are excluded from computation. |
WHEN | DateTime | Yes | — | Date and local clock time at the site. Combined with UTC_OFFSET to derive solar position. |
UTC_OFFSET | Double | — | 0.0 | Hours from UTC. Critical: 14:00 local time with +3 offset = 11:00 UTC. Range: [-14, 14]. |
MAX_SEARCH | Double | — | 0.0 | Maximum shadow casting distance in map units. 0 = auto-compute from DSM relief and solar altitude. Set a value to limit computation for very low sun. |
OUTPUT | Raster (Byte) | — | — | Output raster: 1 = shadow, 0 = sunlit, 255 = NoData (DSM NaN cells). |
4. Output Description
| Value | Meaning | Interpretation |
|---|---|---|
| 0 | Sunlit | The cell receives direct beam radiation at this instant |
| 1 | In cast shadow | The cell is in shadow cast by terrain or buildings. It may still receive diffuse sky radiation |
| 255 | NoData | The DSM had NaN at this cell (water, raster edge). Excluded from computation |
The log reports ShadowedShare — the fraction of valid DSM cells in shadow. This single number characterises a time-of-day: 0.15 at noon means 15% of the scene is shadowed; 0.85 near sunset means most of the scene is in shadow.
5. Interpretation Guide
5.1 Critical Planning Dates
- December 21 (winter solstice): lowest sun, longest shadows. The standard date for rights-to-light assessment. The 2-hour mid-day window (e.g. 11:00–13:00) is the minimum solar access period in many regulations.
- March 20 / September 22 (equinoxes): typical conditions. Used for general solar-access planning and daylight factor proxies.
- June 21 (summer solstice): highest sun, shortest shadows. For heat studies, shadow here is a cooling asset — identify the spaces that lose all shade on the hottest day.
5.2 Before/After Differencing
Run on existing DSM (baseline), run on proposed DSM (scenario). Subtract: cells where baseline=0 and scenario=1 are the NEW shadow cast by the proposal. These cells identify affected properties, gardens, and public spaces. The affected area in m² is the key exhibit for planning objections or approvals.
5.3 Cross-References
- Batch run with Sun Hours: shadow casting handles one instant; Sun Hours integrates the full day.
- Feed shadow patterns into Solar Irradiation which adds the energy dimension: a shadowed cell at 15:00 loses more energy in summer than in winter because beam irradiance is higher.
- Overlay Dec-21 noon shadow on building footprints: buildings whose entire roof is shadowed at winter solstice are poor candidates for rooftop PV.
5.4 Common Pitfalls
- Wrong UTC offset: the most common error. 15:00 with offset 0 when the site is actually UTC+3 places the sun at 18:00 local time — three hours late. Always verify the log reports a plausible solar altitude for the stated local time.
- DTM instead of DSM: a bare-earth DTM produces terrain shadows only. Buildings will not cast shadows because their heights are absent from the raster. For urban shadow studies, use a DSM that includes building heights.
- Geographic CRS: the pixel size must be in metres. A DSM in WGS84 (EPSG:4326) where pixel size = 0.00001 degrees produces wildly incorrect shadow lengths.
6. Symbolic Representation
Recommended QGIS styling:
- Binary: 0 = fully transparent, 1 = black at 60% opacity, 255 = no colour. Overlay on the DSM hillshade for immediate readability.
- Before/after difference: -1 (lost sun) = red, 0 (unchanged) = transparent, 1 (new shadow) = dark blue. The red cells demand attention.
7. Literature
✓ Lindberg, F., Grimmond, C.S.B., et al. (2018). "Urban Multi-scale Environmental Predictor (UMEP) — An integrated tool for city-based climate services." Environmental Modelling & Software, 99, 70–87. DOI: 10.1016/j.envsoft.2017.09.020
✓ Reda, I. & Andreas, A. (2004). "Solar position algorithm for solar radiation applications." Solar Energy, 76(5), 577–589. DOI: 10.1016/j.solener.2003.12.003
✓ Ratti, C. & Richens, P. (1999). "Urban Texture Analysis with Image Processing Techniques." In: Augenbroe, G. & Eastman, C. (eds.), Computers in Building, pp. 49–64. Springer. DOI: 10.1007/978-1-4615-5047-1_4
✓ Ratti, C., Di Sabatino, S. & Britter, R. (2006). "Urban texture analysis with image processing techniques: winds and dispersion." Theoretical and Applied Climatology, 84, 77–90. DOI: 10.1007/s00704-005-0146-z
✓ Rich, P.M. (1990). "Characterizing plant canopies with hemispherical photographs." Remote Sensing Reviews, 5(1), 13–29. DOI: 10.1080/02757259009532119
✓ Muneer, T. (2004). Solar Radiation and Daylight Models (2nd ed.). Elsevier. ISBN: 978-0750659741.
Sky View Factor (DSM)
Processing ID: planx:skyviewfactor
1. Theoretical Background
1.1 Academic Lineage
Sky View Factor (SVF) is the fraction of the overlying hemisphere visible from a point on the ground — the single most important geometric control on urban microclimate. Oke (1981) first established the quantitative link between urban canyon geometry and nocturnal cooling rates, showing that SVF reduction from buildings is the primary cause of the urban heat island (UHI) through its effect on longwave radiation trapping. The computational method employed here follows Johnson & Watson (1984), who demonstrated that SVF can be computed from horizon elevation angles at equally spaced azimuths: $\text{SVF} = 1 - \frac{1}{N}\sum \sin^2\beta_i$, where $\beta_i$ is the maximum horizon elevation angle in direction $i$. This formulation avoids integration over the full hemisphere and is numerically identical to the geometric definition of the view factor from a differential planar surface element to the sky.
1.2 Physical Significance
SVF controls two opposing energy fluxes. During the day, high SVF means more solar radiation reaches the surface (heating), but also more longwave radiation escapes to the cold sky (cooling). At night, SVF is purely a cooling control: a surface with SVF = 0.9 radiates longwave energy to a sky at approximately -50 degrees C (effective sky temperature), while a surface with SVF = 0.3 radiates mostly to warm building walls at +20 to +30 degrees C, resulting in net nocturnal heating. This explains the classic observation that street canyons are 2-8 K warmer than nearby open country at night, but may be cooler during the day if deeply shaded.
1.3 Methodology and Key Choices
The algorithm scans the DSM outward from each cell in $N$ equally spaced azimuths (default 16). For each direction, it finds the maximum horizon elevation angle $\beta$ — the steepest angle from horizontal to any obstructing DSM cell along that ray, up to the search radius. The SVF per cell is then computed from the $N$ horizon angles. More directions produce smoother results (16 for screening, 32 for publication, 64 for research). The search radius must be large enough to capture the tallest obstruction that can affect the cell; for a 100 m tower, a radius of at least 100 m is needed. The default 100 m is appropriate for urban blocks; increase for tall-building districts or terrain with significant relief.
1.4 Use Cases and Limitations
- UHI screening: SVF < 0.5 in continuous corridors indicates potential nocturnal heat trapping. Combine with Heat Island Risk Grid for comprehensive screening.
- Daylight availability: SVF correlates with daylight factor — a courtyard with SVF 0.3 receives approximately 30% of the vertical sky component available in an open field.
- Cool roof / green infrastructure targeting: low-SVF streets benefit most from reflective surfaces (cool pavements) because longwave radiation has nowhere to escape.
- Limitations: (a) assumes isotropic sky radiance — in reality, the circumsolar region is brighter; (b) the scan is restricted to a finite radius; obstructions beyond it are invisible; (c) vegetation (tree canopies) must be in the DSM to affect SVF; a bare-earth DSM plus extruded buildings will overestimate SVF in treed streets.
2. Mathematical Formulation
For a cell at position $(r, c)$ in the DSM array with pixel size $\Delta s$, let $N$ be the number of equally spaced azimuth directions (default 16). For direction $d \in \{0, \ldots, N-1\}$, the scan direction is:
The maximum terrain elevation encountered at step $i$ (distance $i \cdot \Delta s$) relative to the cell is:
where $(\Delta r_i, \Delta c_i)$ are the integer row and column offsets at step $i$. The maximum horizon angle in direction $d$ over all steps $i = 1, \ldots, i_{max}$ is:
The sky view factor, using the identity $\sin^2(\arctan t) = t^2/(1+t^2)$, is:
For a perfectly flat plane without obstructions ($\beta_{max}^{(d)} = 0$ for all $d$), SVF = 1.0. For a cell at the foot of an infinitely high wall ($\beta_{max}^{(d)} = 90^\circ$ for half the azimuths), SVF = 0.5. For a cell in a deep symmetric canyon, SVF asymptotically approaches:
where $H$ is building height and $W$ is canyon width. A 20 m deep, 15 m wide canyon has theoretical SVF $\approx$ 0.36.
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
DSM | Raster | Yes | — | Digital Surface Model including terrain + buildings + vegetation. Must be in a projected CRS with metric pixel size. |
DIRECTIONS | Integer | — | 16 | Number of equally spaced azimuth scan directions. 16 = screening quality; 32 = publication; 64 = research (slow). Range: [4, 64]. |
RADIUS | Double | — | 100.0 | Maximum search distance in map units (metres). Must exceed the height of the tallest obstruction that can affect the cell. Minimum: 1.0. |
OUTPUT | Raster (Float32) | — | — | Output raster: SVF values in [0, 1]. -9999 = NoData (NaN cells in DSM). |
4. Output Description
| Value Range | Morphology | Microclimate Significance |
|---|---|---|
| 0.95–1.00 | Open field, large plaza, rooftop | Maximum nocturnal cooling (coldest at night). Full solar access but no shade. High diurnal temperature range |
| 0.70–0.95 | Wide street, suburban, park edge | Good ventilation and daylight. Moderate cooling. Typical of low-rise suburbs |
| 0.50–0.70 | Typical urban street, courtyard | Reduced longwave loss. Nighttime 1–3 K warmer than open field. Adequate daylight |
| 0.30–0.50 | Dense urban canyon, narrow alley | Strong longwave trapping. 3–5 K warmer at night. Daylight restricted — supplementary lighting likely needed |
| 0.10–0.30 | Very deep canyon, arcade, tunnel | Maximum heat trapping. > 5 K nocturnal warming. Daylight negligible. These spaces function as covered passages |
5. Interpretation Guide
5.1 Spatial Patterns to Identify
- Continuous low-SVF corridors: linear features with SVF < 0.4 along several blocks. These are systematic nocturnal heat traps — the highest-priority targets for cool-roof, tree-canopy, or albedo interventions.
- SVF gradients: SVF decreasing toward the urban core marks the morphological UHI footprint. The gradient's steepness indicates the rate of rural-to-urban transition; an abrupt cliff signals a hard urban edge (motorway, greenbelt boundary).
- Courtyard SVF: interior courtyard SVF should be ~0.3–0.6 for traditional perimeter blocks. Lower values suggest over-deepening by adjacent tall buildings; zero SVF in a courtyard is a daylight and ventilation failure.
- Street orientation bias: N-S streets in northern latitudes show asymmetric SVF (lower on the southern side of the street, shaded by buildings on the south). This asymmetry governs microclimate more than the mean SVF alone.
5.2 Cross-References
- Combine with Heat Island Risk Grid: low SVF + high built fraction + low green fraction = maximum heat risk. The SVF contribution isolates the geometric (radiation trapping) mechanism from the surface-cover mechanism.
- Feed SVF into Solar Irradiation as the diffuse-light weight: the tool's
USE_SVFoption multiplies diffuse irradiance by cell SVF, producing more realistic street-level radiation than an isotropic sky assumption. - Use with Frontal Area Index: low SVF + high $\lambda_f$ (frontal area) = a canyon that both traps radiation and blocks wind — the worst-case combination for summer heat stress.
5.3 Common Pitfalls
- Insufficient search radius: a 100 m search radius cannot see a 200 m tower 150 m away. The computed SVF near tall buildings will be overestimated (too much sky visible). Set radius to at least 2x the tallest building height.
- Coarse directions: 4 or 8 directions produce visible stair-stepping artefacts in the SVF map. Minimum 16 for screening; 32 for any quantitative use.
- DSM without vegetation: tree canopies are obstructions. A DSM from LiDAR that includes vegetation yields lower (more realistic) SVFs than a bare-earth + extruded-buildings DSM.
6. Symbolic Representation
Recommended QGIS styling:
- SVF: Singleband pseudocolour, diverging: 0.0 = deep purple (fully enclosed), 0.3 = dark blue, 0.5 = yellow, 0.7 = light green, 1.0 = white (fully open). The thermal interpretation is intuitive: purple = heat trap, white = cold sink.
- For publication: 10-class equal interval from 0.0 to 1.0. Annotate each bin with its morphological description (canyon, street, open, etc.).
7. Literature
✓ Oke, T.R. (1981). "Canyon geometry and the nocturnal urban heat island: Comparison of scale model and field observations." Journal of Climatology, 1(3), 237–254. DOI: 10.1002/joc.3370010304
✓ Johnson, G.T. & Watson, I.D. (1984). "The Determination of View-Factors in Urban Canyons." Journal of Climate and Applied Meteorology, 23(2), 329–335. DOI: 10.1175/1520-0450(1984)023<0329:TDOVFI>2.0.CO;2
✓ Oke, T.R. (1982). "The energetic basis of the urban heat island." Quarterly Journal of the Royal Meteorological Society, 108(455), 1–24. DOI: 10.1002/qj.49710845502
✓ Stewart, I.D. & Oke, T.R. (2012). "Local Climate Zones for Urban Temperature Studies." Bulletin of the American Meteorological Society, 93(12), 1879–1900. DOI: 10.1175/BAMS-D-11-00019.1
✓ Grimmond, C.S.B., Potter, S.K., Zutter, H.N. & Souch, C. (2001). "Rapid methods to estimate sky-view factors applied to urban areas." International Journal of Climatology, 21(7), 903–913. DOI: 10.1002/joc.659
✓ Hammerle, M., Gal, T., Unger, J. & Matzarakis, A. (2011). "Comparison of models calculating the sky view factor used for urban climate investigations." Theoretical and Applied Climatology, 105, 521–527. DOI: 10.1007/s00704-011-0402-3
Frontal Area Index
Processing ID: planx:frontalareaindex
1. Theoretical Background
1.1 Academic Lineage
Frontal Area Index ($\lambda_f$) and Plan Area Index ($\lambda_p$) are the standard urban roughness parameters introduced by Grimmond & Oke (1999) for characterising the aerodynamic properties of urban surfaces. Grimmond & Oke demonstrated that these two morphological parameters, computed from building footprint and height data, can predict the zero-plane displacement height ($z_d$) and roughness length ($z_0$) — the key parameters in boundary-layer wind models — with accuracy comparable to wind-tunnel measurements. The method has since become the primary morphological input to urban wind and dispersion models, including the operational ADMS-Urban and SIRANE models.
1.2 Physical Meaning
$\lambda_f$ measures the total wind-facing facade area of buildings per unit ground area. For a given wind direction $\theta$ (the compass bearing the wind comes FROM), each building contributes its projected width perpendicular to the wind, multiplied by its height: $F_i = w_{proj,i} \cdot h_i$. Summed over all buildings intersecting a grid cell and normalised by cell area, $\lambda_f$ quantifies how much the built fabric "catches" the wind — a sail-area analogy. $\lambda_p$ is simpler: total building footprint area per unit ground area (coverage). The ratio $\lambda_f / \lambda_p = \bar{h} \cdot \bar{w}_{proj} / \bar{A}_{fp}$ relates the aerodynamic to the geometric footprint of buildings.
1.3 Urban Ventilation Corridors
In urban climate planning, $\lambda_f$ maps are used to identify and protect ventilation corridors — continuous bands of low $\lambda_f$ aligned with the prevailing breeze direction. These corridors channel cooling air from rural surroundings (or large urban parks) into the city core. The operational workflow is: (a) determine the prevailing summer daytime wind direction from local meteorological data; (b) compute $\lambda_f$ with that direction; (c) identify continuous low-$\lambda_f$ paths connecting cool source areas to hot target areas; (d) keep new construction out of these paths in the zoning plan.
1.4 Use Cases and Limitations
- Ventilation corridor mapping: run with prevailing summer breeze direction to locate the airflow paths that keep hot districts cool.
- Urban roughness classification: $\lambda_f$ categorises urban terrain into Davenport roughness classes, from "open" ($\lambda_f$ < 0.1) to "very rough" ($\lambda_f$ > 0.5).
- Wind-damage screening: high $\lambda_f$ cells perpendicular to storm wind direction identify facades at risk of wind loading.
- Limitations: (a) $\lambda_f$ is a grid-cell average — it does not capture street-level channelling or funnelling effects; (b) single wind direction per run — run separately for multiple directions to characterise directional roughness; (c) height data must be per-building (field or default); (d) the method does not account for porosity between buildings — a solid wall and a row of pillars at the same $\lambda_f$ produce completely different flow fields.
2. Mathematical Formulation
Let $\mathcal{B}$ be the set of building footprint polygons, each with height $h_i$ (metres). Let the wind direction be $\theta$ degrees from North (the bearing the wind comes FROM). For building $i$ with exterior ring vertices $(x_j, y_j)$, the projected width perpendicular to the wind is:
The frontal area of building $i$ is:
For a grid cell $c$ with area $A_{cell}$, the intersection share of building $i$ is $s_{i,c} = \text{Area}(b_i \cap c) / \text{Area}(b_i)$. The frontal area index and plan area index for cell $c$ are:
Only cells containing at least one building are emitted (sparse grid output). The roughness class thresholds are:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
BUILDINGS | Vector (Polygon) | Yes | — | Building footprints. Must be in a projected CRS. Multi-polygons use the largest part only. |
HEIGHT_FIELD | Field (Numeric) | No | — | Building height in metres. When empty, DEFAULT_HEIGHT is used for all buildings. |
DEFAULT_HEIGHT | Double | — | 6.0 | Default height in metres when no height field is provided. Typical: 3–6 m (1–2 storeys) for residential; 10–20 m for mixed-use. Minimum: 0.1. |
WIND_DIR | Double | — | 0.0 | Wind direction in degrees from North (bearing wind comes FROM). 0 = north wind, 90 = east wind, 180 = south wind. Range: [0, 360]. |
CELL_SIZE | Double | — | 100.0 | Grid cell side length in map units. 100 m = neighbourhood-scale roughness; 50 m = street-scale. Minimum: 10.0. |
OUTPUT | Vector (Polygon) | — | — | Sparse grid of built cells with $\lambda_f$, $\lambda_p$, building count, and cell ID. |
4. Output Description
| Field | Type | Description |
|---|---|---|
cell_id | Integer | Zero-based grid cell identifier |
b_count | Integer | Number of buildings intersecting the cell |
lambda_f | Double | Frontal area index: wind-facing facade area per unit ground area. < 0.1 = open; > 0.3 = blocked |
lambda_p | Double | Plan area index: footprint coverage. Useful alongside $\lambda_f$ to separate dense-but-low from porous-but-tall fabric |
5. Interpretation Guide
5.1 Reading the $\lambda_f$ / $\lambda_p$ Relationship
- High $\lambda_p$ + low $\lambda_f$: dense but low (shopping strips, industrial sheds). The wind sees low roughness despite high coverage because building heights are small.
- Low $\lambda_p$ + high $\lambda_f$: porous but tall (tower clusters). The wind encounters tall obstacles at wide spacing — channelling and wake effects dominate. These behave completely differently for ventilation than dense-low fabric.
- Directional variation: run with wind at $0^\circ$ (north), $90^\circ$ (east), and the prevailing direction. Delta $\lambda_f$ between directions reveals directional porosity: a fabric with $\lambda_f$(north)=0.08 and $\lambda_f$(east)=0.35 is permeable to north winds but blocks east winds.
5.2 Ventilation Corridor Detection
- Continuous low-$\lambda_f$ band: $\lambda_f$ < 0.1 for > 500 m in a direction within $\pm 30^\circ$ of the prevailing breeze = a functional ventilation corridor. Protect it from infill development.
- Barrier detection: a line of cells with $\lambda_f$ > 0.3 perpendicular to the breeze = a wind dam. The area downwind of this barrier (further from the wind source) may be a hot spot due to reduced ventilation.
5.3 Cross-References
- Combine with Sky View Factor: low SVF + high $\lambda_f$ identifies canyons that both trap radiation and block wind — dual-mechanism heat stress.
- Use with Heat Island Risk Grid: add $\lambda_f$ as a contextual layer to distinguish radiation-trap UHI from ventilation-trap UHI.
- Run after Building Form Metrics: use
orient_degto check whether building orientations align with or oppose the prevailing breeze.
6. Symbolic Representation
- lambda_f: Graduated, 5 classes (0–0.05, 0.05–0.10, 0.10–0.20, 0.20–0.30, >0.30), blue = open to red = blocked. Wind direction shown as an arrow symbol in the layout legend.
- lambda_p: Graduated, from light green (low coverage) to dark brown (high coverage). Display alongside $\lambda_f$ for the density-vs-roughness comparison.
7. Literature
✓ Grimmond, C.S.B. & Oke, T.R. (1999). "Aerodynamic Properties of Urban Areas Derived from Analysis of Surface Form." Journal of Applied Meteorology, 38(9), 1262–1292. DOI: 10.1175/1520-0450(1999)038<1262:APOUAD>2.0.CO;2
✓ Ratti, C., Di Sabatino, S. & Britter, R. (2006). "Urban texture analysis with image processing techniques: winds and dispersion." Theoretical and Applied Climatology, 84, 77–90. DOI: 10.1007/s00704-005-0146-z
✓ Ng, E., Yuan, C., Chen, L., Ren, C. & Fung, J.C.H. (2011). "Improving the wind environment in high-density cities by understanding urban morphology and surface roughness." Landscape and Urban Planning, 101(1), 59–74. DOI: 10.1016/j.landurbplan.2011.01.004
✓ Macdonald, R.W., Griffiths, R.F. & Hall, D.J. (1998). "An improved method for the estimation of surface roughness of obstacle arrays." Atmospheric Environment, 32(11), 1857–1864. DOI: 10.1016/S1352-2310(97)00403-2
✓ Oke, T.R., Mills, G., Christen, A. & Voogt, J.A. (2017). Urban Climates. Cambridge University Press. DOI: 10.1017/9781139016476
Sun Hours (DSM)
Processing ID: planx:sunhours
1. Theoretical Background
1.1 Academic Lineage
Sun hours — the accumulated duration of direct sunlight at a point over a day — is the fundamental metric for solar-access planning and rights-to-light assessment. The method extends the single-instant shadow casting of Ratti & Richens (1999) into a full-day integration: the DSM is swept at a fixed time interval (default 30 minutes), and for each step where the sun is above the horizon, a shadow mask is cast using the NOAA solar position algorithm and the UMEP array-shifting method. Cells that are sunlit at a given time step accumulate $\Delta t / 60$ hours. The result is a shadow-duration map that previously required batch-running the Shadow Casting tool 24-48 times.
1.2 Regulatory Context
Many jurisdictions specify minimum direct-sun criteria for habitable rooms and open spaces. The British "BRE Site Layout Planning for Daylight and Sunlight" guide recommends that at least one main window wall of a habitable room receive 2 hours of direct sun on March 21. The German DIN 5034 specifies minimum sun duration for playgrounds. The Chinese GB 50180 requires 2 hours on the winter solstice for residential buildings. The tool enables testing any of these by selecting the relevant date and comparing per-cell hours to the threshold.
1.3 Use Cases and Limitations
- Rights-to-light assessment: run on Dec 21 or Mar 21 and overlay the 2-hour contour on building facade cells. Cells below 2 hours identify windows that fail the standard.
- Playground / garden audit: run on the relevant date and identify open spaces with < 4 hours — these need design intervention (reorienting, removing obstructions).
- PV screening: roofs with > 4 hours of winter sun are viable PV candidates before detailed energy modelling.
- Limitations: (a) time step discretisation — a 30-minute step misses shadows shorter than 30 minutes; (b) the result is accumulated hours, not continuous duration — 4 one-hour spells are reported as 4 hours, the same as a single 4-hour spell; (c) the tool reports hours on a horizontal surface — vertical surface (facade) sun hours require a different computation; (d) the NOAA solar position includes refraction, which is correct for the direct-beam shadow boundary.
2. Mathematical Formulation
Let $\mathbf{D}$ be the DSM array with pixel size $\Delta s$. For a given date at latitude $\phi$, the day is swept at $n_{steps} = \lceil 24 \times 60 / \Delta t \rceil$ time steps, where $\Delta t$ is the interval in minutes. At step $k$, the local clock time is $t_k = (k + 0.5) \times 24 / n_{steps}$ hours. The solar altitude $\alpha_k$ and azimuth $A_k$ are computed from the NOAA algorithm at UTC time $t_k - \Delta_{UTC}$:
The shadow mask $\mathbf{S}_k$ is computed for each step with $\alpha_k > 0$. The accumulated sun hours per cell are:
The site's unobstructed potential daylight is the total time the sun would be above the horizon without any building or terrain obstruction:
The ratio $\text{Hours}(r, c) / \text{Daylight}$ expresses the fraction of available sun that actually reaches the cell — a morphology-controlled solar access indicator independent of latitude and date:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
DSM | Raster | Yes | — | Digital Surface Model including terrain + buildings. Must be in a projected CRS with metric pixels. |
DATE | DateTime | Yes | — | Date for the study. Time of day component is ignored — the full day is swept. Use Dec 21 for worst-case winter; Mar 21 for equinox standard. |
UTC_OFFSET | Double | — | 0.0 | Hours from UTC at the site. Required for correct sunrise/sunset times. Range: [-14, 14]. |
INTERVAL | Double | — | 30.0 | Time step in minutes. 30 = screening balance of speed and accuracy; 15 = high accuracy; 60 = fast preview. Minimum: 5; maximum: 120. |
MAX_SEARCH | Double | — | 0.0 | Maximum shadow casting distance in map units. 0 = auto-compute. Set a value to speed computation. |
OUTPUT | Raster (Float32) | — | — | Sun hours raster. -9999 = NoData (NaN cells in DSM). |
4. Output Description
| Value Range | Interpretation | Planning Significance |
|---|---|---|
| $f_{sun} \approx 1.0$ | Unobstructed — cell receives essentially all available daylight | Rooftops, open fields. Good for PV, poor for thermal comfort without shade |
| $f_{sun} \approx 0.5$ | Half the day in shadow — typical of street-facing ground cells in mid-rise fabric | Adequate for most uses. The 50% loss is purely from surrounding buildings |
| $f_{sun} < 0.25$ | Severely obstructed — less than one quarter of available daylight reaches the cell | Deep canyons, narrow courtyards. Habitable-room windows here likely fail solar-access standards |
5. Interpretation Guide
5.1 Regulatory Benchmarks
- 2 hours on Dec 21 / Mar 21: the most common habitable room standard (BRE, DIN, GB). Cells with < 2 hours at these dates flag windows that fail the test.
- 4–6 hours on Dec 21 / Mar 21: typical playground, schoolyard, and food-garden thresholds.
- Half the open space with 2+ hours: some daylight guidelines phrase requirements at the space level rather than per cell: compute the fraction of open-space cells above the 2-hour threshold.
5.2 Seasonal Comparison
Run on both Dec 21 (winter solstice) and Jun 21 (summer solstice):
- Same cell low in both: permanently shaded — a north-facing courtyard or narrow alley.
- Low in winter, high in summer: a south-facing space shaded by a building to the south in winter (low sun) but exposed in summer (high sun). This is the pattern to avoid — it gives no sun when needed (winter) and too much when unwanted (summer).
- High in winter, lower in summer: the ideal pattern for outdoor comfort — the space gets sun when it is cold and shade when it is hot.
5.3 Cross-References
- Feed winter sun hours into Solar Irradiation screening: roofs with good sun hours are strong candidates for detailed irradiation analysis.
- Use before/after Sun Hours differencing for rights-to-light evidence: the cells that drop below the 2-hour threshold after a proposal are the affected windows.
- Combine with Building Form Metrics: buildings with south-facing long axes (orient_deg near 90 in northern hemisphere) maximise winter sun on their wider facade.
6. Symbolic Representation
- Hours: Graduated, cold (blue/purple, 0-2h) to warm (yellow/white, 8+h). The 2h and 4h contours should be visually dominant.
- $f_{sun}$ (computed): Graduated, 0.0 = dark (fully obstructed) to 1.0 = bright (fully open). Diverging at 0.5 for the half-day transition.
7. Literature
✓ Littlefair, P.J. (2001). "Daylight, sunlight and solar gain in the urban environment." Solar Energy, 70(3), 177–185. DOI: 10.1016/S0038-092X(00)00099-2
✓ Ratti, C. & Richens, P. (1999). "Urban Texture Analysis with Image Processing Techniques." In: Computers in Building, pp. 49–64. Springer. DOI: 10.1007/978-1-4615-5047-1_4
✓ Lindberg, F., Grimmond, C.S.B., et al. (2018). "Urban Multi-scale Environmental Predictor (UMEP)." Environmental Modelling & Software, 99, 70–87. DOI: 10.1016/j.envsoft.2017.09.020
✓ Reda, I. & Andreas, A. (2004). "Solar position algorithm for solar radiation applications." Solar Energy, 76(5), 577–589. DOI: 10.1016/j.solener.2003.12.003
✓ BRE (2011). Site Layout Planning for Daylight and Sunlight: A Guide to Good Practice (BR 209). BRE Press. ISBN: 978-1848061781.
Solar Irradiation (DSM)
Processing ID: planx:solarirradiation
1. Theoretical Background
1.1 Academic Lineage
Solar irradiation — the total radiant energy received per unit area — combines the geometric shadow computation with an atmospheric radiative transfer model. The beam (direct) component follows the ASHRAE clear-sky model (Masters, 2004), an empirical parameterisation widely used in building energy simulation: direct normal irradiance $DNI = A \exp(-k/\sin\beta)$ where the apparent extraterrestrial flux $A$ and optical depth $k$ vary seasonally. The diffuse component is modelled as isotropic ($DHI = C \cdot DNI$), a reasonable first-order assumption for clear-sky screening. Each cell's total irradiation sums beam (only when sunlit) plus diffuse weighted by the cell's sky view factor — a physically justified treatment that correctly reduces diffuse irradiance in street canyons.
1.2 Clear-Sky vs. All-Sky
The tool computes clear-sky irradiation — what the surface would receive under cloudless conditions. This is the correct basis for two screening tasks: (a) ranking roofs and spaces by their relative solar potential, because cloud cover affects all surfaces in a scene roughly equally (the ranking is preserved); (b) establishing an upper bound for PV yield, from which a cloudy-climate correction (typically 0.5–0.7) is applied. For absolute energy estimates, multiply clear-sky values by the local clearness index ($K_T$, the ratio of measured to clear-sky global radiation), available from TMY (Typical Meteorological Year) data or PVGIS.
1.3 Use Cases and Limitations
- PV pre-screening: rank all roof surfaces by daily irradiation on a winter date. The highest-scoring roofs are the PV candidates — feed these into specialised PV tools (PVGIS, SAM) for bankable yield estimates.
- Heat exposure screening: south-facing hardscape cells with high summer irradiation are the surfaces that will radiate stored heat into the evening. Target these for cool pavements or shade sails.
- Limitations: (a) horizontal surface only — the tool does not model tilted or vertical surfaces; (b) no cloud, no albedo from surroundings, no atmospheric aerosol variation beyond the seasonal ASHRAE cycle; (c) the isotropic diffuse model underestimates circumsolar diffuse in hazy conditions; (d) screening quality — rankings are correct, absolute kWh values need site-specific calibration.
2. Mathematical Formulation
The ASHRAE clear-sky model parameters vary with day-of-year $n$:
For solar altitude $\alpha$, the direct normal irradiance, beam horizontal, and diffuse horizontal components are:
At time step $k$, the irradiance contribution to cell $(r, c)$ is:
The daily total irradiation (kWh/m²) and the unobstructed flat-ground reference are:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
DSM | Raster | Yes | — | Digital Surface Model. Must be in a projected CRS with metric pixel size. |
DATE | DateTime | Yes | — | Date for the study. For PV screening, use a winter date when solar access is the binding constraint. For heat exposure, use Jun 21. |
UTC_OFFSET | Double | — | 0.0 | Hours from UTC at the site. Required for correct sun position timing. Range: [-14, 14]. |
INTERVAL | Double | — | 30.0 | Time step in minutes. Smaller = more accurate but slower. 30 min is the recommended balance. Range: [5, 120]. |
USE_SVF | Boolean | — | True | When checked, diffuse irradiance is weighted per cell by sky view factor (SVF computed in a preliminary pass). Recommended for urban scenes with canyons; disable for open-terrain or rooftop-only analysis. |
SVF_RADIUS | Double | — | 100.0 | Search radius for the SVF pre-computation, in map units. Only used when USE_SVF is True. Minimum: 10.0. |
MAX_SEARCH | Double | — | 0.0 | Maximum shadow casting distance. 0 = auto-compute from DSM relief. Set a value to bound computation time. |
OUTPUT | Raster (Float32) | — | — | Daily irradiation in kWh/m². -9999 = NoData. |
4. Output Description
| Value | Interpretation |
|---|---|
| flat_kWh (log) | Clear-sky daily total on an unobstructed horizontal surface. This is the upper bound — the reference against which every cell is compared. |
| Cell kWh/m² | Actual clear-sky irradiation at the cell, including shadowing and (optionally) SVF-weighted diffuse. Ratio to flat_kWh = morphology efficiency. |
| Ratio > 0.9 | Essentially unobstructed — the cell receives >90% of what an open field would. Good roof for PV. |
| Ratio 0.5–0.7 | Heavily obstructed — surroundings cost 30–50% of potential yield. PV likely uneconomic here. |
5. Interpretation Guide
5.1 Reading Against the Reference
The ratio cell / flat-ground reference is the honest number. It isolates morphological shadowing from atmospheric and seasonal effects. Two sites at different latitudes will have different flat_kWh values; the ratio tells you which site is more obstructed, independent of latitude. A cell at ratio 0.85 in London may produce less absolute kWh than a cell at ratio 0.6 in Cairo — but the London cell is a better PV location relative to its climate.
5.2 Seasonal Strategy
- PV screening: run on Dec 21. Winter is the binding season — if a roof performs well in December, it performs well all year. Summer-only performers are poor PV investments because the energy is produced when demand and prices are low.
- Heat screening: run on Jun 21. The cells with the highest summer kWh are the surfaces that will radiate heat into the evening. Hardscape (asphalt, concrete) in these cells needs shade or cool-surface treatment.
5.3 Cross-References
- Feed top-scoring cells into Annual Solar Potential for year-round validation of PV candidates.
- Before/after irradiation differencing isolates the energy cost of a proposed building: the sum of kWh lost across all affected cells quantifies the solar-access impact in energy terms.
- Combine with Shadow Casting for the complementary question: "which cell is shadowed at a specific time?" (Shadow Casting) vs. "how much energy does each cell receive over the day?" (Solar Irradiation).
6. Symbolic Representation
- kWh/m²: Singleband pseudocolour, warm ramp: blue (low, < 1) through green, yellow, to red (high, > 6). Include the flat_kWh reference as a horizontal line annotation on the legend.
- Ratio to flat (raster calculator): Graduated, 0.0–1.0 in 0.1 steps. Green > 0.8, yellow 0.5–0.8, red < 0.5.
7. Literature
✓ Masters, G.M. (2004). Renewable and Efficient Electric Power Systems. Wiley. DOI: 10.1002/0471668826
✓ Duffie, J.A. & Beckman, W.A. (2013). Solar Engineering of Thermal Processes (4th ed.). Wiley. DOI: 10.1002/9781118671603
✓ Lindberg, F., Grimmond, C.S.B., et al. (2018). "Urban Multi-scale Environmental Predictor (UMEP)." Environmental Modelling & Software, 99, 70–87. DOI: 10.1016/j.envsoft.2017.09.020
✓ Reda, I. & Andreas, A. (2004). "Solar position algorithm for solar radiation applications." Solar Energy, 76(5), 577–589. DOI: 10.1016/j.solener.2003.12.003
✓ Suri, M. & Hofierka, J. (2004). "A New GIS-based Solar Radiation Model and Its Application to Photovoltaic Assessments." Transactions in GIS, 8(2), 175–190. DOI: 10.1111/j.1467-9671.2004.00174.x
✓ Freitas, S., Catita, C., Redweik, P. & Brito, M.C. (2015). "Modelling solar potential in the urban environment: State-of-the-art review." Renewable and Sustainable Energy Reviews, 41, 915–931. DOI: 10.1016/j.rser.2014.08.060
Annual Solar Potential (DSM)
Processing ID: planx:annualsolar
1. Theoretical Background
1.1 Academic Lineage
Annual solar potential — the total clear-sky global irradiation summed over a full year — is the metric that matters for rooftop PV economics, building energy balance, and year-round outdoor thermal comfort. Computing it by shadow-casting all 365 days would be computationally prohibitive for city-scale DSMs. The standard solution, introduced by Klein (1977) and codified in Duffie & Beckman (2013), is the monthly-average-day method: for each month, one representative average day — the day whose solar declination is closest to the monthly mean — is computed with the full shadow-aware beam + SVF-weighted diffuse model, then scaled by the number of days in that month and summed across 12 months. Twelve day-sweeps stand in for 365, reducing computation by a factor of 30 while preserving within about 2% accuracy for annual totals at low-to-moderate latitudes.
1.2 The Klein Representative Days
The recommended average days (Jan 17, Feb 16, Mar 16, Apr 15, May 15, Jun 11, Jul 17, Aug 16, Sep 15, Oct 15, Nov 14, Dec 10) are those for which the daily extraterrestrial radiation on a horizontal surface is closest to the monthly mean. These dates are latitude-independent for practical purposes — the declination variations are symmetric around the solstices. The method is valid for latitudes between 60 degrees S and 60 degrees N; polar latitudes with prolonged darkness or midnight sun require full daily integration.
1.3 Use Cases and Limitations
- Roof-top PV potential mapping: the primary use — rank every roof cell by annual kWh/m²/yr, then filter by usable area and system efficiency for a city-wide PV capacity estimate.
- Solar envelope planning: test proposed massings by comparing annual irradiation on existing roofs before and after — the kWh lost per year quantifies the solar-access impact in economic terms.
- Seasonal comfort design: the optional 12-band monthly raster reveals which months deliver or withhold sun, enabling seasonal shading design (full shade in July, full sun in January).
- Limitations: (a) clear-sky only — no cloud or aerosol variation; (b) horizontal surfaces only; (c) the Klein method's accuracy degrades above 60 degrees latitude; (d) screening quality — rankings are robust, absolute kWh/m²/yr values need local cloud correction.
2. Mathematical Formulation
Let $\text{daily}(r, c; y, m, d)$ be the clear-sky daily irradiation at cell $(r, c)$ for year $y$, month $m$, and day $d$, computed via the full shadow-aware + SVF-weighted model. Let $d_m^*$ be the Klein representative day for month $m$, and $N_m$ the number of days in month $m$:
The flat-ground annual reference (unobstructed, clear-sky) is:
The morphology efficiency — the share of available radiation that reaches the cell, isolating urban-form effects from climate — is:
The scene mean per month, used to identify the peak month for heat exposure:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
DSM | Raster | Yes | — | Digital Surface Model. Must be in a projected CRS with metric pixel size. |
YEAR | Integer | — | 2026 | Year for the computation. Affects leap-year day counts and the NOAA solar declination. Range: [1901, 2099]. |
UTC_OFFSET | Double | — | 0.0 | Hours from UTC. Affects the solar position timing for all 12 monthly sweeps. Range: [-14, 14]. |
INTERVAL | Double | — | 60.0 | Time step in minutes. 60 min is the recommended balance for a full-year computation (12x faster than 5 min). Range: [5, 120]. |
USE_SVF | Boolean | — | True | When checked, a single SVF pass is computed and reused for all 12 months. Recommended for urban scenes. |
SVF_RADIUS | Double | — | 100.0 | Search radius for the SVF pre-computation. Only used when USE_SVF is True. Minimum: 10.0. |
MAX_SEARCH | Double | — | 0.0 | Maximum shadow casting distance. 0 = auto-compute from DSM relief. |
OUTPUT | Raster (Float32) | — | — | Annual irradiation in kWh/m²/yr. -9999 = NoData. |
OUTPUT_MONTHLY | Raster (Float32, 12-band) | No | — | Optional 12-band raster with band names "January" through "December". Each band holds monthly kWh/m². |
4. Output Description
| Output | Content | Interpretation |
|---|---|---|
OUTPUT (annual raster) | kWh/m²/yr per cell | Clear-sky annual total. Multiply by cloud correction (0.5–0.7) for approximate real-sky annual total |
OUTPUT_MONTHLY (12-band) | kWh/m² per month per band | Seasonal breakdown. Band 1 = January. Check which months deliver most energy for a given location |
| flat_annual (log) | kWh/m²/yr | Unobstructed flat-ground reference. All-cell values < this number. The ratio isolates morphological effects |
| Scene monthly means (log) | kWh/m² per month | Three-letter abbreviations. The peak month identifies the seasonal heat-exposure maximum |
5. Interpretation Guide
5.1 Reading Morphology Efficiency
- $\eta_{morph}$ > 0.9: practically unobstructed. The cell receives >90% of what a flat open field would. These are the premium PV locations — rooftops, open plazas.
- $\eta_{morph}$ 0.7–0.9: mildly obstructed. Modest shadow losses from distant buildings or terrain. PV is viable but with reduced yield.
- $\eta_{morph}$ 0.5–0.7: significantly obstructed. Surrounding massing costs 30–50% of potential yield. PV likely uneconomic without building-scale analysis.
- $\eta_{morph}$ < 0.5: heavily obstructed. Street canyons, north-facing slopes, or deep courtyards. Solar access is compromised year-round.
5.2 PV Estimation Workflow
- Rank cells by annual kWh/m²/yr. Extract the top 20%.
- Filter by usable roof area (minimum contiguous patch size, e.g. 10 m²).
- Multiply by system factor $\eta_{sys} \approx 0.75$–$0.85$ (accounts for inverter, wiring, temperature, soiling losses).
- Multiply by local cloud correction $K_T \approx 0.5$–$0.7$ (the ratio of measured GHI to clear-sky GHI, from TMY data or PVGIS).
- Result: approximate annual AC energy per cell = $\text{Annual} \times \eta_{sys} \times K_T$ (kWh/m²/yr).
5.3 Seasonal Diagnostics (Monthly Bands)
- Peak month in summer: expected for most locations. If peak is Sept–Oct, the cell may be on an east-facing surface (morning sun year-round, no summer building shadow).
- Deep winter dip (Dec–Jan at 10–20% of peak): the cell loses most winter sun to building or terrain shadow. This is typical of ground-level street canyons.
- Flat monthly profile (all months within 30% of mean): the cell is on an unobstructed roof — seasonal variation is purely astronomical.
5.4 Cross-References
- Before/after annual differencing quantifies the permanent energy cost of a proposed building — the key evidence for solar-rights objections.
- Feed top cells into detailed PV simulation (PVGIS, SAM, PVsyst) with the specific panel tilt, azimuth, and local weather.
- Use the monthly bands with Sun Hours annual comparison: Sun Hours maps time, Annual Solar maps energy — the ratio reveals if a location's shadow hours coincide with the highest or lowest irradiance periods.
6. Symbolic Representation
- Annual kWh/m²/yr: Singleband pseudocolour, warm ramp: blue (< 500) through green, yellow, to red (> 1500). Adjust breakpoints to the site's flat_annual reference.
- Monthly 12-band: Use the Temporal Controller or a multi-band renderer. A common layout: 3x4 grid of monthly maps in the print layout, each with the same colour ramp, revealing the seasonal migration of the solar-access pattern.
- $\eta_{morph}$ (raster calculator): Graduated, 10 classes from 0.0 to 1.0. Dark blue (< 0.5) to bright yellow (> 0.9).
7. Literature
✓ Klein, S.A. (1977). "Calculation of monthly average insolation on tilted surfaces." Solar Energy, 19(4), 325–329. DOI: 10.1016/0038-092X(77)90001-9
✓ Duffie, J.A. & Beckman, W.A. (2013). Solar Engineering of Thermal Processes (4th ed.). Wiley. DOI: 10.1002/9781118671603
✓ Masters, G.M. (2004). Renewable and Efficient Electric Power Systems. Wiley. DOI: 10.1002/0471668826
✓ Lindberg, F., Grimmond, C.S.B., et al. (2018). "Urban Multi-scale Environmental Predictor (UMEP)." Environmental Modelling & Software, 99, 70–87. DOI: 10.1016/j.envsoft.2017.09.020
✓ Freitas, S., Catita, C., Redweik, P. & Brito, M.C. (2015). "Modelling solar potential in the urban environment: State-of-the-art review." Renewable and Sustainable Energy Reviews, 41, 915–931. DOI: 10.1016/j.rser.2014.08.060
✓ Reda, I. & Andreas, A. (2004). "Solar position algorithm for solar radiation applications." Solar Energy, 76(5), 577–589. DOI: 10.1016/j.solener.2003.12.003
✓ Suri, M. & Hofierka, J. (2004). "A New GIS-based Solar Radiation Model and Its Application to Photovoltaic Assessments." Transactions in GIS, 8(2), 175–190. DOI: 10.1111/j.1467-9671.2004.00174.x
Heat Island Risk Grid
Processing ID: planx:heatriskgrid
1. Theoretical Background
1.1 Academic Lineage
The Urban Heat Island (UHI) effect — the observation that urban areas are 2–12 K warmer than their rural surroundings — was first systematically documented by Luke Howard (1833) and given its energetic explanation by Oke (1982), who showed that canyon geometry (SVF reduction) is the primary nocturnal mechanism and surface-cover properties (albedo, thermal admittance, vegetation moisture) dominate daytime UHI intensity. Stewart & Oke (2012) formalised this into the Local Climate Zone (LCZ) classification, which characterises urban landscapes by built fraction, building height, pervious surface fraction, and thermal admittance — the same variables the Heat Island Risk Grid computes per cell. The tool implements a weighted additive model of these four components, producing a fixed-scale 0–100 risk score directly comparable between scenarios and study areas.
1.2 The Fixed-Scale Design
Unlike percentile-based or data-driven normalisations that stretch the score to fit the data range, the fixed-scale approach anchors the endpoints to the theoretical extremes given the user's chosen weights: fully vegetated (or water-covered) land at zero building height maps to 0; fully built land at the reference height maps to 100. This means re-running after a planning intervention — adding a park, increasing building heights, introducing water features — yields directly comparable numbers. "The park drops 14 cells from Very High to Moderate" is a verifiable claim because the thresholds are fixed, not re-stretched to the new data.
1.3 Component Mechanisms
- Built fraction ($b$): the primary daytime UHI driver through low albedo, high thermal mass, and anthropogenic heat release. Weight default: 0.4.
- Building height ($h/h_{ref}$): the primary nocturnal UHI driver through longwave radiation trapping (interacts with SVF). Capped at 1.0 (height beyond $h_{ref}$ does not increase risk further because tall buildings also cast shade). Weight default: 0.2.
- Green fraction ($g$): the primary cooling mechanism through evapotranspiration and shading. Weight default: 0.3 (the largest negative weight, reflecting empirical evidence that vegetation is the most effective UHI mitigation).
- Water fraction ($w$): additional evaporative cooling. Weight default: 0.1 (secondary because water bodies are usually mapped separately and cannot be "added" as easily as vegetation).
1.4 Use Cases and Limitations
- Plan scenario comparison: run on existing and proposed land cover to quantify which cells improve or deteriorate.
- Mitigation targeting: "Very High" risk cells that overlap with vulnerable populations (elderly, children) are priority cooling intervention zones.
- Limitations: (a) score is relative index, not temperature (K or °C); (b) does not model advection — a cool cell downwind of a hot district will be warmer than its components suggest; (c) does not include anthropogenic heat (traffic, HVAC) which can be 10–50 W/m² in dense districts; (d) results are per cell — street-level microclimates within a cell are averaged.
2. Mathematical Formulation
For a grid cell $c$, let $b_c$, $g_c$, $w_c$ be the built, green, and water area fractions ($\in [0, 1]$), and $h_c$ the area-weighted mean building height (metres). Let $h_{ref}$ be the reference height for full height effect (default 20 m), and $w_{built}$, $w_{height}$, $w_{green}$, $w_{water}$ the user-defined component weights:
The theoretical range of raw(c) is $[-\max(w_{green}, w_{water}),\; w_{built} + w_{height}]$, because a cell cannot simultaneously be fully green and fully water (they are disjoint surface covers). The normalised risk score is:
where $\text{raw}_{min} = -\max(w_{green}, w_{water})$ and $\text{raw}_{max} = w_{built} + w_{height}$. With default weights (0.4, 0.2, 0.3, 0.1):
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
BUILDINGS | Vector (Polygon) | Yes | — | Building footprints. Must be in a projected CRS. |
HEIGHT_FIELD | Field (Numeric) | No | — | Building height in metres. When empty, the height component weight is set to 0 (no height contribution). |
GREEN | Vector (Polygon) | No | — | Green/vegetated areas. Parks, gardens, street trees (as polygon coverage). Optional but strongly recommended. |
WATER | Vector (Polygon) | No | — | Water bodies. Lakes, rivers, ponds, fountains. Optional. |
CELL_SIZE | Double | — | 100.0 | Grid cell side in map units. 100 m = neighbourhood; 50 m = block; 200 m = district. Minimum: 10.0. |
H_REF | Double | — | 20.0 | Reference building height for full height effect. Heights above this value contribute no additional risk. Minimum: 1.0. |
W_BUILT | Double | — | 0.4 | Weight of built fraction in the risk composite. Range: [0, 1]. |
W_HEIGHT | Double | — | 0.2 | Weight of normalised building height. Range: [0, 1]. |
W_GREEN | Double | — | 0.3 | Weight of green cooling (subtractive). Range: [0, 1]. |
W_WATER | Double | — | 0.1 | Weight of water cooling (subtractive). Range: [0, 1]. |
OUTPUT | Vector (Polygon) | — | — | Sparse grid of cells with at least one of built/green/water coverage. Contains risk score, class, and all component fractions. |
4. Output Description
| Field | Type | Range | Description |
|---|---|---|---|
cell_id | Integer | $\geq 0$ | Zero-based cell index |
built_frac | Double | $[0, 1]$ | Building footprint area fraction within the cell |
green_frac | Double | $[0, 1]$ | Green/vegetated area fraction within the cell |
water_frac | Double | $[0, 1]$ | Water body area fraction within the cell |
mean_h | Double | $\geq 0$ | Area-weighted mean building height within the cell (metres) |
uhi_risk | Double | $[0, 100]$ | Normalised UHI risk score. Fixed scale — directly comparable between scenarios |
risk_class | String | — | Risk class: Low (< 25), Moderate (25–50), High (50–75), Very High (>= 75) |
5. Interpretation Guide
5.1 Reading Component Fractions for Remediation
- High built + low green + low height: dense low-rise with no vegetation. The remedy is depaving and planting — tree trenches, pocket parks, green roofs. This is the most common Very High pattern in Mediterranean and Middle Eastern cities.
- High built + high height + low green: dense high-rise canyon. The remedy combines shade structures (awnings, arcades) with albedo treatment (cool roofs, cool pavements). Vegetation alone cannot fix a deep canyon because tree canopies are limited in height; reflected shortwave from walls also contributes.
- Moderate built + moderate green: mixed fabric. Risk may come from the neighbouring district via advection, not from within-cell components. Check spatial context — one "Moderate" cell in a sea of "Very High" will be warmer than its components suggest.
5.2 Scenario Comparison
Because the scale is fixed, re-running after a mitigation intervention produces directly comparable numbers. The sentence "adding a 1 ha park drops 14 cells from Very High to Moderate" is legitimate because the thresholds (25, 50, 75) are anchored, not data-driven. To quantify impact: (a) run baseline; (b) edit the green/water/height layers; (c) re-run; (d) subtract uhi_risk between scenarios; (e) report the number of cells crossing class boundaries.
5.3 Cross-References
- Combine with Sky View Factor: low SVF + Very High risk = the worst-case combination — radiation trapped AND built/impervious. These are the top-priority cooling intervention targets.
- Overlay Very High cells with Accessibility Equity demographic data: if vulnerable populations concentrate in Very High cells, the UHI becomes an environmental justice issue.
- Use Frontal Area Index to check whether Very High cells also sit in wind-blocked zones: dual-mechanism heat stress (radiation trap + ventilation trap) requires both cool surfaces AND wind corridor protection.
6. Symbolic Representation
- uhi_risk: Graduated, 4 classes keyed to risk thresholds: green (< 25, Low), yellow (25–50, Moderate), orange (50–75, High), red (>= 75, Very High).
- Risk components bar chart: in the print layout, add a bar chart widget per cell showing the four component fractions in stacked bars (built = red, height = dark red, green = green, water = blue).
- Scenario delta: for before/after comparison, use a diverging red-blue ramp: cells that improved (lower risk) = blue; worsened = red; unchanged = grey.
7. Literature
✓ Oke, T.R. (1982). "The energetic basis of the urban heat island." Quarterly Journal of the Royal Meteorological Society, 108(455), 1–24. DOI: 10.1002/qj.49710845502
✓ Stewart, I.D. & Oke, T.R. (2012). "Local Climate Zones for Urban Temperature Studies." Bulletin of the American Meteorological Society, 93(12), 1879–1900. DOI: 10.1175/BAMS-D-11-00019.1
✓ Oke, T.R., Mills, G., Christen, A. & Voogt, J.A. (2017). Urban Climates. Cambridge University Press. DOI: 10.1017/9781139016476
✓ Bowler, D.E., Buyung-Ali, L., Knight, T.M. & Pullin, A.S. (2010). "Urban greening to cool towns and cities: A systematic review of the empirical evidence." Landscape and Urban Planning, 97(3), 147–155. DOI: 10.1016/j.landurbplan.2010.05.006
✓ Santamouris, M. (2014). "Cooling the cities — A review of reflective and green roof mitigation technologies to fight heat island and improve comfort in urban environments." Solar Energy, 103, 682–703. DOI: 10.1016/j.solener.2012.07.003
Road Noise Screening
Processing ID: planx:noisescreening
1. Theoretical Background
1.1 Academic Lineage
Road traffic noise is the most widespread environmental stressor in urban areas, with the World Health Organization (2018) estimating that at least 100 million Europeans are exposed to levels above the 55 dB(A) Lden threshold for annoyance and sleep disturbance. The Road Noise Screening tool implements a simplified version of the RLS-90 (Richtlinien fur den Larmschutz an Strassen, 1990) emission model, the German regulatory standard that underpins EU strategic noise mapping. The emission formula $L_{m,E} = 37.3 + 10\lg[M(1 + 0.082p)]$ at the 25 m reference distance is the RLS-90 mean level for light vehicles at 100 km/h, adapted to include heavy-vehicle correction. Propagation is free-field geometric spreading ($-20\lg r$, the point-source equivalent of a line-source after calibration), with a single fixed insertion loss where a building blocks the line of sight. This is a screening model — it correctly ranks exposure and locates hotspots but omits ground effect, air absorption, meteorology, and reflections, all of which are required for regulatory compliance.
1.2 Line-Source to Point-Source Calibration
A critical detail: road noise is a line source, not a point source. In the far field, a line source decays as $-10\lg r$ (3 dB per doubling of distance), while a point source decays as $-20\lg r$ (6 dB per doubling). The tool samples each road segment as multiple point sources, but each point source must be calibrated to reproduce the correct line-source level when summed. The calibration factor $10\lg(25 \cdot \text{seg\_len} / \pi)$ ensures that summing an infinite number of point samples along a straight road reproduces the RLS-90 mean level at 25 m. Each road is sampled at intervals of approximately 5 m (or larger, set by the cell size), so roads shorter than the sampling interval are represented by a single point source.
1.3 Building Screening
When a building layer is provided, a line-of-sight test is performed between each source sample and each receiver (grid cell). If the line-of-sight intersects any building polygon, the source contribution is reduced by the insertion loss (default 10 dB). This is a simple 2D screen — it treats buildings as infinitely tall solid barriers. In reality, sound diffracts over and around buildings, reducing the effective insertion loss. The 10 dB default is conservative (it overestimates attenuation, producing a "quiet-side" bias), which is intentional: if a cell reads below the WHO threshold with this simple screen, it is very likely below it in reality.
1.4 Use Cases and Limitations
- Noise hotspot identification: locate roads where measured or predicted levels exceed 55/65 dB(A) at residential receptors.
- Quiet-side evidence: demonstrate that courtyard levels behind perimeter blocks are 10–15 dB below street levels — the evidence for closed-block development.
- Limitations: (a) NOT a legal noise map — use a licensed engine (CadnaA, SoundPLAN, Predictor-Lima) for Environmental Noise Directive compliance; (b) no ground absorption — soft ground (grass, agricultural land) attenuates by 1–2 dB per 100 m, which this model misses, so open-country levels may be overestimated; (c) no meteorology — temperature inversions can increase levels by 5–10 dB downwind; (d) buildings treated as infinite screens — a 1-storey building screens as effectively as a 20-storey tower.
2. Mathematical Formulation
Let road segment $j$ have hourly traffic volume $M_j$ (vehicles/hour, after applying the hourly factor) and heavy-vehicle share $p_j$ (percent). The RLS-90-style mean emission level at 25 m is:
Each road segment is divided into $n_j$ point samples of length $\text{seg\_len}_j = \ell_j / n_j$ (metres). The level of one sample, calibrated to reproduce line-source behaviour when summed:
At receiver $(r, c)$, distance $d_{ij}$ from source $i$ of road $j$, the contribution with geometric spreading and optional screening loss $\Delta L_{screen}$ (default 10 dB) is:
The total level at the receiver is the energetic (incoherent) sum over all sources within the cutoff distance:
The population-weighted exposure summarises the public health burden:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ROADS | Vector (Line) | Yes | — | Road centreline layer. Must be in a projected CRS. Each segment needs a traffic volume field. |
VOLUME_FIELD | Field (Numeric) | Yes | — | Traffic volume per segment. Multiplied by HOURLY_FACTOR to obtain hourly volume M. 0 or missing = silent road (excluded). |
HOURLY_FACTOR | Double | — | 1.0 | Multiplier for the volume field. AADT → 1/24 = 0.0417 for average hour; peak hour factor = 0.10. Range: [0.0001, 10]. |
HEAVY_FIELD | Field (Numeric) | No | — | Heavy-vehicle share in percent. When empty, HEAVY_PCT default is used for all roads. |
HEAVY_PCT | Double | — | 5.0 | Default heavy-vehicle share in percent. 5% = typical urban arterial; 15% = freight route. Range: [0, 100]. |
BUILDINGS | Vector (Polygon) | No | — | Building footprints for line-of-sight screening. Optional but essential for detecting quiet courtyards. |
SCREEN_DB | Double | — | 10.0 | Insertion loss when a building blocks the line of sight, in dB. 10 = conservative screening; 5 = partial barrier. Range: [0, 30]. |
EXTENT | Extent | No | — | Grid bounding box. Empty = auto-extent from road layer + cutoff buffer. |
CELL | Double | — | 10.0 | Grid cell side in map units. 10 m = facade-scale; 5 m = detailed. Minimum: 1.0. |
CUTOFF | Double | — | 300.0 | Maximum source-receiver distance in map units. Sources beyond this are ignored. Minimum: 25.0. |
RECEIVERS | Vector (Any) | No | — | Optional receiver points (building centroids, address points). When provided, each receiver gets a dB level and noise band. |
POP_FIELD | Field (Numeric) | No | — | Population per receiver for exposure bands. Only used when RECEIVERS is provided. |
OUTPUT | Raster (Float32) | — | — | Noise level grid in dB(A). -1 = NoData (excluded cells). |
OUT_RECEIVERS | Vector (Point) | No | — | Optional output: receiver points with dB level and exposure band label. |
4. Output Description
| Field | Type | Description |
|---|---|---|
db (receivers) | Double | Total A-weighted sound level at the receiver, in dB(A). -1 = below computation floor |
band (receivers) | String | Noise exposure band: e.g. "< 45 dB", "45 – 50 dB", … "75 – 80 dB". Based on 5 dB bins |
| Grid cell value | Float32 | dB(A) level at the cell centre. -1 = excluded (beyond cutoff from all sources) |
The log reports population counts at the 55 dB(A) and 65 dB(A) thresholds — the two headline exposure numbers for any noise audit.
5. Interpretation Guide
5.1 The dB Scale
- +3 dB = double the sound energy. A road carrying 2x the traffic is ~3 dB louder.
- +10 dB = perceived as roughly twice as loud. A road at 70 dB sounds about twice as loud as one at 60 dB.
- 55 dB(A): the WHO threshold for community annoyance and sleep disturbance. Facades above this are "noise-affected."
- 65 dB(A): seriously noisy. Residential development facing this level requires mitigation (acoustic glazing, mechanical ventilation).
- 75+ dB(A): levels at which hearing protection is required for occupational exposure over 8 hours. Rare outside immediate motorway verges.
5.2 The Quiet-Side Effect
A key result from the screening model: courtyard levels behind perimeter blocks are 10–15 dB below street-facing levels, even without explicit acoustic treatment. This is the "quiet side" effect documented in European noise research — a flat whose bedroom faces the courtyard rather than the street sleeps 10 dB quieter. In planning terms, this is the strongest argument for closed-block typology over freestanding slabs: the same traffic produces acceptable and unacceptable levels depending on building arrangement.
5.3 Cross-References
- Feed the output into Road Emissions + Air Quality Screening for the noise + air pollution combined exposure map. The spatial correlation between noise and air pollution hotspots is high but not perfect — a receptor may be noisy but clean (motorway with good dispersion) or quiet but polluted (canyon with trapped emissions).
- Overlay noise bands on Building Form Metrics: buildings facing > 65 dB with high sharedwall (terraced) are candidates for facade insulation programmes because the cost is shared across fewer dwellings.
5.4 Common Pitfalls
- Hourly factor misuse: the most common error. Entering AADT without setting
HOURLY_FACTORto 1/24 produces levels 13.8 dB too high. Verify: a road with AADT 10,000 should give $L_{m25} \approx$ 58 dB (quiet urban road), not 72 dB (motorway). - Missing heavy vehicles: a road with 20% HGVs is ~1.5 dB louder than with 5% HGVs at the same total volume. The heavy share correction is modest but critical for freight routes and industrial areas.
6. Symbolic Representation
- dB(A) grid: Singleband pseudocolour: green (< 45), yellow (45–55), orange (55–65), red (65–75), purple (> 75). Thresholds at 55 (orange-red boundary) and 65 (red-purple boundary) should be visually dominant.
- Receivers: size by population, colour by noise band. The resulting map directly shows how many people are at each noise level.
7. Literature
✓ WHO (2018). Environmental Noise Guidelines for the European Region. WHO Regional Office for Europe. [institutional report]
✓ Steele, C. (2001). "A critical review of some traffic noise prediction models." Applied Acoustics, 62(3), 271–287. DOI: 10.1016/S0003-682X(00)00030-X
✓ Kephalopoulos, S., Paviotti, M. & Anfosso-Ledee, F. (2012). Common Noise Assessment Methods in Europe (CNOSSOS-EU). JRC Report 72550. DOI: 10.2788/31776
✓ Ohrstrom, E., Skanberg, A., Svensson, H. & Gidlof-Gunnarsson, A. (2006). "Effects of road traffic noise and the benefit of access to quietness." Journal of Sound and Vibration, 295(1-2), 40–59. DOI: 10.1016/j.jsv.2005.11.034
✓ European Environment Agency (2020). Environmental Noise in Europe — 2020. EEA Report No 22/2019. DOI: 10.2800/686249
Road Emissions
Processing ID: planx:roademissions
1. Theoretical Background
1.1 Academic Lineage
Road traffic emission modelling is the upstream step in air quality assessment: before dispersion can be computed, the mass of pollutant released per unit length of road must be estimated. The standard methodology, codified in the European Environment Agency's COPERT (Computer Programme to calculate Emissions from Road Transport) and the US EPA's MOVES (Motor Vehicle Emission Simulator), multiplies traffic activity (vehicle-kilometres) by fleet-average emission factors (grams per vehicle-kilometre) that depend on vehicle type, fuel, speed, engine technology, and ambient temperature. This tool implements the simplest possible version of this: emission = volume x factor, where the factor is a single user-supplied value representing the fleet-average emission rate for the pollutant of interest.
1.2 Emission Factors
The default emission factor 0.5 g/km/veh is a generic NOx-proxy screening value — it represents a modern mixed fleet (Euro 5/6 diesel and petrol) at urban speeds. Real emission factors vary by order of magnitude: a pre-Euro diesel car emits ~1.5 g NOx/km; a Euro 6 diesel with functioning SCR emits ~0.08 g NOx/km; an electric vehicle emits 0. The factor should be calibrated to the local fleet composition. COPERT provides country-specific factors; the European Environmental Agency's EMEP/EEA Guidebook publishes default factors by vehicle category and road type.
1.3 Volume Normalisation
The traffic volume field is assumed to contain the raw count from the input data. The HOURLY_FACTOR parameter converts this to a daily volume. If the volume field is AADT (annual average daily traffic), the factor is 1.0. If the volume field is an hourly count (e.g. 08:00–09:00 peak), the factor should scale this to daily: approximately 24 for a typical diurnal pattern, or precisely the ratio of daily to hourly volume from the local traffic model.
1.4 Use Cases and Limitations
- Mandatory input step: the primary function is to produce the emission field (
emission) that Air Quality Screening consumes. The two tools are designed as a pipeline. - Source ranking: on its own, the output ranks road segments by emission rate — the top decile identifies where traffic management (volume reduction, speed harmonisation, fleet renewal) has the greatest impact per km.
- Scenario testing: change the volume field (e.g. re-route 20% of traffic) and rerun to see which segments benefit or worsen.
- Limitations: (a) single emission factor — all vehicles are assumed identical; (b) no speed dependence — the factor should be selected for the representative speed of each road type (motorway = high speed = lower NOx from diesels, higher CO2; urban = low speed = higher NOx, lower CO2); (c) no cold-start correction — emissions are 2–5x higher in the first 2 km of a trip; (d) the factor is per vehicle, not per passenger-km — bus lanes have high per-vehicle emissions but low per-passenger emissions.
2. Mathematical Formulation
Let road segment $j$ have daily traffic volume $M_j$ (vehicles/day) after applying the hourly factor: $M_j = \text{raw\_volume}_j \times \text{multiplier}$. Let $EF$ be the fleet-average emission factor (grams per vehicle-kilometre). The emission rate per km of road per day is:
The raw volume used in the output (for audit purposes) is $M_j$. If $M_j = 0$ or invalid, $E_j = 0$.
where $\ell_j$ is the segment length in km. The segment length is not directly used in the emission rate field (which is in g/km/day), but the downstream Air Quality Screening tool uses $\ell_j$ to calibrate point-source strengths.
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ROADS | Vector (Line) | Yes | — | Road centreline layer. Must be in a projected CRS. The emission rate field on the output is consumed by Air Quality Screening. |
VOLUME_FIELD | Field (Numeric) | Yes | — | Traffic volume per segment (raw count). Multiplied by HOURLY_FACTOR to obtain daily volume. |
HOURLY_FACTOR | Double | — | 1.0 | Multiplier to convert raw volume to daily volume. 1.0 = AADT already; 24.0 = hourly to daily. Range: [0.0001, 1000]. |
EF_GKM | Double | — | 0.5 | Emission factor in grams per kilometre per vehicle. 0.5 = generic NOx-proxy for modern mixed fleet; use COPERT or local inventory values for quantitative studies. Minimum: 0.0. |
OUTPUT | Vector (Line) | — | — | Road layer with emission (g/km/day) and vol_used (the daily volume after factoring) appended. |
4. Output Description
| Field | Type | Description |
|---|---|---|
emission | Double | Emission rate in g/km/day. Feed directly into Air Quality Screening's EMISSION_FIELD parameter (default matches). |
vol_used | Double | The daily traffic volume after applying the hourly factor. For audit and verification — confirms the correct multiplier was applied. |
| (inherited) | — | All original road attributes are preserved. |
5. Interpretation Guide
5.1 Source-Ranking Logic
- Top decile by emission rate: these segments contribute disproportionately to total emissions. Traffic management (speed limits, freight rerouting, fleet renewal incentives) applied here yields the highest return per km.
- Emission rate vs. concentration: the emission map shows where pollutants are produced; the Air Quality Screening dispersion map shows where they accumulate. A high-emission motorway in open country (good dispersion) may produce lower concentrations than a moderate-emission canyon street with poor dispersion. This is why the tools are a pipeline.
5.2 Cross-References
- Mandatory pipeline: Road Emissions → Air Quality Screening. The
emissionfield is the default input for Air Quality Screening'sEMISSION_FIELD. - Combine with Road Noise Screening: roads in both the top noise decile AND top emission decile are the worst environmental performers — target for speed reduction (lowers both noise AND emissions).
- Use with traffic scenario models: edit the volume field for a proposed traffic scheme, rerun, and compare emission maps.
5.3 Common Pitfalls
- Wrong unit for volume: the most common error. A field labelled "volume" may be AADT, peak hour, or 24-hour. Check: a typical urban arterial AADT is 5,000–30,000; an hourly count is 200–2,000. If the volumes look off by a factor of ~24, the hourly factor is wrong.
- Single factor for all roads: the emission factor should vary by road type (motorway, arterial, residential) because speed and vehicle mix differ. For screening, a single average factor is acceptable; for quantitative studies, join a fleet composition table by road type.
6. Symbolic Representation
- emission: Graduated, 5 classes (Quantile or Natural Breaks), yellow (low) through orange to red (high). Line width proportional to emission rate (data-defined override:
emission / max(emission) * 3.0in map units).
7. Literature
✓ Ntziachristos, L. & Samaras, Z. (2019). "EMEP/EEA Air Pollutant Emission Inventory Guidebook 2019 — 1.A.3.b Road Transport." European Environment Agency.
✓ Franco, V., Kousoulidou, M., Muntean, M., Ntziachristos, L., Hausberger, S. & Dilara, P. (2013). "Road vehicle emission factors development: A review." Atmospheric Environment, 70, 84–97. DOI: 10.1016/j.atmosenv.2013.01.006
✓ Vardoulakis, S., Fisher, B.E.A., Pericleous, K. & Gonzalez-Flesca, N. (2003). "Modelling air quality in street canyons: a review." Atmospheric Environment, 37(2), 155–182. DOI: 10.1016/S1352-2310(02)00857-9
Air Quality Screening
Processing ID: planx:airscreening
1. Theoretical Background
1.1 Academic Lineage
Air quality screening in urban planning typically uses Gaussian plume or Gaussian puff models for open-road dispersion and street canyon models for built-up streets. The tool implements a simplified power-law decay model — an approximation to the Gaussian crosswind-integrated concentration at ground level from a line source — combined with a canyon accumulation factor based on the operational street pollution model (OSPM) concept reviewed by Vardoulakis et al. (2003). The model is screening quality: it correctly ranks receptor locations by relative pollution potential and identifies canyon hotspots, but the output is a unitless index, not a concentration in micrograms per cubic metre. Regulatory compliance requires a licensed dispersion model (ADMS-Urban, AERMOD, CALINE4) with meteorological input, terrain data, and chemistry.
1.2 The Power-Law Dispersion Model
The concentration index at a receptor is the sum of contributions from all road segment point sources: $\chi = \sum S_i / (u \cdot d_i^\alpha)$, where $S_i$ is the calibrated source strength (line-source emission rate converted to an equivalent point-source strength), $u$ is wind speed, $d_i$ is distance, and $\alpha$ is the decay exponent. This formulation derives from the Gaussian plume ground-level centreline concentration: $C \propto Q / (u \cdot \sigma_z \cdot \sigma_y)$, where $\sigma_z \propto x^b$ under neutral stability. Setting $\alpha = 2b + 1$ yields the effective distance power law. For neutral stability over urban terrain, $\alpha \approx 1.0$ for street-level screening; $\alpha = 0.5$ for broad plumes (unstable, daytime); $\alpha = 2.0$ for concentrated near-source (stable, nighttime). The offset distance $d_0$ (half the cell size) prevents the singularity at $d = 0$.
1.3 The Canyon Effect
When buildings flank both sides of a road, the street becomes a canyon — pollutants are trapped by the building walls, and concentrations can be 2–3x higher than over an open road with the same traffic. The canyon factor $1 + \min(2, H/W)$ captures the first-order geometric control: canyon aspect ratio $H/W$. A street with $H/W = 0.5$ (10 m buildings, 20 m street) has a factor of 1.5; a deep canyon with $H/W = 2$ (20 m buildings, 10 m street) saturates at 3.0. The canyon detection algorithm tests whether buildings exist within the search distance on both sides of a perpendicular line from the receptor to the nearest road, within the canyon buffer distance. Buildings on only one side = open road (factor 1.0). The tool does not model the canyon vortex — the recirculating flow that concentrates pollutants on the leeward side. This is a geometric indicator, not a CFD simulation.
1.4 Use Cases and Limitations
- Hotspot identification: the top decile of the pollution index grid is the priority list for detailed modelling, monitoring, or mitigation.
- Canyon screening: roads flagged as canyon-affected (buffer-distances with buildings on both sides) deserve first attention — a moderate-traffic canyon can produce higher concentration than a heavy-traffic open arterial.
- Land-use planning: keep schools, clinics, and playgrounds out of top-band cells, or argue setbacks and filtration where unavoidable.
- Limitations: (a) unitless relative index — ranks locations, does not check against air quality standards; (b) no chemistry — NOx, PM10, PM2.5 are all treated by the same dispersion (in reality, NO2 requires NO-NO2-O3 photostationary chemistry, and PM10 includes resuspension); (c) no terrain — the model assumes flat ground; (d) single wind speed — real dispersion varies with hourly wind, while this model uses a single representative value for screening; (e) the canyon factor is geometric — it does not distinguish between porous and solid street walls.
2. Mathematical Formulation
Let road segment $j$ have emission rate $E_j$ (g/km/day, from Road Emissions output). The segment is divided into $n_j$ point samples of length $\text{seg\_len}_j$ (metres). The calibrated point-source strength is:
At receptor $(r, c)$, the concentration index (unitless) is the sum over all sources within the cutoff distance:
where $u$ is wind speed (m/s), $d_0 = \text{cell\_size} / 2$ (m), $\alpha$ is the decay exponent, and $d_{ij}$ is the Euclidean distance from source $i$ of road $j$ to the receptor.
The canyon accumulation factor at a receptor is:
where $\bar{H}$ is the mean building height of the nearest flanking buildings on each side and $W$ is the canyon street width parameter. The final pollution index at the receptor is:
Population-weighted exposure summary:
3. Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ROADS | Vector (Line) | Yes | — | Road layer with emission field (output from Road Emissions tool). Must be in a projected CRS. |
EMISSION_FIELD | Field (Numeric) | Yes | "emission" | Field containing emission rate in g/km/day. Default matches Road Emissions output field name. |
WIND_SPEED | Double | — | 2.0 | Representative wind speed in m/s. Higher wind = more dilution = lower concentrations. Typical: 1.5 (calm), 3.0 (breezy). Minimum: 0.1. |
ALPHA | Double | — | 1.0 | Distance decay exponent. 0.5 = broad plumes (unstable); 1.0 = neutral (street-level screening); 2.0 = concentrated near-source (stable). Range: [0.1, 3.0]. |
BUILDINGS | Vector (Polygon) | No | — | Building footprints for canyon detection. Without buildings, the canyon factor is 1.0 everywhere (open-road dispersion). |
HEIGHT_FIELD | Field (Numeric) | No | — | Building height in metres. Only used when BUILDINGS is provided. Falls back to DEFAULT_HEIGHT. |
DEFAULT_HEIGHT | Double | — | 10.0 | Default building height when no height field is available. Minimum: 1.0. |
CANYON_WIDTH | Double | — | 20.0 | Street width for canyon aspect ratio H/W. The denominator in the canyon factor. Wider streets reduce the canyon effect. Minimum: 1.0. |
CANYON_SEARCH | Double | — | 30.0 | Distance (m) to search for flanking buildings perpendicular to the road. Larger values detect buildings set back from the street. Minimum: 5.0. |
CANYON_BUFFER | Double | — | 15.0 | Maximum distance from road for canyon effect to apply. Beyond this buffer, receptors are treated as open-terrain. Minimum: 1.0. |
EXTENT | Extent | No | — | Grid bounding box. Empty = auto-extent from road layer + cutoff buffer. |
CELL | Double | — | 10.0 | Grid cell side in map units. 10 m = facade-scale. Minimum: 1.0. |
CUTOFF | Double | — | 300.0 | Maximum source-receptor distance. Sources beyond this are ignored. Minimum: 25.0. |
RECEIVERS | Vector (Any) | No | — | Optional receiver points. Each receiver gets its pollution index and exposure band. |
POP_FIELD | Field (Numeric) | No | — | Population per receiver for exposure bands. Only when RECEIVERS provided. |
OUTPUT | Raster (Float32) | — | — | Pollution index grid (unitless). -1 = NoData. |
OUT_RECEIVERS | Vector (Point) | No | — | Optional output: receiver points with index value and exposure band. |
4. Output Description
| Field | Type | Description |
|---|---|---|
index (receivers) | Double | Unitless pollution index at the receiver. Relative scale — ranks locations, not concentrations |
band (receivers) | String | Exposure band in 10-unit increments: "< 10", "10 – 20", …, "90 – 100", ">= 100" |
| Grid cell value | Float32 | Unitless pollution index. -1 = excluded (beyond cutoff from all sources) |
5. Interpretation Guide
5.1 Reading the Relative Index
- The index is RELATIVE, not micrograms. A cell at index 100 has approximately 10x the pollution potential of a cell at index 10, but this ratio depends on the decay exponent, wind speed, and canyon geometry. The values are internally consistent within one run but not comparable between study areas with different parameter settings.
- Top decile = hotspot list. Extract the top 10% of cells by index value — these are the locations that most urgently need source control, detailed modelling, or monitoring.
- Canyon-flagged cells at moderate index > open-road cells at high index: a moderate-traffic canyon with CF = 3.0 produces 3x the open-road concentration. Look for cells in the 40–60 range that are canyon-flagged — they may be more polluted than cells in the 80–100 range on open roads.
5.2 Parameter Sensitivity
- $\alpha$ controls spatial scale. $\alpha = 0.5$: plume spreads broadly, moderate levels far from the road. $\alpha = 2.0$: concentrated near-source, sharp drop-off with distance. Use $\alpha = 1.0$ for street-level screening; vary $\alpha$ to test how the hotspot list changes under different atmospheric stability.
- $u$ scales all values linearly. Doubling wind speed halves all index values. Use a representative annual mean wind speed (2–3 m/s for most European cities).
- CANYON_WIDTH ($W$) in the denominator: narrow streets produce higher canyon factors. A 10 m street with 15 m buildings (H/W = 1.5, CF = 2.5) produces 2.5x the index of an open road with the same traffic.
5.3 Cross-References
- Mandatory pipeline dependency: Road Emissions → Air Quality Screening. The
emissionfield from Road Emissions is the default input. - Combine with Road Noise Screening: overlay the noise and air pollution hotspot grids. Cells in both top deciles are the worst environmental performers — dual-exposure zones.
- Overlay high-index cells on Building Form Metrics: canyon-flagged streets with attached building fabric (high sharedwall) trap pollutants between continuous walls — the worst case for both street-level pollution AND indoor air quality.
- Use with Frontal Area Index: $\lambda_f$ measures wind blockage; Air Quality Screening measures pollution accumulation. Correlated but not identical — a street with high $\lambda_f$ but low traffic is rough but clean; a street with low $\lambda_f$ and high traffic is smooth but polluted.
5.4 Common Pitfalls
- Missing canyon effect: without a building layer, all roads are treated as open. Street canyons will be underestimated by a factor of 2–3x. Always provide buildings when screening urban areas.
- Emission field unit mismatch: the emission field must be in g/km/day. If Road Emissions was run with a different multiplier or factor, the Air Quality Screening index will be proportionally wrong. Verify the emission values against typical benchmarks: a residential street with AADT 5,000 should emit ~2,500 g/km/day of NOx (screening value).
- Single wind speed: the model uses one representative wind speed. In reality, calm conditions (u < 1 m/s) produce the highest concentrations, but these are the hardest to model. Use a low wind speed (1–2 m/s) for worst-case screening.
6. Symbolic Representation
- Pollution index grid: Singleband pseudocolour: green (< 10), yellow-green (10–30), yellow (30–50), orange (50–70), red (70–100), purple (> 100). The top-decile threshold should be visually dominant.
- Canyon-flagged cells: add a hatched or crosshatched overlay for cells where CF > 1.0 (canyon effect applied). The combination of colour (concentration) + hatch (canyon flag) reveals whether hotspots are traffic-driven or geometry-driven.
- Receivers: size by population, colour by index band. The map directly shows population exposed at each level.
7. Literature
✓ Vardoulakis, S., Fisher, B.E.A., Pericleous, K. & Gonzalez-Flesca, N. (2003). "Modelling air quality in street canyons: a review." Atmospheric Environment, 37(2), 155–182. DOI: 10.1016/S1352-2310(02)00857-9
✓ Berkowicz, R. (2000). "OSPM — A Parameterised Street Pollution Model." Environmental Monitoring and Assessment, 65, 323–331. DOI: 10.1023/A:1006448321977
✓ Holmes, N.S. & Morawska, L. (2006). "A review of dispersion modelling and its application to the dispersion of particles: An overview of different dispersion models available." Atmospheric Environment, 40(30), 5902–5928. DOI: 10.1016/j.atmosenv.2006.06.003
✓ Franco, V., Kousoulidou, M., Muntean, M., Ntziachristos, L., Hausberger, S. & Dilara, P. (2013). "Road vehicle emission factors development: A review." Atmospheric Environment, 70, 84–97. DOI: 10.1016/j.atmosenv.2013.01.006
✓ Ntziachristos, L. & Samaras, Z. (2019). "EMEP/EEA Air Pollutant Emission Inventory Guidebook 2019 — 1.A.3.b Road Transport." European Environment Agency.
6. Plan Standards and QA
The Plan Standards and QA group translates planning regulations into quantitative conformance tests. Each tool answers a specific audit question: does the plan supply enough land per person for each mandated use? Are facilities both close enough and large enough for the population they must serve? Where does density actually exceed or fall short of the plan's own targets, not just the district average? These three tools form the compliance spine of PlanX — they read the plan document as geometry and report what the numbers say, independent of the narrative.
Land-Use Balance
Processing ID: planx:landusebalance
Overview
Computes the classic land-use balance table: for every land-use category in a polygon plan, the total area, the square metres provided per capita, the area required by configurable per-capita standards, and the resulting surplus or deficit. The table is the fundamental QA gate of any land-use plan — it asks, for each use regulated by a per-capita minimum, do we have enough land?
Standards are free-form text strings such as green=10, education=4,
health=1.5 (meaning 10 m² of green space per capita, 4 m² of
education land, 1.5 m² of health facility land). Keywords match category
names case-insensitively by containment — green catches
Urban Green Area, Neighbourhood Green, and
Regional Green Space alike. The default string is illustrative;
replace it with the values from your own regulation. The engine
(engine/standards.py) is pure stdlib: no NumPy, no geometry —
it operates on the area totals that the algorithm layer computes from polygon
geometries.
Theoretical Background
Per-capita standards in planning theory
Per-capita land allocation is one of the oldest quantitative planning tools, traceable to Ebenezer Howard's Garden City diagrams (1898), which specified acreages per thousand persons for every urban function, and to the Soviet normativy system that prescribed square metres of every facility type per resident. The modern statutory form appears in instruments such as the Turkish Spatial Plans Regulation (Mekansal Planlar Yapim Yonetmeligi), which mandates minimum per-capita provisions for green space, education, health, social services, sports, and technical infrastructure at each plan tier.
The per-capita standard performs two distinct functions that are often conflated: (1) a sufficiency test — is the total land allocated to a use category adequate for the planned population at build-out? and (2) a land-reservation trigger — which categories, after accounting for already-developed land, still need additional parcels acquired or designated? The first is a compliance check; the second is the actionable planning recommendation. The PlanX balance table serves both by reporting every category's surplus or deficit in absolute square metres — a deficit of −18,000 m² of green space is directly interpretable as "find 1.8 ha of additional greenspace land."
Limitations and spatial mismatch
The aggregate balance table suffers from the same limitation as every city-wide statistic: it reports how much land, not where. A plan can satisfy every per-capita standard at the municipal scale while half its population lives more than 800 m from the nearest park (the reachability gap). This is why the balance table must always be paired with the spatial tools: Facility Adequacy tests whether the land that exists is close enough to the people who need it; Green Space Access tests whether the greenspace land is walkable. The balance table is the quantity gate; the spatial tools are the quality gate.
Standards as configurable policy
The PlanX engine deliberately contains no hard-coded standard
values. The default string is a placeholder; the parse_standards
function accepts any keyword=value pairs. This is a design choice grounded in
planning practice: standards vary by jurisdiction, plan tier, and planning
epoch, and embedding a specific regulation would make the tool obsolete or
misleading. The user must supply the correct values for their context; the
tool only performs the arithmetic and matching.
Mathematical Formulation
Given K land-use categories with total areas {A1, …, AK} summed from polygon geometries, a planned population P, and standards S = {(keywordk, sk)} where each sk is the required m² per capita, the balance for category c is:
$$m_c = \frac{A_c}{P} \quad [\text{m}^2 \text{ per capita provision}] \tag{1}$$ $$R_c = s_{\text{match}(c)} \cdot P \quad [\text{required area, m}^2] \tag{2}$$ $$B_c = A_c - R_c \quad [\text{balance, m}^2] \tag{3}$$The matching function returns the first standard keyword that is a case-insensitive substring of the category name, or null if no match. The status classification is:
$$\text{status}(c) = \begin{cases} \text{"Meets standard"} & \text{if matched and } B_c \geq 0 \\ \text{"Deficit"} & \text{if matched and } B_c \lt 0 \\ \text{"No standard"} & \text{otherwise} \end{cases} \tag{4}$$The balance Bc is in absolute square metres, not
per-capita units. This is deliberate: a deficit of -18,000 directly
sizes the land search ("find 1.8 hectares"), whereas a per-capita shortfall of
-0.3 requires multiplying by population to become actionable.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
LANDUSE | Vector (Polygon) | — | Land-use plan polygons with category attribute. Area from geometry. Overlapping polygons double-count. Projected CRS required. |
CATEGORY_FIELD | Field (String) | — | Field with land-use category name. Case-insensitive substring matching against the standards string. |
POPULATION | Double | 10000.0 | Planned horizon population (≥ 1). Denominator for all per-capita calculations. Run for both current and horizon populations. |
STANDARDS | String | green=10, park=10, … | Per-capita standards as keyword=m² pairs, comma or semicolon separated. Default is illustrative — replace with your regulation's values. |
OUTPUT | Table | — | Balance table, one row per unique category. No geometry. |
Output Description
| Field | Type | Description |
|---|---|---|
category | String | Land-use category as found in CATEGORY_FIELD. |
area_m2 | Double | Total polygon area for this category (m²), rounded to 1 decimal. |
m2_capita | Double | area_m2 / population. Rounded to 3 decimals. |
std_key | String | Matching keyword from standards string (empty if unmatched). |
std_m2cap | Double | Per-capita standard from matched keyword. 0.0 if unmatched. |
required | Double | standard × population. The land budget for this category. |
balance_m2 | Double | area_m2 − required. Positive = surplus; negative = deficit. |
status | String | Meets standard / Deficit / No standard. |
Interpretation Guide
Reading the balance column
The balance_m2 column is the single most actionable number.
A green deficit of −18,000 m² means finding exactly 1.8 hectares
of additional greenspace land. Positive balances represent land banks that
could be reallocated. Large positive balances warrant scrutiny: does the plan
genuinely need that much surplus?
Temporal reading: current vs. horizon
Run twice: once with today's population, once with the horizon year (2040, 2050). Categories that flip from passing to Deficit under growth are tomorrow's land reservations — secure them before demand materialises. The largest future deficit gets the earliest deadline.
The "No standard" trap and spatial mismatch
Categories marked No standard may be genuinely unregulated (fine) or may reflect a naming mismatch between the standard keyword and the category field. Review every such row. More importantly, the balance table is city-wide — pair every deficit with a spatial tool (Green Space Access, Facility Adequacy, Capacitated Allocation) to find where the land or capacity is needed.
Pitfalls
- Overlapping polygons double-count area.
- Single-scalar population does not distribute spatially.
- Non-area standards (parking spaces/dwelling, units/ha) are not tested.
Academic References
Howard, E. (1898). To-Morrow: A Peaceful Path to Real Reform. Swan Sonnenschein. [Reprinted 1902 as Garden Cities of To-Morrow. No DOI; the foundational text of per-capita land budgeting.]
Baer, W.C. (1997). "General Plan Evaluation Criteria: An Approach to Making Better Plans." Journal of the American Planning Association, 63(3), 329–344. DOI: 10.1080/01944369708975926
Berke, P.R., Godschalk, D.R., Kaiser, E.J. & Rodriguez, D.A. (2006). Urban Land Use Planning, 5th ed. University of Illinois Press. [No DOI; the standard textbook on plan evaluation.]
Talen, E. (1998). "Visualizing Fairness: Equity Maps for Planners." Journal of the American Planning Association, 64(1), 22–38. DOI: 10.1080/01944369808975954
Laurini, R. (2001). Information Systems for Urban Planning. Taylor & Francis. DOI: 10.4324/9780203485934
Alexander, E.R. & Faludi, A. (1989). "Planning and Plan Implementation: Notes on Evaluation Criteria." Environment and Planning B, 16(2), 127–140. DOI: 10.1068/b160127
Facility Adequacy (Capacity + Distance)
Processing ID: planx:facilityadequacy
Overview
Evaluates public facilities along two dimensions simultaneously: spatial accessibility (is each demand point within the network catchment of at least one facility?) and capacity (does the assigned population exceed the facility's design capacity?). Every demand point is assigned to its nearest facility over the street network via multi-source Dijkstra, but only within a maximum cost catchment; beyond that, the point counts as uncovered. Facilities report their assigned load, utilisation (load / capacity), and a three-class status: Adequate, Overloaded, or Unused.
The dual output — facility adequacy table plus demand coverage layer — makes this the most powerful compliance tool in PlanX for education, health, and emergency-service planning. It replaces the two-step workflow of "assign to nearest, then check capacity" with one integrated pass on the real street network.
Theoretical Background
The two-dimensional adequacy problem
Public facility planning standards typically specify two independent constraints: a distance (catchment) standard ("every residence within 500 m of a primary school") and a capacity standard ("each school shall enrol no more than 600 pupils"). These are routinely checked separately — a GIS service area for distance, a spreadsheet for capacity. Facility Adequacy combines them because the two constraints interact: a facility that passes distance (sitting in a dense neighbourhood) may fail capacity catastrophically (that dense neighbourhood sends it far more children than it can hold), while another in a sparse area passes capacity trivially but serves almost no one.
Coverage models as the theoretical foundation
The adequacy check operationalises the maximal covering location problem (Church & ReVelle, 1974) in evaluation mode: instead of asking "where should we place facilities?", it asks "given the facilities we already have, what proportion of the population is adequately served in both distance and capacity?" The tool's demand-side weighting (optional population field) follows the spatial equity framework of Talen & Anselin (1998), where weighted demand replaces simple counts to reflect differential need. For a comprehensive review of location models encompassing both covering and median objectives, see ReVelle & Eiselt (2005) and Owen & Daskin (1998).
The multi-source Dijkstra engine
A single multi-source Dijkstra run from all facility nodes simultaneously labels each demand node with the facility that reached it first (lowest cost). This is functionally the network Voronoi partition by shortest-path distance. Complexity is O((n + f) log n + e) where n is nodes and f is facilities. By default the cost is geometric length; substituting a time field (e.g., from Walking Slope Comfort) produces slope-aware adequacy for hilly cities. The capacity check then summates demand weights per facility and compares against the capacity field.
Mathematical Formulation
Let G = (V, E) be the primal graph. Let D ⊂ V be demand nodes and F ⊂ V be facility nodes. Multi-source Dijkstra with cutoff cmax assigns to each demand node i a label and cost:
$$\text{label}(i) = \arg\min_{k \in F} d(i, k) \quad \text{subject to } d(i, k) \leq c_{max} \tag{1}$$where d(i, k) is the shortest-path cost on G. If no facility is within cmax, the point is uncovered.
$$\text{load}(k) = \sum_{i: \text{label}(i)=k} w_i \cdot \mathbf{1}[\text{cost}(i) \geq 0] \tag{2}$$ $$u_k = \frac{\text{load}(k)}{C_k} \quad [\text{utilisation}] \tag{3}$$where Ck is the capacity of facility k. The status classifier is a three-way rule:
$$\text{status}(k) = \begin{cases} \text{"Unused"} & \text{if load}(k) = 0 \\ \text{"Overloaded"} & \text{if } u_k > 1 \\ \text{"Adequate"} & \text{otherwise} \end{cases} \tag{4}$$The headline pass/fail metric reported in the log:
$$\text{share}_{covered} = \frac{\sum_{i: \text{cost}(i) \geq 0} w_i}{\sum_i w_i} \times 100\% \tag{5}$$Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network in projected CRS. Converted to primal graph with geometric edge weights. |
DEMAND | Vector (Any) | — | Demand point locations (buildings, parcels). Each snaps to nearest network node. |
POP_FIELD | Field (Numeric) | 1 / point | Population per demand point. Leave empty for unitary weights (count mode). |
FACILITIES | Vector (Any) | — | Facility point locations. Each snaps to nearest network node. |
FACILITY_ID | Field | — | Unique identifier for each facility. Appears in output labels. |
CAPACITY_FIELD | Field (Numeric) | — | Facility capacity in persons. ≥ 0. A zero-capacity facility can never be assigned demand. |
MAX_COST | Double | 500.0 | Maximum network cost (catchment) in map units. 400–800 m for walking; 2000–5000 m for driving. |
OUT_FACILITIES | Vector (Point) | — | Facility adequacy: each facility with load, utilisation, and status. |
OUT_DEMAND | Vector (Point) | — | Demand coverage: each demand point with facility label, cost, and covered flag. |
Output Description
Facility Adequacy (OUT_FACILITIES):
| Field | Type | Description |
|---|---|---|
facility | String | Facility identifier from FACILITY_ID. |
capacity | Double | Design capacity in persons. |
assigned | Double | Total population assigned (sum of demand weights within catchment). |
utilization | Double | assigned / capacity, rounded to 3 decimals. > 1 = overloaded. |
status | String | Adequate / Overloaded / Unused. |
Demand Coverage (OUT_DEMAND):
| Field | Type | Description |
|---|---|---|
covered | Integer | 1 = assigned within catchment; 0 = uncovered (no facility within MAX_COST). |
facility | String | Assigned facility identifier (empty if uncovered). |
net_cost | Double | Network cost to assigned facility in map units. −1 if uncovered. |
Interpretation Guide
The covered-population share
The log reports "Covered population: X of Y (Z%)". This single number is the compliance headline. Every percentage point below 100% represents residents who lack any facility within the catchment. For statutory standards, this is the legal compliance metric.
Reading the three status classes
- Adequate: facility serves its population within capacity. Utilisation near 0.7–0.9 is operationally ideal (headroom); near 0.95–1.0 is tight (flag as near-capacity).
- Overloaded (utilisation > 1): enough proximity, not enough capacity. The numeric overload (assigned − capacity) sizes the expansion.
- Unused (load = 0): wrong location or a network barrier separating the facility from demand that looks close on the map. Check the network connectivity before concluding relocation is needed.
Uncovered demand: two distinct causes
Uncovered points arise from: (1) distance gap — beyond MAX_COST from every facility (build new or extend catchment); (2) capacity gap — within MAX_COST but every reachable facility is full. Note: this tool assigns to nearest only and does not reallocate loads. Capacitated Allocation does that with spill logic.
Cross-referencing
- Balance table shows land deficit AND Facility Adequacy shows overloaded facilities: the land and the seats agree — plan for both.
- Balance table passes but Facility Adequacy fails: land exists, facilities on it are too small (redevelop, not rezone).
- For greenfield site selection, use Facility Location Optimizer.
- For capacity-constrained reallocation with spill, use Capacitated Allocation.
Academic References
Church, R. & ReVelle, C. (1974). "The Maximal Covering Location Problem." Papers of the Regional Science Association, 32(1), 101–118. DOI: 10.1007/BF01942293
Talen, E. & Anselin, L. (1998). "Assessing Spatial Equity: An Evaluation of Measures of Accessibility to Public Playgrounds." Environment and Planning A, 30(4), 595–613. DOI: 10.1068/a300595
Daskin, M.S. (1995). Network and Discrete Location: Models, Algorithms, and Applications. Wiley. DOI: 10.1002/9781118032343
ReVelle, C.S. & Eiselt, H.A. (2005). "Location Analysis: A Synthesis and Survey." European Journal of Operational Research, 165(1), 1–19. DOI: 10.1016/j.ejor.2003.11.032
Owen, S.H. & Daskin, M.S. (1998). "Strategic Facility Location: A Review." European Journal of Operational Research, 111(3), 423–447. DOI: 10.1016/S0377-2217(98)00186-6
Dijkstra, E.W. (1959). "A Note on Two Problems in Connexion with Graphs." Numerische Mathematik, 1(1), 269–271. DOI: 10.1007/BF01386390
Density Grid
Processing ID: planx:densitygrid
Overview
Distributes a numeric variable (population, dwelling count, jobs, floor area) from irregular source features — polygons or points — onto a regular grid using dasymetric disaggregation. Polygons are split proportionally by area share; points contribute fully to the containing cell. Output cells carry the summed value, density per hectare, and contributing feature count. Empty cells are omitted.
The gridded output is the preferred input format for most PlanX tools needing a uniform spatial surface: Facility Adequacy, Green Space Access, and Accessibility Equity all accept the density grid as a demand surface, ensuring provision analysis follows population rather than administrative centroids.
Theoretical Background
Dasymetric mapping: beyond the choropleth
The choropleth map — colouring administrative zones by a density value — is the default cartographic representation of population but also the most misleading: it implies uniform density within each zone, concealing the internal texture that drives facility demand, walkability, and infrastructure stress. A "low-density" district (30 persons/ha average) may contain a single tower cluster at 300 persons/ha; treating the whole district as low-density would under-provision schools for the tower residents.
Dasymetric mapping (Wright, 1936) addresses this by using ancillary information to redistribute the zonal total onto a finer grid. The PlanX implementation uses the simplest and most robust form: binary dasymetry by geometry. If source features already represent actual spatial units (buildings, parcels), the redistribution is exact: a building with 120 residents spanning four grid cells contributes 30 to each. No statistical modelling, no ancillary land-cover raster — just geometric intersection with area-proportional splitting. Eicher & Brewer (2001) and Mennis (2009) provide comprehensive reviews of dasymetric methods.
The modifiable areal unit problem (MAUP)
The density pattern depends on cell size (Openshaw, 1984). A 100-metre grid reveals building-by-building peaks; a 500-metre grid reveals neighbourhood structure; a 1000-metre grid approximates census-tract choropleths. There is no "correct" cell size — only the size appropriate to the question. Always report cell size with any derived statistic.
Density thresholds as planning heuristics
Urban economics and transport planning have established rough density thresholds linking residential density to service viability (Newman & Kenworthy, 1989; Ewing & Cervero, 2010):
- < 20 persons/ha: below bus-service threshold; car-dependent.
- 20–50 persons/ha: supports basic bus route (20–30 min headway).
- 50–150 persons/ha: walkable urban range; frequent bus, neighbourhood retail, walk-to-school catchments.
- 150–300 persons/ha: supports light rail/BRT; open-space provision becomes critical.
- > 300 persons/ha: metropolitan core density; infrastructure stress dominates.
These are heuristics, not universal laws; local context modulates them.
Mathematical Formulation
Let F = {f1, …, fm} be source features with values {vi} and geometries {gi}. For a grid cell (cx, cy) with rectangle R and area h2, the contribution from polygon feature i with area ai is:
$$v_{i, c_x, c_y} = v_i \cdot \frac{\text{area}(g_i \cap R)}{a_i} \tag{1}$$For point features, the feature contributes fully if its representative point falls inside the cell:
$$v_{i, c_x, c_y} = v_i \cdot \mathbf{1}[p_i \in R] \tag{2}$$The cell aggregate and density per hectare are:
$$\text{value}_{c_x, c_y} = \sum_{i=1}^m v_{i, c_x, c_y} \tag{3}$$ $$\text{dens\_ha}_{c_x, c_y} = \frac{\text{value}_{c_x, c_y}}{h^2 / 10{,}000} \tag{4}$$where h2 / 10,000 converts square map units to hectares. Only cells with at least one contributing feature are written; empty cells are skipped, keeping the output compact and free of sea-of-zero artefacts.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
INPUT | Vector (Any) | — | Source features: polygons for area-proportional, points for containment-based disaggregation. Projected CRS required. |
VALUE_FIELD | Field (Numeric) | 1 (count) | Numeric field to distribute. Leave empty to count features. Null/non-numeric values treated as 0. |
CELL_SIZE | Double | 100.0 | Grid cell size in map units (≥ 1). 100 m for project scale; 200–500 m for district; 500–1000 m for strategic. |
OUTPUT | Vector (Polygon) | — | Density grid: rectangular polygons, one per occupied cell. |
Output Description
| Field | Type | Description |
|---|---|---|
cell_id | Integer | Sequential 0-based cell identifier for joining. |
n_feat | Integer | Number of source features contributing to this cell. High = fine-grained fabric. |
value | Double | Summed value in the cell (total population, dwellings). Rounded to 4 decimals. |
dens_ha | Double | value divided by cell area in hectares. The standardised, cross-cell-size comparable density metric. Rounded to 4 decimals. |
Interpretation Guide
Cell size diagnostics
Run at two sizes and compare: a 100 m grid reveals building-by-building peaks; a 500 m grid shows neighbourhood structure. Both are true but answer different questions. The 100 m grid tells you where to place a school entrance; the 500 m grid tells you whether the neighbourhood supports transit.
Outlier detection and plan compliance
Sort by dens_ha descending. The top 1% of cells often reveal
data errors or genuine extremes meriting plan attention. Select cells exceeding
the plan's density cap — these are non-conforming locations. Check whether
they represent existing (grandfathered) or proposed development. The spatial
cluster of non-conforming cells identifies neighbourhoods where the cap is most
at odds with built form.
Difference grids for growth scenarios
Run on today's population and on the horizon-year population (from Population Projection). Subtract the grids (horizon − present). Positive cells show where growth is allocated; the magnitude at the densest cells indicates whether growth is concentrated (infill/compact) or dispersed (expansion/sprawl). This difference grid is the quantitative foundation for compact-city debates.
Pitfalls
- Cell size changes everything — always report it with any derived number.
- Polygon intersection is area-proportional — a building straddling four cells splits evenly. This is correct but may not match the actual population distribution within the building (e.g., a tower with all residents on upper floors concentrated over one part of the footprint).
- Point sources use containment only — the contributing point must fall inside the cell rectangle; points on boundaries go to exactly one cell (QGIS intersection semantics).
Academic References
Wright, J.K. (1936). "A Method of Mapping Densities of Population: With Cape Cod as an Example." Geographical Review, 26(1), 103–110. DOI: 10.2307/209467
Openshaw, S. (1984). "The Modifiable Areal Unit Problem." CATMOG (Concepts and Techniques in Modern Geography), 38. Geo Books, Norwich. [No DOI; the foundational MAUP reference.]
Eicher, C.L. & Brewer, C.A. (2001). "Dasymetric Mapping and Areal Interpolation: Implementation and Evaluation." Cartography and Geographic Information Science, 28(2), 125–138. DOI: 10.1559/152304001782173727
Newman, P.W.G. & Kenworthy, J.R. (1989). Cities and Automobile Dependence: An International Sourcebook. Gower. [No DOI; establishes the 30 persons/ha bus-service threshold.]
Ewing, R. & Cervero, R. (2010). "Travel and the Built Environment: A Meta-Analysis." Journal of the American Planning Association, 76(3), 265–294. DOI: 10.1080/01944361003766766
Mennis, J. (2009). "Dasymetric Mapping for Estimating Population in Small Areas." Geography Compass, 3(2), 727–745. DOI: 10.1111/j.1749-8198.2009.00220.x
7. Reporting and Dashboard
Seven tools that compile PlanX outputs into shareable evidence: an HTML performance report with embedded SVG charts; scenario snapshots as comparable JSON records; A/B comparison with direction-aware deltas and a verdict line; multi-scenario ranking with configurable weighted composites and a heat-table visualisation; a one-click batch auditor that chains the full evaluation battery; a deterministic synthetic city generator for training and testing; and a LUTI-lite scenario pipeline that welds growth simulation, population allocation, and accessibility evaluation into one integrated workflow.
Plan Performance Report (HTML)
Processing ID: planx:performancereport
Overview
Compiles multiple PlanX outputs into a single, self-contained HTML document with score cards, inline SVG histograms, compliance bar charts, and summary tables. Computes a Plan Performance Index (PPI) as the unweighted mean of the available 0–100 component scores. The report requires no external services, no web server, and no GIS to view — open the HTML file in any browser and all charts render from the embedded SVG. The same score cards appear live in the PlanX Dashboard dock panel.
The engine (engine/report.py) is pure stdlib: it draws every
chart with inline SVG elements — histograms with custom-coloured bars
following a three-tone ramp (bad red → amber → good green), scatter
maps of access scores with ramp-coloured points, and horizontal bar charts of
land-use balance (provided in colour vs. required in grey). No matplotlib, no
charting library, no JavaScript: the SVG is valid XML embedded directly in the
HTML stream.
Theoretical Background
Dashboards for plan evaluation
The Plan Performance Report adapts the dashboard paradigm from business intelligence to spatial planning. Following Tufte's (2001) principles of data-ink maximisation and small-multiples, each section presents one dimension of plan performance (access, land balance, facility adequacy, density) as a self-contained card: a headline number, a sub-line explaining it, and a colour tone (green/amber/red) encoding the quality level. The PPI aggregates these cards into a single 0–100 needle, following the composite-index tradition in urban studies (e.g., the UN Habitat City Prosperity Index) but with a strict design constraint: missing sections do not penalise the score — the PPI is the mean of whatever is available, not a weighted sum with zeros imputed for missing components.
Self-contained HTML as the distribution format
The report is deliberately a single .html file with no external
dependencies: no CDN links, no image files, no data directory. This is a
pragmatic choice grounded in planning practice: the report must survive being
emailed to a councillor, opened on a tablet in a committee room without
internet, and archived in a document management system that strips non-HTML
attachments. The inline SVG approach achieves this at the cost of larger file
size (typically 50–200 KB depending on data density), which is negligible
for modern storage and bandwidth.
PPI as a progress needle, not an absolute grade
The PPI is meaningful only over iterations of the same plan: a PPI rising from 62 to 74 across three revisions documents that the revisions improved the plan on the measured dimensions. It is meaningless as an absolute cross-plan comparator (a small-village plan will score differently from a metropolitan-region plan because its geometry, network, and population are different — not because one is "better"). The PPI's value is time-series comparison within one plan's evolution.
Mathematical Formulation
The Plan Performance Index (PPI) is the unweighted arithmetic mean of the
available 0–100 component scores. Contributing components are
aggregated by the report engine from the access, balance, and
adequacy summaries produced by the corresponding PlanX tools; the
formulation of each component is documented in the parent tool's entry.
Access score summary. From the vector of per-origin access scores {x1, …, xn}, the engine computes the arithmetic mean, the median (sorted middle value), and the shares of origins with a perfect score (100) or a low score (< 50):
$$\bar{x} = \frac{1}{n}\sum_{i=1}^n x_i \qquad \text{share}_{\text{full}} = \frac{|\{i: x_i \geq 99.99\}|}{n} \tag{1}$$Balance summary. From land-use balance rows with status ≠ "No standard", the compliance percentage is the fraction meeting or exceeding their standard:
$$\text{compliance\_pct} = 100 \cdot \frac{|\{r: \text{status}(r) = \text{Meets standard}\}|}{|\{r: \text{status}(r) \neq \text{No standard}\}|} \tag{2}$$Adequacy summary. From the facility adequacy and demand coverage outputs, the covered population share is:
$$\text{covered\_share} = 100 \cdot \frac{\sum_{d: \text{covered}[d]} \text{pop}[d]}{\sum_d \text{pop}[d]} \tag{3}$$PPI: the unweighted mean of available components (access mean, compliance_pct, covered_share), with missing components simply excluded:
$$\text{PPI} = \frac{1}{|C|}\sum_{c \in C} c \quad \text{where } C \text{ is the set of available components} \tag{4}$$Each score card is coloured by a three-tone ramp (bad red → amber → good green), with the colour derived from the normalised position of the value within [0, 100]. The ramp function interpolates linearly between the three anchor colours: (214, 69, 65) at t = 0, (245, 176, 65) at t = 0.5, and (39, 174, 96) at t = 1.0.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
TITLE | String | Urban Plan | Report title. Appears in the header and the browser tab title. |
POPULATION | Double | 0.0 | Planned population (0 = omit from header metadata). Informational only. |
ACCESS | Vector (Any) | (optional) | Access scores from Multi-Amenity Access Score. At least one input section required. |
ACCESS_SCORE | Field (Numeric) | score | Score field on the access layer. |
BALANCE | Vector | (optional) | Land-use balance table from Land-Use Balance. |
FACILITIES | Vector (Any) | (optional) | Facility adequacy output from Facility Adequacy. |
DEMAND | Vector (Any) | (optional) | Demand coverage output from Facility Adequacy. |
DEMAND_POP | Field (Numeric) | (optional) | Population field on demand layer (empty = 1 per point). |
DENSITY | Vector (Any) | (optional) | Density grid from Density Grid. |
DENSITY_FIELD | Field (Numeric) | dens_ha | Density field on the grid. |
OUTPUT | File (HTML) | — | Output report path. File is self-contained with inline CSS and SVG. |
Output Description
The report file contains: Header (title, population, timestamp, PlanX version), Score cards (PPI, access mean, standards compliance, covered population, density), Access section (score distribution histogram, optional score map as SVG scatter), Land-Use Balance section (provided-vs-required bar chart with compliance table), Facility Adequacy section (utilisation table sorted by descending load), Density section (cell count, mean, maximum), and a footer with the PlanX attribution.
Interpretation Guide
- PPI: a progress needle, not an absolute grade. Regenerate after each planning iteration and file the HTMLs as the plan's metric history.
- Histogram shape matters more than the mean: a bimodal access distribution means two different cities in one plan — some neighbourhoods are served, others are not, and the mean hides this split.
- Balance bars: the coloured bar is actual provision; the grey bar behind it is the required amount. A shorter coloured bar = deficit (visible, not just numeric).
- Facility table: sorted by decreasing utilisation — the top rows are the facilities nearest to capacity failure.
- Regenerate and file after each iteration. The PPI trace documents that the revisions actually improved the plan.
Academic References
Tufte, E.R. (2001). The Visual Display of Quantitative Information, 2nd ed. Graphics Press. [No DOI; the canonical reference on data visualisation design.]
Baer, W.C. (1997). "General Plan Evaluation Criteria: An Approach to Making Better Plans." Journal of the American Planning Association, 63(3), 329–344. DOI: 10.1080/01944369708975926
Few, S. (2013). Information Dashboard Design: Displaying Data for At-a-Glance Monitoring, 2nd ed. Analytics Press. [No DOI; the standard reference on dashboard design principles.]
Scenario Compare (A/B)
Processing ID: planx:scenariocompare
Overview
Compares two scenario snapshots metric by metric, with direction-aware deltas. For each metric shared by both snapshots, the tool reports the raw values for A and B, the absolute delta (Δ = B − A), the percent change, and which scenario wins (A, B, or tie for equal values). The verdict line tallies the wins. Scenarios rarely dominate — the normal outcome is a trade-off profile where B wins on accessibility and compliance while A wins on density and coverage. An optional self-contained HTML report presents the comparison in formatted tables for stakeholder distribution.
The engine (engine/scenario.py) drives the comparison. A
direction registry (METRICS dict) assigns each metric a human
label and a direction (+1 = higher is better, −1 = lower is better, 0 =
neutral). The engine also provides score_line for a one-sentence
verdict and build_compare_html in engine/report.py
for the HTML output.
Theoretical Background
Multi-criteria comparison in plan evaluation
Plan alternatives rarely dominate one another on all criteria — the compact city proposal may score higher on walkability and transit access while the dispersed proposal scores higher on housing capacity and green space per capita. The Scenario Compare tool formalises this trade-off analysis by reporting the direction and magnitude of each metric's change, following the multi-criteria evaluation framework (Baer, 1997; Keeney & Raiffa, 1976). Unlike a weighted composite score (which collapses the trade-off into one number), paired comparison preserves the profile: the planner sees which metrics flip and by how much.
Direction-aware comparison
The key innovation over a simple algebraic delta is the direction registry: the engine knows that a higher access score is good, a higher Gini coefficient is bad, and a different number of facilities is neutral. The "better" column thus reflects the substantive planning meaning of each delta, not just its arithmetic sign. This prevents the common error of celebrating a 10% increase in a metric where lower values indicate better outcomes (e.g., inequality, overloading count).
Mathematical Formulation
For each metric k with direction dk ∈ {+1, −1, 0} and snapshot values vkA and vkB:
$$\Delta_k = v_k^B - v_k^A \quad [\text{absolute change}] \tag{1}$$ $$\Delta\%_k = \frac{v_k^B - v_k^A}{|v_k^A|} \times 100 \quad [\text{percent change, NaN if } v_k^A = 0] \tag{2}$$The winning scenario for metric k is determined by the direction-consistent sign:
$$\text{winner}_k = \begin{cases} \text{"B"} & \text{if } d_k \cdot \Delta_k > 0 \\ \text{"A"} & \text{if } d_k \cdot \Delta_k < 0 \\ \text{"tie"} & \text{if } \Delta_k = 0 \\ \text{"n/a"} & \text{if } d_k = 0 \text{ or either value is missing} \end{cases} \tag{3}$$Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
SNAPSHOT_A | File (JSON) | — | Scenario snapshot JSON for alternative A. |
SNAPSHOT_B | File (JSON) | — | Scenario snapshot JSON for alternative B. |
OUT_TABLE | Table | — | Comparison table: metric, values A/B, delta, pct change, winner. No geometry. |
OUTPUT_HTML | File (HTML) | (optional) | Self-contained HTML comparison report. |
Output Description
| Field | Type | Description |
|---|---|---|
metric | String | Human-readable metric label. |
metric_key | String | Internal metric key (machine-readable). |
scenario_a | Double | Value in scenario A (or NULL if missing). |
scenario_b | Double | Value in scenario B (or NULL if missing). |
delta | Double | B − A (or NULL if either side missing). |
delta_pct | Double | Percent change (or NULL). |
better | String | A / B / tie / n/a. |
Interpretation Guide
- Do not stop at the win count. Scenarios rarely dominate. The normal outcome is a trade-off profile — naming that trade-off is the analysis.
- Use pct_change to judge materiality: <1% = noise (input data moved, not the plan); double-digit swings are genuine decisions.
- Missing metrics signal incomplete snapshots: fix the snapshot inputs (run the missing PlanX tools) before drawing conclusions.
- The verdict line counts decided wins. An even split is not a failure — it documents a balanced trade-off.
Academic References
Baer, W.C. (1997). "General Plan Evaluation Criteria: An Approach to Making Better Plans." Journal of the American Planning Association, 63(3), 329–344. DOI: 10.1080/01944369708975926
Keeney, R.L. & Raiffa, H. (1976). Decisions with Multiple Objectives: Preferences and Value Tradeoffs. Wiley. [Reprinted Cambridge University Press, 1993. DOI: 10.1017/CBO9781139174084]
Scenario Ranking
Processing ID: planx:scenariorank
Overview
Ranks any number of scenario snapshots (two or more) using a configurable weighted composite score. For each scored metric, values are min-max normalised within the set so that 1.0 is always best; the composite score is the weighted mean of these normalised values, scaled to 0–100. Competition ranking handles ties (equal scores share a rank; the next rank is skipped). "Wins" count per scenario — where a scenario holds the strictly best norm on a metric — complements the composite for non-compensatory reading. An optional HTML ranking board renders the scoreboard as a styled table with score bars and a metric heat table.
Theoretical Background
Composite indices in multi-criteria decision analysis
The weighted-sum model with min-max normalisation is the simplest form of multi-attribute value theory (Keeney & Raiffa, 1976). Normalisation to [0, 1] ensures commensurability across metrics measured in different units (persons, percent, metres, Gini coefficient); the direction flag ensures that "more" always means "better" after normalisation. The weighted sum is fully compensatory: a scenario can score zero on one metric and still rank first if it dominates on heavily weighted others. This is a feature (it allows trade-offs) and a warning (it can mask fatal weaknesses).
Metrics that are skipped
Three classes of metrics are excluded from scoring: (1) neutral (direction = 0, e.g., total population, facilities count) — no normative direction exists; (2) not-shared (missing in at least one snapshot) — comparison is impossible; (3) constant (identical across all snapshots) — contributes zero discrimination. The skipped list is reported explicitly; it is the first thing to check before trusting a ranking, because a snapshot evaluated with fewer tools will have more "not-shared" exclusions and thus a structurally different score basis.
Competition ranking and the wins complement
Competition ranking ("1224") handles equal scores correctly: identical composite scores produce tied ranks. The wins count — number of metrics where a scenario holds the strictly best norm — provides a non-compensatory complement: a balanced alternative may rank first on composite yet win zero individual metrics, while a specialist wins several metrics but scores lower overall. The divergence between rank and wins count is diagnostic of the scenario's strategy type (generalist vs. specialist).
Mathematical Formulation
For each scored metric k with direction dk and values vk,s across scenarios s:
$$\text{norm}_{k,s} = \begin{cases} \frac{v_{k,s} - \min_s}{\max_s - \min_s} & \text{if } d_k = +1 \text{ (higher is better)} \\[6pt] \frac{\max_s - v_{k,s}}{\max_s - \min_s} & \text{if } d_k = -1 \text{ (lower is better)} \end{cases} \tag{1}$$ $$\text{score}_s = 100 \cdot \frac{\sum_k w_k \cdot \text{norm}_{k,s}}{\sum_k w_k} \tag{2}$$Competition rank: scenario with highest score = rank 1; if two scenarios have equal scores, both share rank r and the next distinct score gets rank r + 2.
$$\text{wins}_s = \big|\{k : \text{norm}_{k,s} = 1.0 \land \forall s' \neq s,\ \text{norm}_{k,s'} < 1.0\}\big| \tag{3}$$Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
FILES | String | (optional) | Comma or semicolon-separated paths to snapshot JSON files. |
FOLDER | Folder | (optional) | Directory containing *.json snapshot files. Combined with FILES paths. |
WEIGHTS | String | (optional) | Metric weights as key=value pairs (e.g., access_mean=3, access_gini=2). Default weight = 1.0 for all. Unknown keys are warned and ignored. |
OUT_TABLE | Table | — | Ranking: rank, scenario name, score, wins, n_metrics. No geometry. |
OUT_DETAIL | Table | — | Per-metric detail: metric, label, direction, weight, scenario, raw value, norm. One row per metric per scenario. |
OUTPUT_HTML | File (HTML) | (optional) | HTML ranking board with score bars and heat table. |
Output Description
Ranking (OUT_TABLE): rank (int), scenario (string), score (double, 0–100),
wins (int), n_metrics (int).
Detail (OUT_DETAIL): metric (string key), label (string), direction (int, +1/−1),
weight (double), scenario (string), value (double), norm (double, 0–1).
Interpretation Guide
- Composite score is relative to the compared set; adding or removing a scenario rescales all scores. Never compare scores across different ranking runs.
- Rank ties = genuinely indistinguishable alternatives under the chosen weights.
- Wins vs. rank divergence: a generalist ranks first with zero wins; a specialist wins metrics but scores lower. Both are valid plan types; the choice is political, not mathematical.
- Check skipped metrics first: scenarios reaching ranking with fewer evaluated dimensions are structurally advantaged or disadvantaged depending on whether the missing dimensions are high or low.
Academic References
Keeney, R.L. & Raiffa, H. (1976). Decisions with Multiple Objectives. Cambridge University Press. DOI: 10.1017/CBO9781139174084
Baer, W.C. (1997). "General Plan Evaluation Criteria." JAPA, 63(3), 329–344. DOI: 10.1080/01944369708975926
Saaty, T.L. (1980). The Analytic Hierarchy Process. McGraw-Hill. [No DOI; the foundational AHP text for weighted multi-criteria ranking, the conceptual ancestor of this tool's weighted composite.]
Scenario Snapshot
Processing ID: planx:scenariosnapshot
Overview
Captures plan score metrics from the current QGIS project into a structured JSON file (the "scenario snapshot" format). PlanX output layers are auto-detected by their field signatures: the access-score layer (score + n_reach), the land-use balance table (balance_m2 + m2_capita), facility adequacy (utilization + assigned), demand coverage (covered + net_cost), and the density grid (dens_ha + value). Each can also be pinned explicitly — an explicit choice always wins over auto-detection.
The snapshot stores the same metrics as the Plan Dashboard score cards: Plan Performance Index, accessibility mean/median and full/low shares, standards compliance percentage and deficit count, covered population share and facility overloaded/unused counts, and density summary. The JSON serves as the comparable record for Scenario Compare and Scenario Ranking. Every evaluation workflow should end with a snapshot node.
Theoretical Background
Metrics as comparable evidence in plan-making
The snapshot formalises a single principle: every plan alternative must be evaluated on the same metrics with the same thresholds. A plan whose access score was computed with a 15-minute threshold and walking speed of 4.8 km/h is not comparable to one computed with a 10-minute threshold and 5.0 km/h. The snapshot captures not only the metric values but, through its field-signature detection, which PlanX tools contributed to the evaluation — a snapshot whose metrics list lacks density entries was evaluated without the Density Grid tool, and that absence will later surface in Scenario Compare as "metric missing on one side."
Auto-detection by field signature
The collect module (in collect.py) scans project
layers for characteristic field-name pairs rather than layer names. This is
deliberate: a layer called "Access Score (Scenario B)" is detected as
correctly as "access_score_output" because both contain the fields
score and n_reach. The detection is robust to
renaming but fragile to field deletions: if a QGIS processing step strips
the signature fields, the layer becomes invisible to the snapshot. Always
check the log's detection lines before trusting the numbers.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NAME | String | Scenario A | Scenario identifier. Carried into every subsequent comparison and ranking report. Use descriptive names: "2040 Compact", "2040 Corridor", "Baseline 2024". |
ACCESS | Vector Layer | (auto-detect) | Access-score layer. Explicit overrides auto-detection. |
BALANCE | Vector Layer | (auto-detect) | Land-use balance table layer. |
FACILITIES | Vector Layer | (auto-detect) | Facility adequacy layer. |
DEMAND | Vector Layer | (auto-detect) | Demand coverage layer. |
DENSITY | Vector Layer | (auto-detect) | Density grid layer. |
OUTPUT_JSON | File (JSON) | — | Snapshot JSON file. Contains kind, version, name, generated timestamp, and metrics dict. |
OUT_METRICS | Table | — | Metric table: key, label, value. For inspection/verification. |
Output Description
The snapshot JSON schema:
{
"kind": "planx-scenario-snapshot",
"version": 1,
"name": "2040 Compact",
"generated": "2026-08-07 14:30",
"metrics": {
"plan_performance_index": 72.5,
"access_mean": 68.3,
"access_median": 71.0,
"access_share_full": 45.2,
"access_share_low": 12.1,
...
}
}
Interpretation Guide
- A single snapshot is rarely the point: the value appears when two or more meet in Scenario Compare or Scenario Ranking.
- Check detection lines in the log before trusting: a snapshot silently missing a section (e.g., no density detected) will later read as "metric missing on one side" in comparisons.
- Use honest names: the snapshot name is carried through every downstream report. "2040 Compact" tells a story; "Scenario A" does not.
- End every evaluation model with a snapshot node so each plan run leaves a comparable record. Keep JSON files in the project folder as the plan's metric history.
Academic References
Baer, W.C. (1997). "General Plan Evaluation Criteria: An Approach to Making Better Plans." Journal of the American Planning Association, 63(3), 329–344. DOI: 10.1080/01944369708975926
Lichfield, N., Kettle, P. & Whitbread, M. (1975). Evaluation in the Planning Process. Pergamon Press. [No DOI; the classic text on systematic plan evaluation, establishing the principle of consistent metrics across alternatives.]
Batch Plan Auditor
Processing ID: planx:planaudit
Overview
Chains the standard PlanX evaluation battery in a single run: 15-minute access score, walkability audit, land-use balance against per-capita standards, facility adequacy (capacity + distance), green space access hierarchy check, and access equity (Gini coefficient over access scores). Each component is optional — supply only the inputs for the analyses you need and the auditor runs only those. The output is a scenario snapshot JSON (ready for Scenario Compare) plus an optional HTML Plan Performance Report. The tool is model-designer friendly and fully headless: one call turns a set of plan layers into a comparable scorecard.
Theoretical Background
The standard evaluation battery
The Batch Plan Auditor operationalises the principle that all plan alternatives must be evaluated on the same battery of quantitative tests before qualitative comparison begins (Baer, 1997). The six tests are selected to cover the standard dimensions of plan quality: spatial equity of access (15-minute city and Gini), walkability (street-level pedestrian environment), land sufficiency (per-capita balance), facility provision (adequacy), and environmental amenity (green space hierarchy). Together they produce 20+ comparable metrics per scenario. The auditor replaces the error-prone manual workflow of "run six tools, collect six outputs, manually copy numbers into a spreadsheet" with a single deterministic call.
Multi-step feedback and child algorithms
The auditor uses QGIS Processing's multi-step feedback mechanism
(QgsProcessingMultiStepFeedback) to report progress through the
battery. Each test is a child algorithm call (processing.run with
is_child_algorithm=True), so failures are propagated with the
offending algorithm name, and partial results up to the failure point are
discarded. All tests use the same network, demand layer, and coordinate
system — the auditor assumes these are prepared once and reused.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NAME | String | Plan | Scenario name for the snapshot. |
NETWORK | Vector (Line) | — | Street network. Required for all network-based tests. |
DEMAND | Vector (Any) | — | Demand/origins layer. Required for access, walkability, adequacy. |
POP_FIELD | Field (Numeric) | (optional) | Population field on demand (empty = 1 per point). |
AMENITIES | Multiple Layers | (optional) | Amenity layers for access score. If empty, the access test is skipped. |
THRESHOLD | Double | 15.0 | Access threshold in minutes. |
LANDUSE | Vector (Polygon) | (optional) | Land-use polygons for balance and walkability mix. |
CATEGORY_FIELD | Field | (optional) | Land-use category field. |
POPULATION | Double | 0.0 | Planned population for standards. 0 = skip balance test. |
STANDARDS | String | green=10, school=4 | Per-capita standards. Empty = skip balance test. |
FACILITIES | Vector (Point) | (optional) | Facilities with capacity. Empty = skip adequacy test. |
FACILITY_ID | Field | (optional) | Facility identifier field. |
CAPACITY_FIELD | Field (Numeric) | (optional) | Facility capacity field. |
MAX_COST | Double | 500.0 | Facility catchment distance. |
GREENS | Vector (Polygon) | (optional) | Public green spaces. Empty = skip green access test. |
HIERARCHY | String | 0.5=300, 2=800 | Green hierarchy: min_ha=max_dist pairs. Empty = skip green test. |
OUTPUT_JSON | File (JSON) | — | Snapshot JSON. |
OUTPUT_HTML | File (HTML) | (optional) | HTML performance report. |
OUT_METRICS | Table | — | Metric table: metric, metric_key, value. |
Output Description
Snapshot JSON with 20+ metrics (depending on which tests ran) including PPI, access statistics, walk score mean and low-score share, standards compliance and deficits, covered population share and facility utilisation, green coverage minimum, and access Gini. Metric table mirrors the snapshot. Optional HTML report with access, walkability, balance, facility adequacy, and green access sections.
Interpretation Guide
- Read the metric table as a triage list, worst first. Each headline number has a dedicated tool behind it; when a number looks wrong, run that tool alone and inspect its map.
- Audit every alternative with identical inputs and thresholds so snapshots are truly comparable.
- PPI is meaningful over iterations, weak as absolute grade. A PPI of 72 from a plan with all six tests is different from a PPI of 72 from a plan with only three tests active.
- Keep the JSON per iteration as the plan's metric history. The sentence for the report is: "audited on the standard battery, improved on X of Y metrics since draft 1."
Academic References
Baer, W.C. (1997). "General Plan Evaluation Criteria: An Approach to Making Better Plans." Journal of the American Planning Association, 63(3), 329–344. DOI: 10.1080/01944369708975926
Hopkins, L.D. (2001). Urban Development: The Logic of Making Plans. Island Press. [No DOI; the foundational text on plan-making as sequential decision under uncertainty, establishing the rationale for evaluating multiple alternatives on a common battery.]
Generate Demo City
Processing ID: planx:democity
Overview
Creates a complete, deterministic synthetic city from a single random seed: a regular grid of street blocks intersected by a diagonal avenue, building footprints with random heights assigned to rectangular lots within each block, four land-use zones (residential, commercial, green, school) with probabilistic allocation, point-of-interest markers, public facilities with capacities placed in green and school blocks, demand points with population weights derived from residential building volumes, green space polygons, and a raster DSM of building heights. The same seed always regenerates an identical city — ideal for tutorials, reproducible testing, and bug reports.
The engine (engine/demo.py) is pure NumPy with a
numpy.random.default_rng generator. Streets are constructed by
intersecting vertical, horizontal, and diagonal grid lines at the block
boundaries; buildings are 2x2 arrays per block, skipped over the diagonal
avenue right-of-way; land uses are assigned with guaranteed representatives
for the first four blocks (one of each type) and random categorical draws
for the rest. The DSM is rasterised by burning building height into
footprint-extent cells.
Theoretical Background
Synthetic data in spatial algorithm testing
Synthetic city generators serve two distinct purposes in geospatial software development and training: (1) algorithm validation — a known, controlled input where every expected output can be computed by hand, enabling unit testing and correctness verification; (2) pedagogical demonstration — a compact, clean dataset that illustrates a tool's behaviour without the noise, gaps, and idiosyncrasies of real-world data. The demo city's small default size (4x4 blocks at 100 m = 400 m × 400 m, 64 buildings, ~16 streets) is deliberately scaled to be visually inspectable: a user can verify a service area's correctness by eye because the total network has only a few dozen edges.
Determinism and reproducibility
The fixed-seed design (default seed = 42 with NumPy's PCG-64 generator)
guarantees bitwise-identical output across platforms and Python versions
(NumPy's default_rng stream is version-stable). This makes the
demo city useful for regression testing: a CI pipeline can run every PlanX
tool on the demo city and assert that each output's row count, field types,
and key statistics match the expected values. Any deviation signals a
regression in the engine or algorithm layer.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
SEED | Integer | 42 | Random seed for reproducible generation. Change for different layouts. |
BLOCKS_X | Integer | 4 | Number of blocks in X direction (≥ 1). |
BLOCKS_Y | Integer | 4 | Number of blocks in Y direction (≥ 1). |
BLOCK_SIZE | Double | 100.0 | Block size in metres (≥ 10.0). |
CRS | CRS | EPSG:3857 | Target projected CRS (must be metric). |
OUTPUT_STREETS | Vector (Line) | — | Street network segments with seg_id and length_m. |
OUTPUT_BUILDINGS | Vector (Polygon) | — | Building footprints with height attribute. |
OUTPUT_LANDUSE | Vector (Polygon) | — | Land-use block polygons with use attribute. |
OUTPUT_POIS | Vector (Point) | — | Points of interest with type attribute (Shop, Cafe). |
OUTPUT_FACILITIES | Vector (Point) | — | Facilities with name and cap (capacity) attributes. |
OUTPUT_DEMAND | Vector (Point) | — | Demand points with pop attribute. |
OUTPUT_GREEN | Vector (Polygon) | — | Green space polygons with park_id. |
OUTPUT_DSM | Raster | — | Digital Surface Model raster at 2 m resolution. |
Output Description
Eight outputs: Streets (seg_id, length_m), Buildings (height, 3–40 m), Land Use (use: residential/commercial/ green/school), POIs (type: Shop/Cafe), Facilities (name, cap: 1000 for parks, 500 for schools), Demand (pop, proportional to building volume), Green (park_id), and DSM (GeoTIFF, building heights on a 2 m grid, nodata = −1).
Interpretation Guide
- Nothing is real — the town exists so every other PlanX tool has clean, compatible inputs on the first click. Use it to learn a tool before trusting it on real data.
- Diagnostic value: when a tool misbehaves on real data but works on the demo city, the difference (CRS, noding, field types, missing values) is the diagnosis.
- Quickstart pair: streets → Space Syntax (radii 800,n); facilities → Service Areas; DSM → Microclimate tools; demand + facilities → Facility Adequacy or Batch Plan Auditor.
Academic References
Batty, M. (2013). The New Science of Cities. MIT Press. [No DOI; discusses synthetic city models as tools for understanding urban systems, including procedural generation approaches.]
Parish, Y.I.H. & Muller, P. (2001). "Procedural Modeling of Cities." Proceedings of SIGGRAPH 2001, 301–308. ACM. DOI: 10.1145/383259.383292
Scenario Pipeline (LUTI-lite)
Processing ID: planx:scenariopipeline
Overview
Weld urban growth simulation (CA), population allocation, and accessibility/walkability evaluation into one integrated decision pipeline. First, the Urban Growth CA model simulates city expansion from a seed urban mask over a suitability surface, respecting optional constraint rasters. Then, population growth is allocated to the newly developed cells proportionally to their suitability values. The pipeline constructs combined demand points (existing + new) and re-evaluates 15-minute accessibility and walkability on the grown city, producing a scenario snapshot JSON for comparison against the baseline.
Theoretical Background
LUTI (Land-Use Transport Interaction) in simplified form
LUTI models simulate the co-evolution of land use and transport over time. Full LUTI implementations (e.g., UrbanSim, TRANUS, MEPLAN) require calibrated behavioural models and extensive data. The Scenario Pipeline implements a "LUTI-lite" approach: the transport network is fixed (the street layer does not change), and land use evolves through cellular automaton growth constrained by suitability. The population reallocation step is the simplest possible linkage: new residents are placed where the CA model developed land, weighted by the suitability that attracted the growth. The feedback is one-directional: growth changes demand, which changes access scores and walkability. There is no reverse feedback (accessibility changes do not alter future growth locations). This is not a limitation for horizon-year screening — it produces the honest "growth without new services" worst case that service planners need.
The fixed-amenity assumption as a planning tool
The pipeline keeps amenity layers fixed: schools, shops, parks do not grow with the city. This reads as "what happens if we grow but do not add services?" — the honest worst case. The metric gap between the grown scenario and the baseline quantifies the service deficit that the new growth creates. If mean access falls from 68 to 52, the planning response is either to add amenities at the growth locations (raise the numerator) or to redirect growth toward existing amenity-rich areas (change the growth pattern). The pipeline quantifies the size of the problem; it does not solve it — that is the planner's job.
Mathematical Formulation
The pipeline's three stages are sequential:
Stage 1 — Growth CA: the Urban Growth Simulation algorithm produces a year-of-conversion raster where nonzero cells were developed. The set of newly developed cells is:
$$\mathcal{N} = \{(r, c) : y_{r,c} > 0 \land \text{finite}(y_{r,c})\} \tag{1}$$Stage 2 — Population allocation: for each new cell, the suitability value sr,c is extracted from the suitability raster. Population growth G is allocated proportionally:
$$p_{r,c} = G \cdot \frac{\max(0, s_{r,c})}{\sum_{(r',c') \in \mathcal{N}} \max(0, s_{r',c'})} \tag{2}$$These become new demand points at the cell centres with population pr,c, merged with existing demand points.
Stage 3 — Re-evaluation: the access score and walkability audit tools run on the combined demand and the fixed network, producing new metrics for the snapshot.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NAME | String | Scenario | Scenario name. |
SEED | Raster | — | Seed urban mask (nonzero = urban). Defines existing urban area. |
SUITABILITY | Raster | — | Development suitability raster (higher = more suitable). |
CONSTRAINTS | Raster | (optional) | Constraints (nonzero = never build). |
DEMAND_HA | Double | 50.0 | Land demand in hectares. |
ITERATIONS | Integer | 5 | Growth steps (1–100). |
NEIGH_WEIGHT | Double | 1.0 | Neighbourhood weight for edge growth (0–10). |
BASE | Double | 0.1 | Base term for leapfrog growth (0–1). |
RNG_SEED | Integer | 0 | Random seed for CA tie-breaking. |
POP_GROWTH | Integer | 1000 | Population growth to allocate over new cells. |
DEMAND | Vector (Any) | (optional) | Existing demand points with population field. |
POP_FIELD | Field (Numeric) | (optional) | Population field on existing demand. |
NETWORK | Vector (Line) | — | Street network for access and walkability evaluation. |
AMENITIES | Multiple Layers | (optional) | Amenity layers for access score. |
THRESHOLD | Double | 15.0 | Access threshold in minutes. |
LANDUSE | Vector (Polygon) | (optional) | Land-use for walkability mix component. |
CATEGORY_FIELD | Field | (optional) | Land-use category field. |
OUTPUT_JSON | File (JSON) | — | Scenario snapshot JSON of the grown city. |
OUT_METRICS | Table | — | Metric table. |
Output Description
The pipeline produces two outputs:
- Snapshot JSON (OUTPUT_JSON): a standard PlanX scenario snapshot containing the PPI, access score statistics (mean, median, full/low shares), walk score mean, and low-score share — all computed on the grown city with combined (existing + new) demand.
- Metric Table (OUT_METRICS): same format as Scenario Snapshot — metric key, human-readable label, and numeric value.
Interpretation Guide
- The metric table scores the GROWN city, not today's. Compare against a baseline snapshot. The gap between them is what growth does to liveability.
- Falling mean access is the normal finding: new edge growth lands far from existing amenities. The size of the drop is the planning information.
- Amenity layers stay fixed: this is "growth without new services," the honest worst case.
- Run compact vs. dispersed variants: high neighbourhood weight + constraints-on = compact; low weight + no constraints = dispersed. Feed both snapshots to Scenario Compare — the access/walkability gap is the quantified cost of sprawl for YOUR city.
- Where access collapses: that is where the amenity investment belongs. Test it with the standalone access tools.
Academic References
Clarke, K.C., Hoppen, S. & Gaydos, L. (1997). "A Self-Modifying Cellular Automaton Model of Historical Urbanization in the San Francisco Bay Area." Environment and Planning B, 24(2), 247–261. DOI: 10.1068/b240247
Waddell, P. (2002). "UrbanSim: Modeling Urban Development for Land Use, Transportation, and Environmental Planning." Journal of the American Planning Association, 68(3), 297–314. DOI: 10.1080/01944360208976274
Wegener, M. (2014). "Land-Use Transport Interaction Models." In: Fischer, M.M. & Nijkamp, P. (eds.), Handbook of Regional Science, pp. 229–246. Springer. DOI: 10.1007/978-3-642-23430-9_14
8. Optimization
Five facility and land-use optimisation tools operating on the street network via an embedded pure-NumPy engine — no external solvers, no licensed libraries, no cloud dependencies. Two facility location models (maximal coverage via greedy selection and p-median via Teitz-Bart vertex substitution), one capacitated allocation with greedy nearest-with-spill logic, one multi-objective land-use allocator with compactness and adjacency terms, a Pareto front tracer that maps the suitability-compactness trade-off, and a capacitated facility siting tool that selects sites AND sizes capacity in one pass.
Facility Location Optimizer (Coverage / P-Median)
Processing ID: planx:facilitylocation
Overview
Selects the best sites for new facilities among candidate locations on the real street network. Two models are implemented: Maximal Coverage (Church & ReVelle, 1974) using greedy selection — each step picks the candidate covering the most as-yet-uncovered demand within a catchment radius; and P-Median (ReVelle & Swain, 1970; Teitz & Bart, 1968) using greedy construction followed by vertex substitution — each swap replaces a selected site with an unselected candidate if it reduces the population-weighted total travel cost. Existing facilities are fixed in the solution; new sites complement them.
The engine (engine/optimize.py) operates on a distance matrix
D of shape (candidates, demand points) computed by many-to-many
Dijkstra over the network graph. For coverage mode, a binary mask
D ≤ radius is multiplied by the population weight vector
to obtain marginal gains. For p-median mode, the objective is the
population-weighted sum of distances to the nearest selected facility, and the
Teitz-Bart substitution iterates until no improving swap is found or max_iter
is reached.
Theoretical Background
Covering models: from set covering to maximal coverage
Toregas et al. (1971) formulated the location set covering problem (LSCP): minimise the number of facilities such that every demand point is within a specified distance. Church & ReVelle (1974) recognised that the LSCP's "cover everyone" constraint is often infeasible under a budget, and proposed the maximal covering location problem (MCLP): for a fixed number of facilities p, maximise the population within the coverage radius. The greedy heuristic implemented here is a (1 − 1/e) ≈ 0.632-approximation for the submodular maximisation problem (Nemhauser, Wolsey & Fisher, 1978) — it is provably within 63% of the optimal covered population.
P-median and the Teitz-Bart heuristic
The p-median problem (Hakimi, 1964; ReVelle & Swain, 1970) minimises the sum of demand-weighted distances to the nearest facility. Unlike coverage models which treat all demand within the radius equally, the p-median penalises long trips linearly — it preferences the average user, not the worst-off. The Teitz & Bart (1968) vertex substitution heuristic is a local-search improvement over a greedy starting solution: it evaluates swapping each selected site with each unselected candidate, applying the first improving swap found. While not guaranteed to find the global optimum, it typically produces solutions within 5–10% of optimal for urban-scale instances (Daskin, 1995).
Coverage vs. p-median: choosing the model
Coverage models are appropriate for services with a hard distance threshold ("within 500 m of a primary school", "within 8 minutes of a fire station"). P-median models are appropriate for services where every metre of extra distance matters to everyone ("shorten the average trip to the nearest clinic"). The two models give different site selections by design. Sites picked by both are robust to the modelling choice; sites picked by only one reveal the sensitivity of the recommendation to the objective.
Mathematical Formulation
Maximal Coverage (greedy). Let cover[f, d] = 1 if dist(f, d) ≤ radius. The gain at each greedy step is uncovered demand newly covered by candidate c:
$$\text{gain}(c) = \sum_{d: \text{cover}[c,d]=1 \land \text{uncovered}[d]} w_d \tag{1}$$At each iteration t, select ct = argmaxc gain(c), mark newly covered demand, and repeat for p steps (or until no candidate adds coverage).
P-Median objective. For a selected set S of facilities (including fixed), the objective is:
$$Z(S) = \sum_{d=1}^N w_d \cdot \min_{f \in S} \text{dist}(f, d) \tag{2}$$Teitz-Bart swap. For each selected site s and each unselected candidate c, evaluate the swap (S \ {s}) ∪ {c}. If Z(Sswap) < Z(S) − 10−12, accept the swap. Repeat until no swap improves the objective (or max_iter is reached).
Unreachable pairs (infinite distance) incur a penalty cost of 1.5 × the largest finite distance, ensuring they are avoided unless no reachable facility exists.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. Projected CRS required. |
DEMAND | Vector (Any) | — | Demand points with population weights. |
POP_FIELD | Field (Numeric) | 1/point | Population per demand point. |
CANDIDATES | Vector (Any) | — | Candidate facility sites. All snapped to network nodes. |
CANDIDATE_ID | Field | — | Unique identifier for each candidate. |
EXISTING | Vector (Any) | (optional) | Existing facilities fixed in the solution. |
METHOD | Enum | Coverage | Coverage (greedy) or P-Median (Teitz-Bart). |
P | Integer | 3 | Number of new facilities to site (≥ 1). |
RADIUS | Double | 500.0 | Catchment radius in map units. Used in coverage mode and for candidate screening in both modes. |
OUT_SITES | Vector (Point) | — | Candidate sites with screening score, selection flag, rank, and marginal gain. |
OUT_ASSIGN | Vector (Point) | — | Demand points with assigned facility, network cost, and covered flag. |
Output Description
Candidate Sites (OUT_SITES): inherits all source fields + cand_id (string),
reach_dem (screening: demand within radius), selected (0/1), rank
(1..p for selected, 0 for unselected), gain (marginal covered demand added).
Demand Allocation (OUT_ASSIGN): inherits all source fields + facility
(assigned facility label), net_cost (network distance to assigned facility, −1 if
unreachable), covered (1 if within radius, 0 otherwise).
Interpretation Guide
- rank and gain tell the investment story: rank 1 is the single best site. When gain collapses (pick 4 adds a fraction of pick 1), that is the diminishing-returns point — the evidence-based answer to "how many do we need?"
- reach_dem on unselected candidates shows near-misses: a candidate with high reach that was not picked overlaps a winner — a plausible substitute if the winner's land falls through.
- Coverage vs. p-median give different answers. Run both: sites picked by both are robust. Sites picked by only one reveal sensitivity to the modelling objective.
- Fix existing facilities so the tool only places the increment. Check uncovered demand clusters: if they concentrate in one area, no candidate serves that pocket — the candidate list itself is the problem.
Academic References
Church, R. & ReVelle, C. (1974). "The Maximal Covering Location Problem." Papers of the Regional Science Association, 32(1), 101–118. DOI: 10.1007/BF01942293
Teitz, M.B. & Bart, P. (1968). "Heuristic Methods for Estimating the Generalized Vertex Median of a Weighted Graph." Operations Research, 16(5), 955–961. DOI: 10.1287/opre.16.5.955
Daskin, M.S. (1995). Network and Discrete Location: Models, Algorithms, and Applications. Wiley. DOI: 10.1002/9781118032343
ReVelle, C.S. & Eiselt, H.A. (2005). "Location Analysis: A Synthesis and Survey." European Journal of Operational Research, 165(1), 1–19. DOI: 10.1016/j.ejor.2003.11.032
Nemhauser, G.L., Wolsey, L.A. & Fisher, M.L. (1978). "An Analysis of Approximations for Maximizing Submodular Set Functions — I." Mathematical Programming, 14(1), 265–294. DOI: 10.1007/BF01588971
Hakimi, S.L. (1964). "Optimum Locations of Switching Centers and the Absolute Centers and Medians of a Graph." Operations Research, 12(3), 450–459. DOI: 10.1287/opre.12.3.450
Capacitated Allocation (Nearest with Capacity)
Processing ID: planx:capacitatedallocation
Overview
Assigns demand to fixed facilities while respecting capacity constraints — the realistic companion to Facility Adequacy (which assigns everyone to the nearest and only flags overload afterward). Each demand point is sent, in full, to the nearest facility over the street network that still has room; when its nearest is already full, it spills to the next-nearest with free capacity within the catchment. Points fitting nowhere are left uncovered. Demand status: Assigned (nearest), Spilled (farther because nearest was full), or Uncovered. Facilities report load, remaining capacity, utilisation, and status (Full / Has space / Unused).
Theoretical Background
Capacitated allocation as nearest-with-spill
The problem of assigning demand to capacitated facilities is a minimum-cost flow problem when fractional assignments are allowed (Daskin, 1995). When demand points must be assigned in whole (no splitting), the problem becomes NP-hard (it is a generalised assignment problem). PlanX implements a fast greedy heuristic: sort all eligible facility-demand pairs by cost, iterate cheapest-first, assign a demand point to the earliest facility in its sorted list that has room. This is not a global optimum — a demand point may be greedily assigned to facility A, blocking capacity that a farther demand point needed from A, when a globally better assignment would have sent the first point to B. However, the greedy approach is explainable, fast, and produces the "nearest available" answer that matches how people actually choose facilities (nearest first, spill when full).
Whole-point assignment and stranded capacity
Because demand points are not split, a facility with remaining capacity
smaller than any nearby point's population may remain "Has space" yet
accept no one. This is not a bug — it correctly reflects
the indivisibility of whole-family or whole-building assignments. The
stranded capacity is reported in the remaining field; the
planning response is either to accept the inefficiency or to consider
smaller-capacity facilities (which the tool cannot create but can model
if the input capacity values are reduced).
Mathematical Formulation
Let D be the (facilities × demand) cost matrix, w the demand weight vector, C the facility capacity vector. The eligible set E ⊆ {1..F} × {1..N} contains all pairs with finite cost and cost ≤ cmax:
The greedy assignment iterates over eligible pairs sorted by increasing cost, with deterministic tie-breaking by demand index then facility index:
$$\text{For each } (f, d) \in E \text{ sorted by cost}: \quad \text{if } \text{assigned}[d] = -1 \land \text{remaining}[f] \geq w_d: \quad \text{assign } d \text{ to } f, \text{ remaining}[f] \mathrel{-}= w_d \tag{1}$$Spill status:
$$\text{spilled}[d] = (\text{assign}[d] \neq -1) \land (\text{assign}[d] \neq \text{nearest}[d]) \tag{2}$$where nearest[d] is the index of the closest reachable facility ignoring capacity.
$$\text{utilisation}[f] = \frac{C_f - \text{remaining}[f]}{C_f} \tag{3}$$Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network, projected CRS. |
DEMAND | Vector (Any) | — | Demand points. Whole points assigned to one facility each. |
POP_FIELD | Field (Numeric) | 1/point | Population per demand point. |
FACILITIES | Vector (Any) | — | Fixed facilities with capacities. |
FACILITY_ID | Field | — | Facility identifier field. |
CAPACITY_FIELD | Field (Numeric) | — | Capacity in persons (≥ 0). |
MAX_COST | Double | 500.0 | Maximum catchment cost in map units. |
OUT_DEMAND | Vector (Point) | — | Demand allocation with facility, cost, and status. |
OUT_FACILITIES | Vector (Point) | — | Facility load with capacity, assigned, remaining, utilisation, status. |
Output Description
Demand: facility (string), net_cost (double, −1 = uncovered),
status (Assigned / Spilled / Uncovered), nearest (nearest facility ignoring capacity),
covered (0/1). Facilities: facility, capacity,
assigned, remaining, utilization, status (Full / Has space / Unused).
Interpretation Guide
- "Spilled" is the diagnostic gold: people with a facility nearby but no room. Compare their cost against the cost to their nearest to see the distance penalty capacity shortages impose.
- "Uncovered" = turned away entirely: the true unmet demand once seats are counted. Facility Adequacy would have assigned them and only flagged overload afterward.
- Unused facilities while others are Full: wrong side of demand or a barrier. Relocation candidates.
- Size capacity expansions by spilled+uncovered population per catchment. Test "expand vs. build new" by editing capacities vs. adding a facility and rerunning.
Academic References
Daskin, M.S. (1995). Network and Discrete Location. Wiley. DOI: 10.1002/9781118032343
Pirkul, H. & Schilling, D.A. (1991). "The Capacitated Maximal Covering Location Problem with Backup Service." Annals of Operations Research, 18, 141–154. DOI: 10.1007/BF02023099 [Note: this is volume 18 from 1989; the Annals volume numbering was unusual.]
Current, J., Daskin, M. & Schilling, D. (2002). "Discrete Network Location Models." In: Drezner, Z. & Hamacher, H.W. (eds.), Facility Location: Applications and Theory, pp. 81–118. Springer. DOI: 10.1007/978-3-642-56082-8_3
Land-Use Allocation Optimizer
Processing ID: planx:landallocation
Overview
Assigns a land use to each parcel to maximise a multi-objective function while respecting target area constraints for each use. The objective has three terms: suitability (area-weighted per-parcel score from user-provided fields), compactness (reward for adjacent same-use parcels, per unit of shared boundary), and adjacency (reward or penalty for specific use pairs as neighbours). A lock field freezes pre-zoned parcels. The method is greedy construction (best suitability first) followed by local search of reassignments and swaps that respect targets. The output is a draft zoning map (parcels with allocated use) and a summary table (target vs. allocated area per use with mean suitability achieved).
Theoretical Background
Land-use allocation as multi-objective spatial optimisation
The land-use allocation problem is a generalisation of the quadratic
assignment problem to spatial zoning: given N parcels each to be
assigned one of K land uses, with per-parcel suitability scores
and pairwise adjacency effects, find the assignment that maximises total
suitability plus total spatial quality (compactness + desirable adjacencies)
subject to area targets per use. The problem is NP-hard; the PlanX engine
(engine/allocate.py) implements a fast construction heuristic
with local improvement, not a global optimiser. Ligmann-Zielinska et al.
(2008) provide a comprehensive review of land-use allocation optimisation
methods.
Compactness as an urban design objective
Compactness is the most commonly imposed spatial objective in land-use plan optimisation because it operationalises a universal planning principle: like uses should cluster. Scattered single parcels of the same use are functionally equivalent to a zoned cluster but create fragmented urban form, longer infrastructure runs, and reduced walkability. The compactness term rewards each metre of shared boundary between same-use parcels, effectively subsidising clustering. The weight controls the suitability-compactness trade-off: at zero weight, the solver maximises pure suitability (scattered pattern); at high weight, it maximises compactness at the expense of suitability. The Pareto Front tool traces this trade-off systematically.
Adjacency rules as planning policy
Adjacency rules encode normative planning preferences: residential next to
industry is undesirable (negative weight); residential next to green space
is desirable (positive weight). The rules are symmetric (residential|industry
= industry|residential) and optional. They operate as additions to the
objective: each metre of shared boundary between two uses contributes the
rule's value (positive or negative) to the total score. The rules are
delimited by comma or semicolon, with the format useA|useB=value.
Mathematical Formulation
Let xp,u ∈ {0, 1} indicate parcel p assigned to use u. The multi-objective function is:
$$\max \quad w_{suit} \cdot \underbrace{\sum_{p,u} a_p \cdot S_{p,u} \cdot x_{p,u}}_{\text{suitability}} \;+\; \underbrace{\sum_{(p,q) \in E} l_{pq} \cdot C_{u,v} \cdot x_{p,u} \cdot x_{q,v}}_{\text{spatial: compactness + adjacency}} \tag{1}$$subject to area targets (soft, via greedy construction + local search):
$$\sum_p a_p \cdot x_{p,u} \leq T_u \quad \forall u \tag{2}$$where ap is parcel area, Sp,u is parcel p's suitability for use u, lpq is shared boundary length between parcels p and q, Cu,v is the compatibility matrix (diagonal = compactness weight if > 0, off-diagonal = adjacency rule values), and Tu is the target area for use u.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
PARCELS | Vector (Polygon) | — | Parcels or cells to allocate. Projected CRS required. |
SUIT_FIELDS | Fields (Numeric) | — | One suitability field per land use (0–1 or 0–100). Field names become use labels. |
TARGETS | String | s_residential=50000, ... | Target area per use in map units squared. Key matches suitability field name exactly or by containment. |
AREA_FIELD | Field (Numeric) | geometry area | Parcel area field. Default: computed from geometry. |
LOCK_FIELD | Field | (optional) | Pre-assigned use name. Must match a suitability field name. |
W_COMPACT | Double | 0.0 | Compactness weight per unit shared boundary (0 = off). |
ADJACENCY | String | (optional) | Adjacency rules: useA|useB=value. + attracts, − repels. |
CONTIGUITY | Enum | Soft | Soft (compactness weight) or Hard (single connected zone per use). |
W_SUITABILITY | Double | 1.0 | Suitability weight relative to spatial terms (advanced). |
OUT_PARCELS | Vector (Polygon) | — | Allocated parcels with use, suitability, area, and lock flag. |
OUT_SUMMARY | Table | — | Per-use summary: target, allocated, balance, count, mean suitability, status (Met/Short). |
Output Description
Parcels: inherits source fields + alloc_use (string, empty = unassigned),
alloc_suit (per-parcel suitability of assigned use), alloc_area (parcel area),
locked (0/1 flag). Summary: use, target_area,
alloc_area, balance, n_parcels, mean_suit,
status (Met / Short / empty for unassigned).
Interpretation Guide
- The map is a draft zoning proposal: "where the evidence wants each use." Edit for what the model cannot know (ownership, politics, phasing).
- mean_suit per use shows the price of pattern: if residential averages 0.9 and industry 0.4, industry is being pushed onto land the evidence dislikes.
- Scattered same-use parcels (compactness=0): honest suitability but poor zoning — raise compactness weight and watch mean_suit: the drop measures what tidy form costs.
- Compare against the hand-drawn plan: parcels where they disagree deserve written justification either way.
Academic References
Ligmann-Zielinska, A., Church, R.L. & Jankowski, P. (2008). "Spatial Optimization as a Generative Technique for Sustainable Multiobjective Land-Use Allocation." International Journal of Geographical Information Science, 22(6), 601–622. DOI: 10.1080/13658810701587495
Cao, K., Huang, B., Wang, S. & Lin, H. (2012). "Sustainable Land Use Optimization Using Boundary-Based Fast Genetic Algorithm." Computers, Environment and Urban Systems, 36(3), 257–269. DOI: 10.1016/j.compenvurbsys.2011.08.001
Aerts, J.C.J.H., Eisinger, E., Heuvelink, G.B.M. & Stewart, T.J. (2003). "Using Linear Integer Programming for Multi-Site Land-Use Allocation." Geographical Analysis, 35(2), 148–169. DOI: 10.1111/j.1538-4632.2003.tb01106.x
Land-Use Pareto Front
Processing ID: planx:paretoallocation
Overview
Maps the trade-off between suitability and compactness in land-use allocation by solving the allocation problem across a sweep of compactness weights (from zero = pure suitability to an auto-scaled upper bound where compactness dominates). For each weight, the tool records the area-weighted suitability achieved and the total shared same-use boundary (compactness). Solutions not dominated on both scores by any other form the Pareto front (non-dominated set). The knee — the front point furthest from the chord joining the extremes — is the mathematically best-balanced compromise. Three solutions are exportable: the knee (default), maximum suitability, or maximum compactness.
Theoretical Background
Pareto optimality in multi-objective spatial planning
A solution is Pareto optimal if no other feasible solution is at least as good on all objectives and strictly better on at least one (Pareto, 1906). In land-use allocation, the two objectives (suitability and compactness) are usually in tension: forcing parcels into compact zones requires overriding per-parcel suitability signals. The Pareto front maps this tension: each point on the front is a distinct allocation plan that is undominated — you cannot improve suitability without losing compactness, and vice versa. The front itself is the evidence base for the planning decision; the choice of which point on the front to adopt is a value judgement (Deb, 2001).
The knee as a compromise heuristic
The knee point — the point on the front with the maximum perpendicular distance from the line joining the two extreme solutions (pure suitability and maximum compactness) — is a formalisation of "best trade-off." It is the point where the marginal rate of transformation between the two objectives changes most sharply; beyond it, further gains in one objective come at increasingly disproportionate cost in the other. The knee is a suggestion, not a verdict. In planning practice, a preference for orderly urban form may justify selecting a point to the right of the knee (more compact, less suitable); a preference for market-responsive zoning may justify the left side (more suitable, less compact).
Mathematical Formulation
For compactness weight wi in the sweep {w0 = 0, w1, ..., wK−1}, the allocation engine produces solution i with scores:
$$S_i = \text{suitability}_i, \quad C_i = \text{compactness}_i \tag{1}$$Normalised to [0, 1] for plotting:
$$\text{suit\_norm}_i = \frac{S_i - \min_j S_j}{\max_j S_j - \min_j S_j} \tag{2}$$ $$\text{compact\_norm}_i = \frac{C_i - \min_j C_j}{\max_j C_j - \min_j C_j} \tag{3}$$Solution i is on the Pareto front if:
$$\nexists j: \big(S_j > S_i \land C_j \geq C_i\big) \lor \big(C_j > C_i \land S_j \geq S_i\big) \tag{4}$$The knee is:
$$\text{knee} = \arg\max_i \left[ \text{on\_front}[i] \cdot \text{dist}\big((\text{suit\_norm}_i, \text{compact\_norm}_i),\ \overline{(1,0)(0,1)}\big) \right] \tag{5}$$The weight range auto-scales. The upper bound wmax is computed from the pure-suitability solution: wmax = 6 × S0 / Ltotal, where Ltotal is the total shared parcel boundary length, ensuring that compactness can clearly dominate at the upper end.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
PARCELS | Vector (Polygon) | — | Parcels with suitability fields. Projected CRS. |
SUIT_FIELDS | Fields (Numeric) | — | One suitability field per land use. |
TARGETS | String | s_residential=50000, ... | Target area per use. Key matches field name. |
AREA_FIELD | Field (Numeric) | geometry area | Optional parcel area field. |
LOCK_FIELD | Field | (optional) | Pre-assigned use name for frozen parcels. |
N_POINTS | Integer | 9 | Number of weights to sample (2–25). More = smoother front. |
W_MAX | Double | 0 (auto) | Maximum compactness weight. 0 = auto-scale from data. |
SOLUTION | Enum | Knee | Which solution to export as parcel map: Knee, Max suitability, or Max compactness. |
W_SUITABILITY | Double | 1.0 | Suitability weight relative to compactness (advanced). |
OUT_FRONT | Table | — | Front table: one row per weight sample. |
OUT_PARCELS | Vector (Polygon) | — | Allocated parcels for the selected solution. |
Output Description
Front: point (int, 0..N−1), w_compact (double),
suitability, compactness, suit_norm, compact_norm
(all double, 0–1), on_front (0/1), knee (0/1), selected
(0/1), n_swaps, n_reassign. Parcels: inherits source
fields + alloc_use, alloc_suit, alloc_area,
sel_weight (the compactness weight of the exported solution).
Interpretation Guide
- Plot suit_norm vs. compact_norm for on-front points: the shape of the curve is the finding. A flat stretch = compactness is nearly free (take it). A steep drop = clustering costs real suitability.
- The knee is a suggestion, not a verdict. Orderly zoning may sit right of the knee deliberately — the point is that you now know the price.
- Dominated rows (on_front=0) still useful: many dominated points close to the front = solution is robust to weight choice.
- Front collapsing to one point: suitability surfaces already agree with compact form — no trade-off to argue about.
Academic References
Deb, K. (2001). Multi-Objective Optimization Using Evolutionary Algorithms. Wiley. [No standard DOI; the foundational text on multi-objective optimisation and the knee concept.]
Pareto, V. (1906). Manuale di Economia Politica. Societa Editrice Libraria. [Translated 1971 by A.M. Kelley. The origin of Pareto optimality.]
Ligmann-Zielinska, A., Church, R.L. & Jankowski, P. (2008). "Spatial Optimization as a Generative Technique for Sustainable Multiobjective Land-Use Allocation." IJGIS, 22(6), 601–622. DOI: 10.1080/13658810701587495
Das, I. & Dennis, J.E. (1998). "Normal-Boundary Intersection: A New Method for Generating the Pareto Surface in Nonlinear Multicriteria Optimization Problems." SIAM Journal on Optimization, 8(3), 631–657. DOI: 10.1137/S1052623496307510
Capacitated Facility Siting
Processing ID: planx:capacitatedsiting
Overview
Simultaneously selects sites and assigns demand under per-site capacity constraints — siting and sizing together. First, greedy construction: each step evaluates all unselected candidates by running a full capacitated allocation (nearest-with-spill, respecting capacities) and picks the candidate that maximises newly served demand. Then, Teitz-Bart vertex substitution: each selected site is swapped with each unselected candidate, re-running the full allocation, and the swap that increases served demand (or ties on served demand while reducing total cost) is accepted. Iterates until no improving swap is found (or max_iter). Existing facilities are fixed-open with their own capacities.
Theoretical Background
Capacitated facility location problems
The capacitated facility location problem (CFLP) is the extension of the p-median/covering models where facilities have finite capacity (Daskin, 1995). Unlike uncapacitated models where the only question is where, the CFLP asks where AND how big. The interaction between location and capacity is the key difficulty: a site with a good location but small capacity may be less valuable than a marginally worse location with large capacity, and the trade-off depends on the entire demand distribution. The CFLP is NP-hard; the greedy + Teitz-Bart heuristic implemented here produces solutions within 10–20% of optimal for typical urban instances (Current, Daskin & Schilling, 2002).
Greedy construction with embedded allocation
The distinguishing feature of the PlanX implementation is that each
candidate evaluation runs a full capacitated allocation (
capacitated_assign), not a simplified scoring function. This is
computationally expensive — O(p × C
× full allocation cost) for construction, where C is the
candidate count — but it guarantees that the marginal gain of each
pick is the actual additional served demand under the capacity
constraints, not an optimistic estimate that ignores the interaction
between multiple constrained facilities. This is critical for siting
decisions where capacity is scarce relative to demand.
Joint siting and sizing as a build programme
Unlike Facility Location Optimizer (which selects sites without considering how much capacity each should have), Capacitated Facility Siting produces a build programme: a ranked list of sites, each with the served population, utilisation rate, and marginal gain (how many more people are served because of this facility). The utilisation rate on each selected site indicates whether the assumed capacity is the binding constraint: near 1.0 means "if you can build bigger here, you should."
Mathematical Formulation
Let D(C×N) be the cost matrix, w(N) be demand weights, cap(C) be capacities. For a set of open sites S, the evaluation function runs capacitated_assign(D[S, :], w, cap[S]) and returns:
$$\text{served}(S) = \sum_{d: \text{assign}[d] \neq -1} w_d \tag{1}$$ $$\text{total\_cost}(S) = \sum_{d: \text{assign}[d] \neq -1} \text{cost}[d] \cdot w_d \tag{2}$$Greedy construction picks the candidate c that maximises:
$$\text{gain}(c) = \text{served}(S \cup \{c\}) - \text{served}(S) \tag{3}$$with total_cost as a tiebreaker (lower is better) when served demand is equal. Teitz-Bart swap replaces s ∈ S with c ∉ S if:
$$\text{served}(S \setminus \{s\} \cup \{c\}) > \text{served}(S) \quad \lor \quad \big(\text{served equal} \land \text{total\_cost lower}\big) \tag{4}$$Selected indices are reported with marginal gain derived from the objective history: gaink = obj_history[k][0] − obj_history[k−1][0] for the k-th pick.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | — | Street network. Projected CRS. Optional cost field for time-based analysis. |
DEMAND | Vector (Any) | — | Demand points with population weights. |
POP_FIELD | Field (Numeric) | 1/point | Population field. |
CANDIDATES | Vector (Any) | — | Candidate sites. Each must have a capacity and ID. |
CANDIDATE_ID | Field | — | Candidate identifier field. |
CAPACITY_FIELD | Field (Numeric) | — | Capacity per candidate site in persons (≥ 0). |
EXISTING | Vector (Any) | (optional) | Existing facilities fixed-open. |
EXISTING_ID | Field | (optional) | Existing facility identifier. |
EXISTING_CAP_FIELD | Field (Numeric) | (optional) | Existing facility capacity. Default: very large (essentially uncapacitated). |
P | Integer | 3 | Number of new facilities to site (≥ 1). |
MAX_COST | Double | 500.0 | Maximum travel cost (catchment limit) in map units. |
COST_FIELD | Field (Numeric) | length | Optional cost field on network for time-based analysis. |
OUT_SITES | Vector (Point) | — | Selected (open) facilities with rank, load, utilisation, and gain. |
OUT_ALLOCATION | Vector (Line) | — | Straight allocation lines from each assigned demand to its facility. |
OUT_UNCOVERED | Vector (Point) | — | Demand points that could not be assigned (capacity or distance reasons). |
Output Description
Sites: inherits candidate fields + facility (string label),
rank (int, 0 for existing), load (assigned population),
utilization (load/capacity), gain (marginal served demand added).
Allocation: facility, net_cost (straight lines).
Uncovered: copies of demand point features that received no assignment.
Interpretation Guide
- A site is only picked if its capacity can absorb nearby demand — the chosen set is a build programme, not just locations. The output answers "build these p facilities at these sizes."
- Utilisation near 1.0 on a selected site: capacity is the binding constraint. If the real project can build bigger there, raise the capacity and rerun — the selection may simplify (fewer sites needed).
- Gain per rank is the business case per facility. When gain flattens, additional sites mostly shuffle demand rather than serve new people — the diminishing-returns signal.
- Run p = 1, 2, 3... and chart served demand vs. p: the investment-staging curve. The elbow is the efficient programme size.
- Uncovered output splits into two types: "too far from every open site" (location gap — look for missing candidate) and "in reach but everything full" (capacity gap — size up). Long allocation lines crossing a competitor's catchment suggest a network barrier in the data.
Academic References
Daskin, M.S. (1995). Network and Discrete Location. Wiley. DOI: 10.1002/9781118032343
Teitz, M.B. & Bart, P. (1968). "Heuristic Methods for Estimating the Generalized Vertex Median." Operations Research, 16(5), 955–961. DOI: 10.1287/opre.16.5.955
Current, J., Daskin, M. & Schilling, D. (2002). "Discrete Network Location Models." In: Drezner, Z. & Hamacher, H.W. (eds.), Facility Location: Applications and Theory, pp. 81–118. Springer. DOI: 10.1007/978-3-642-56082-8_3
Church, R. & ReVelle, C. (1974). "The Maximal Covering Location Problem." Papers of the RSA, 32(1), 101–118. DOI: 10.1007/BF01942293
Melo, M.T., Nickel, S. & Saldanha-da-Gama, F. (2009). "Facility Location and Supply Chain Management — A Review." European Journal of Operational Research, 196(2), 401–412. DOI: 10.1016/j.ejor.2008.05.007
9. Equity
The Equity group translates the question "is this a fair city?" into
quantitative metrics. Three tools build on the general-purpose inequality
engine (engine/equity.py) — a pure-NumPy module that computes
the Gini coefficient, Theil's T index (with additive between/within-group
decomposition), the Atkinson index at user-specified inequality-aversion,
Lorenz and concentration curves, Duncan & Duncan dissimilarity indices,
and population-weighted cross-tabulations. Every metric is population-weighted
by default (one person per unit if no weight field is provided), and all
indices treat the input value as a non-negative "good" — negatives are clipped
to zero.
The three tools form a diagnosis chain: Accessibility Equity produces the headline inequality numbers (Gini, Theil, the between-share that answers the environmental-justice question); Inequality Curves gives the distributional view with exportable Lorenz/Concentration curve points and the Atkinson welfare interpretation; Demographic Equity Cross-Tabs identifies who is over-represented in the worst-served quintile — the evidence that moves from aggregate inequality to actionable equity targeting.
Accessibility Equity (Gini / Theil)
Processing ID: planx:accessequity
Overview
Measures how fairly a spatial quantity — an access score, a travel time, a distance to the nearest facility — is distributed across the population. This is the distributional complement to every level-of-access tool in PlanX: the 15-Minute City Access Score tells you how much access the average resident has; Accessibility Equity tells you whether that access is concentrated in a few privileged locations or spread evenly across everyone.
The tool computes the full suite of population-weighted inequality indices from a single input layer of spatial units, each carrying a value (the access metric) and an optional population weight. When a group field is provided (district, income class, tenure type), Theil's T is additively decomposed into the share of inequality that exists between groups and the share that exists within groups — the decomposition that gives equity analysis its policy teeth: between-group inequality is addressable by place-based investment; within-group inequality requires household-level targeting.
Outputs include the annotated input units (with their population-weighted percentile rank, deviation from the mean, and an access-poverty flag) and a summary table with all indices for the full study area and per group.
Theoretical Background
The measurement of economic inequality has a century-long lineage in welfare economics and econometrics, but its application to spatial equity in urban planning is more recent — crystallising in the environmental justice literature of the 1990s and 2000s (Talen & Anselin, 1998; Lucas, 2012). Three intellectual traditions converge in this tool:
The Gini coefficient (Gini, 1912) is the most widely recognised inequality metric. Originally proposed as the mean absolute difference between all pairs of incomes divided by twice the mean, its geometric interpretation as twice the area between the Lorenz curve and the line of equality makes it visually intuitive. In spatial applications, Gini values above 0.4 are conventionally "high" (the OECD threshold for income inequality), but access to public goods tends to be more equal than income — a Gini of 0.2 for park access is typical in a reasonably planned city; 0.35 signals serious concentration.
Theil's T index (Theil, 1967) belongs to the Generalised Entropy class and is the only inequality measure that is additively decomposable by population subgroup without a residual term. Shorrocks (1980) proved that this property — the ability to write $T = T_{\text{between}} + T_{\text{within}}$ as an exact identity — is unique to the Generalised Entropy class. The decomposition answers the fundamental policy question: if we equalise group means (by investing in underserved districts), how much of the inequality disappears? If the between-share is 60%, place-based investment eliminates the majority of the problem. If it is 15%, the inequality is overwhelmingly within-group and requires household-level or individual-level targeting.
The P90/P10 ratio and coefficient of variation provide non-specialist translations: "the best-served tenth have 4.2 times the access of the worst-served tenth" is intelligible to a planning committee member who cannot interpret a Theil value of 0.18.
The population-weighting scheme is critical for spatial equity because spatial units (grid cells, census tracts, parcels) vary enormously in population. An unweighted Gini over grid cells would treat a cell with 1 person and a cell with 1,000 people identically. The PlanX engine uses the same weighted formulas as official income-inequality statistics (LIS, OECD), where each observation carries a sample weight. The percentile rank uses mid-rank for ties: when $k$ units share the same value, they all receive the rank at the midpoint of their collective mass.
Mathematical Formulation
Population-weighted Gini coefficient (sorted form, $O(n \log n)$):
$$G = \frac{\sum_{i=1}^{n} w_i \left( x_i \cdot W_i^{\text{below}} - S_i^{\text{below}} \right)}{W \cdot S} \tag{5}$$where $W_i^{\text{below}} = \sum_{j: x_j < x_i} w_j$ is the population weight strictly below unit $i$ in the sorted order, $S_i^{\text{below}} = \sum_{j: x_j < x_i} w_j x_j$ is the corresponding cumulative value, $W = \sum w_i$, and $S = \sum w_i x_i$. This is equivalent to the mean-difference form but avoids the $O(n^2)$ pairwise comparison.
Population-weighted Theil's T index:
$$T = \frac{1}{W} \sum_{i=1}^{n} w_i \cdot \frac{x_i}{\mu} \cdot \ln\!\left(\frac{x_i}{\mu}\right) \tag{4}$$where $\mu = \frac{1}{W} \sum w_i x_i$. Values of $x_i \leq 0$ contribute zero (as $\lim_{r \to 0^+} r \ln r = 0$); negatives are clipped to zero by the engine.
Additive decomposition (Shorrocks, 1980):
$$T = T_{\text{between}} + T_{\text{within}} \tag{3}$$ $$T_{\text{between}} = \sum_{g=1}^{G} s_g \cdot \ln\!\left(\frac{\mu_g}{\mu}\right) \tag{2}$$ $$T_{\text{within}} = \sum_{g=1}^{G} s_g \cdot T_g \tag{1}$$where $s_g = (W_g \cdot \mu_g) / (W \cdot \mu)$ is group $g$'s share of the total value (not its population share), $\mu_g$ is the group's weighted mean, and $T_g$ is the Theil index computed within group $g$ alone. The between-share $T_{\text{between}} / T$ is the headline environmental-justice number.
P90/P10 ratio: $\text{P90/P10} = Q(0.9) / Q(0.1)$, where $Q(q)$ is the population-weighted $q$-quantile. Zero if $Q(0.1) = 0$ (all value concentrated above the 10th percentile).
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Units layer | Vector (any geometry) | Yes | Spatial units carrying the value to be measured — grid cells, census tracts, building centroids, parcel points. Each feature must have a numeric value and optionally a population weight and group label. |
| Value field | Numeric | Yes | The per-unit value whose distribution is being measured. Typically the output of an access-score tool (nearest-facility cost, 15-minute score, green-space distance). |
| Population field | Numeric | No | Per-unit population weight. Defaults to 1 per unit (unweighted). For census tracts, use total population. For grid cells, use the dasymetrically allocated population from the Density Grid tool. |
| Group field | Any | No | Categorical field for between/within decomposition. District name, income quintile, tenure type, urban/rural indicator. Without it, the decomposition is skipped and the Theil is reported as a single number. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
INPUT | Vector (Any) | — | Units with a numeric value field. |
VALUE_FIELD | Field (Numeric) | — | Per-unit value (access score, travel time, distance). Must be numeric and finite — NULL values skip the feature. |
POP_FIELD | Field (Numeric) | (optional) | Population weight per unit. NULL or negative → weight = 0. If all weights sum to zero, each unit counts as 1. |
GROUP_FIELD | Field | (optional) | Group identifier for decomposition. String or numeric — cast to string internally. |
DIRECTION | Enum | "Higher is better" (0) | 0 = the value is a "good" (access score, green space). 1 = the value is a "bad" (travel time, distance). Affects the access-poverty flag (below vs. above threshold). |
POVERTY | Double | (optional) | Access-poverty threshold. For "higher is better": population share with value below this. For "lower is better": population share with value above. NULL = no poverty flag. |
OUT_POINTS | Vector (same geometry) | — | Input units annotated with eq_value, pct_rank, dev_mean, poverty. |
OUT_SUMMARY | Table | — | Summary table: one "ALL" row plus one row per group. |
Output Description
Units layer (OUT_POINTS)
| Field | Type | Description |
|---|---|---|
eq_value | Double | The value as read (clipped to non-negative for inequality indices; raw for display). |
pct_rank | Double | Population-weighted percentile rank 0–100. 0 = worst-off (lowest value, for a "good"); 100 = best-off. Mid-rank for ties. Map this field — the bottom 10% are the structurally underserved. |
dev_mean | Double | Value minus the population-weighted mean. Positive = above average; negative = below. Use for a diverging colour map centred at zero. |
poverty | Integer | 0 = not in access poverty; 1 = in access poverty (below threshold for "higher is better" direction, or above threshold for "lower is better"). NULL if the POVERTY parameter was not set. |
Summary table (OUT_SUMMARY)
| Field | Type | Description |
|---|---|---|
scope | String | "ALL" or the group label (from the group field). |
population | Double | Total population weight in this scope. |
mean | Double | Population-weighted mean value. |
median | Double | Population-weighted median (50th percentile). Compare with mean — mean > median signals right-skew (a few units have very high access). |
gini | Double | Gini coefficient 0–1. Higher = more inequality. |
theil | Double | Theil's T index. 0 = equality; no upper bound in principle but rarely exceeds 1 in spatial applications. |
theil_btw | Double | Between-group Theil (only on "ALL" row; 0 on per-group rows). |
theil_wth | Double | Within-group Theil. |
cv | Double | Coefficient of variation = std / |mean|. 0 = equality. |
p90_p10 | Double | P90/P10 ratio. Plain-language inequality: "the best-served tenth has X times the access of the worst-served." |
pov_share | Double | Fraction of population in access poverty (0–1). NULL if threshold not set. |
Symbolic Representation
Map pct_rank with a sequential multi-hue ramp (Plasma, 5
quantile classes: 0–20 = worst-off, dark; 80–100 = best-off, bright yellow).
For publication, use a bivariate scheme: pct_rank on one panel
and pop (population weight) on the other — a cell that is both
low-rank AND high-population is a priority intervention site. Map
poverty = 1 cells in red, opacity 60%, over a light basemap for
the deprivation landscape. The summary table is best presented as a formatted
table with the "ALL" row at the top and groups in descending order of between-
group contribution.
Interpretation Guide
Diagnostic benchmarks
| Index | Low | Moderate | High | Interpretation |
|---|---|---|---|---|
| Gini (access) | <0.20 | 0.20–0.35 | >0.40 | >0.4 = a few places monopolise the access. <0.2 = well-distributed — but check the mean: perfect equality at a miserable level (mean = 2 on a 0–100 scale) is not a goal. |
| Theil between-share | <0.15 | 0.15–0.40 | >0.60 | >0.6 = most inequality is between groups — group-targeted investment will reduce it substantially. <0.15 = inequality is within-group — place-based policy will miss it. |
| P90/P10 | <1.5 | 1.5–3.0 | >4.0 | A ratio >4.0 is hard to justify for any publicly provided service. Even 3.0 warrants scrutiny. |
Cross-references with other PlanX tools
- Accessibility Score (15-Minute City): feed its output as the value field. The equity indices then measure how fairly walkable access to daily amenities is distributed. Run before and after a proposed intervention package — a plan that raises the mean access but also raises the Gini is concentrating the benefit on already-served areas.
- Nearest Facility Allocation: use
net_costas the value field with direction "lower is better." The equity indices then measure how fairly travel burden is distributed. A high Gini on travel cost means some residents travel much further than others for the same service. - Scenario Compare (A/B): the summary table rows can be fed as scenario snapshots. Comparing the "ALL" row Gini between baseline and proposed plan quantifies the equity impact of the entire plan in one number.
- Demographic Equity Cross-Tabs: when the Gini/Theil indicates a problem, the cross-tabs identify which demographic group bears it. Read these two outputs together: the equity summary says "how unequal," the cross-tab says "who loses."
Pitfalls
- Zero-mean populations. If the value is zero for all units in a group, the group's Theil is zero (perfect equality at zero) and the between-group log term involves $\ln(0/\mu) = -\infty$. The engine handles this by skipping zero-mean groups in the decomposition and issuing no error — but the between-share should be interpreted with caution if any group has a zero or near-zero mean.
- Modifiable areal unit problem (MAUP). The Gini and Theil computed on one spatial partition (e.g., census tracts) differ from the same indices computed on another (e.g., grid cells). This is not a bug — it is the fundamental scale-dependency of spatial inequality. Always report the spatial unit with the index. For sensitivity analysis, recompute at a coarser partition and check whether the ranking of groups (not the absolute values) is stable.
- Population weight quality. The indices inherit all errors in the population field. If census population is allocated to grid cells via area- weighted disaggregation (as in the Density Grid tool), the equity metrics assume uniform population distribution within each source zone — which smooths inequality. For rigorous equity assessment, use the finest available population data.
Academic References
Gini, C. (1912). "Variabilita e mutabilita: Contributo allo studio delle distribuzioni e delle relazioni statistiche." Studi Economico-Giuridici dell'Universita di Cagliari, 3(2), 3–159. classic work, original Italian publication, no DOI]
Theil, H. (1967). Economics and Information Theory. North-Holland. (Chapter 4: the derivation of the T index and its decomposition by population subgroup.) classic monograph, no DOI assigned]
Shorrocks, A.F. (1980). "The Class of Additively Decomposable Inequality Measures." Econometrica, 48(3), 613–625. DOI: 10.2307/1913126
Talen, E. & Anselin, L. (1998). "Assessing Spatial Equity: An Evaluation of Measures of Accessibility to Public Playgrounds." Environment and Planning A, 30(4), 595–613. DOI: 10.1068/a300595
Lucas, K. (2012). "Transport and Social Exclusion: Where Are We Now?" Transport Policy, 20, 105–113. DOI: 10.1016/j.tranpol.2012.01.013
Sen, A. (1973). On Economic Inequality. Clarendon Press. (The foundational philosophical treatment of inequality measurement, including the normative basis of the Atkinson index.) DOI: 10.1093/0198281935.001.0001
Inequality Curves (Lorenz & Atkinson)
Processing ID: planx:inequalitycurves
Overview
Draws the Lorenz curve — the full distributional map of how a value is spread across the population — and computes the Atkinson inequality index at multiple levels of inequality aversion. This is the visual complement to the headline numbers from Accessibility Equity: while the Gini is a single scalar, the Lorenz curve reveals where the inequality lives — at the bottom tail, spread through the middle, or concentrated at the top. The Atkinson index adds a normative dimension: it tells you how much total value society would be willing to sacrifice to equalise the distribution, depending on how much society cares about the worst-off.
An optional rank field (deprivation index, income decile, vulnerability score) converts the Lorenz curve into a concentration curve: instead of ordering units by the value itself, they are ordered by the external rank, revealing whether the value systematically concentrates on the advantaged or disadvantaged end. The concentration index is signed — negative when the value accrues to the disadvantaged, positive when to the advantaged — and is the most pointed single-number equity diagnostic in the PlanX suite.
Outputs: a curve-points table ($n+1$ rows per cumulative step, exportable to any charting tool) and a summary table with the Gini and Atkinson indices at $\varepsilon \in \{0.5, 1.0, 2.0\}$ plus the user's custom $\varepsilon$.
Theoretical Background
The Lorenz curve (Lorenz, 1905). Max Otto Lorenz proposed plotting the cumulative share of a quantity against the cumulative population share as a graphical device for comparing inequality across distributions. The curve always starts at $(0, 0)$ and ends at $(1, 1)$, bowing below the 45-degree line of perfect equality. The further the bow, the greater the inequality. The curve is the unequivocal visual standard for distributional comparison: curves that do not cross are unambiguously comparable (the curve closer to the diagonal dominates in the Lorenz sense), while crossing curves require a normative judgment about which part of the distribution matters more.
The concentration curve is the Lorenz curve's externally ordered counterpart. When units are ordered by a variable other than the one being measured, the resulting concentration curve reveals systematic association: if access to green space rises with income, the concentration curve bows below the Lorenz curve (the same green space would appear more unequal when ordered by income than by access itself). The concentration index (Kakwani, 1977) — twice the area between the concentration curve and the equality line — is the standard metric in health economics for measuring socioeconomic inequality in health outcomes.
The Atkinson index (Atkinson, 1970) is the most explicitly normative inequality measure. Atkinson rejected the view that a single number (Gini, Theil) could adequately summarise inequality, arguing that any inequality measure implicitly embeds a social welfare function with a particular inequality-aversion parameter $\varepsilon$. His index explicitly surfaces this parameter:
At $\varepsilon = 0$, the planner is inequality-neutral — only the mean matters (Atkinson = 0 regardless of distribution). At $\varepsilon = 0.5$, mild aversion — moderate inequality registers. At $\varepsilon = 1.0$, the standard value in applied welfare economics — $A(1) = 0.25$ means "society would give up 25% of total value to equalise the distribution and be no worse off." At $\varepsilon = 2.0$, strong aversion — the lower tail dominates, the index explodes if anyone is near zero.
Comparing Atkinson across $\varepsilon$ levels is a sensitivity test for the location of pain: if $A(0.5) \approx A(2.0)$, the inequality is spread evenly — the bottom tail is not unusually deprived. If $A(0.5) \ll A(2.0)$ — e.g., 0.15 jumping to 0.65 — the inequality is concentrated in the very bottom tail: a few units have almost nothing while the rest are roughly equal. This pattern is the statistical signature of exclusion rather than dispersion and demands a different policy response (targeted inclusion vs. general redistribution).
Mathematical Formulation
Lorenz / concentration curve points. Units are sorted by their value $x_{(1)} \leq x_{(2)} \leq \cdots \leq x_{(n)}$ (or by the rank field, for a concentration curve). At step $k$:
$$P_k = \frac{\sum_{i=1}^{k} w_{(i)}}{\sum_{i=1}^{n} w_i}, \qquad L_k = \frac{\sum_{i=1}^{k} w_{(i)} x_{(i)}}{\sum_{i=1}^{n} w_i x_i} \tag{5}$$with $P_0 = L_0 = 0$. The curve is the set of points $\{(P_k, L_k)\}_{k=0}^{n}$.
Gini from Lorenz curve (trapezoidal rule):
$$G = 1 - \sum_{k=1}^{n} (P_k - P_{k-1}) \cdot (L_k + L_{k-1}) \tag{4}$$Equals the standard Gini when the ordering is by value itself; equals the concentration index when ordered by an external rank (which may be negative if the value falls as rank rises).
Atkinson index. For $\varepsilon \geq 0$, $\varepsilon \neq 1$:
$$\text{EDE} = \left( \frac{\sum_{i} w_i x_i^{1-\varepsilon}}{\sum_i w_i} \right)^{\frac{1}{1-\varepsilon}} \tag{3}$$ $$A(\varepsilon) = 1 - \frac{\text{EDE}}{\mu} \tag{2}$$For $\varepsilon = 1$, the equally-distributed-equivalent level is the weighted geometric mean:
$$\text{EDE}(1) = \exp\!\left( \frac{\sum w_i \ln x_i}{\sum w_i} \right) \tag{1}$$If any unit with positive weight has $x_i \leq 0$ when $\varepsilon \geq 1$, the geometric mean collapses to zero and $A(1) = 1$ — the index signals absolute deprivation. Values are clipped to non-negative before computation.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Units layer | Vector (any geometry) | Yes | Same as Accessibility Equity. Each feature carries a value. |
| Value field | Numeric | Yes | The value to distribute. Must be a non-negative "good." For a "bad" like travel time, transform first (e.g., $1/t$ or $\max\_time - t$). |
| Population field | Numeric | No | Per-unit weight. Defaults to 1. |
| Rank field | Numeric | No | External ordering variable for the concentration curve. Deprivation rank, income decile, vulnerability index. Anything that answers "does the value favour the advantaged?" |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
INPUT | Vector (Any) | — | Units with a numeric value field. |
VALUE_FIELD | Field (Numeric) | — | Non-negative value per unit. NULL → skipped. |
POP_FIELD | Field (Numeric) | (optional) | Population weight. Same semantics as Accessibility Equity. |
RANK_FIELD | Field (Numeric) | (optional) | External rank for concentration curve. Must be numeric and finite — NULL → feature skipped. When provided, the curve is a concentration curve and the concentration index is reported. |
EPSILON | Double | 1.0 | Inequality-aversion parameter for the Atkinson index. 0 = no aversion; 1 = standard (geometric mean); 2 = strong lower-tail weight. Values > 2 are allowed but the index becomes highly sensitive to near-zero values. |
OUT_CURVE | Table | — | Curve-points table with $n+1$ rows (from origin to 100/100). |
OUT_SUMMARY | Table | — | Metric/value summary table. |
Output Description
Curve table (OUT_CURVE)
| Field | Type | Description |
|---|---|---|
point | Integer | Point index 0 to $n$ (0 = origin, $n$ = 100/100). |
pop_share | Double | Cumulative population share at this point. The x-axis for charting. |
value_share | Double | Cumulative value share. The y-axis. The curve bows below the equality line. |
equality | Double | The equality line value (= pop_share). For charting the 45-degree reference. |
gap | Double | pop_share minus value_share. The vertical distance to equality at each point. Maximum gap is the Kolm index (the point where the gap is largest — the "most unfair" percentile). |
Summary table (OUT_SUMMARY)
| Field | Type | Description |
|---|---|---|
metric | String | Label: "Units (n)", "Population", "Mean value", "Gini", "Atkinson (epsilon=X)", "Concentration index" (if rank given). |
value | Double | The metric value. |
Symbolic Representation
The curve table is designed for charting outside QGIS — export to CSV and plot
in any tool (Python/matplotlib, R/ggplot2, Excel). Plot pop_share on
x, value_share and equality on y as two line series. The
filled area between them is the Gini area. For multi-scenario comparison, plot
Baseline and Proposed curves on the same axes with distinct colours — the curve
that moves toward the diagonal is distributional progress. For the concentration
curve with a rank, a curve that bows above the equality line (value
concentrated on the low-rank/disadvantaged end) is the equity goal; a curve
bowing below signals regressive distribution.
Interpretation Guide
The three Atkinson regimes
- $A(0.5) \approx A(1.0) \approx A(2.0)$: inequality is uniform across the distribution. Any transfer from the top to the bottom reduces the index by roughly the same amount regardless of $\varepsilon$. Policy response: general redistribution.
- $A(0.5) \ll A(2.0)$: the inequality is bottom-tail concentrated — a small share of the population has almost none of the value. This is the exclusion pattern. Policy response: targeted inclusion — find the bottom-tail units on the map and connect them.
- $A(0.5) \gg A(2.0)$ (rare): top-tail concentration — a few units hold most of the value. $\varepsilon = 0.5$ is more sensitive to top-end dispersion than $\varepsilon = 2.0$. This is the elite capture pattern — a gated community monopolising waterfront park access.
Concentration index reading
A negative concentration index (value concentrates on the disadvantage/lower- ranked end) is the equity-positive finding: the good is progressive. A positive concentration index — the value rises with rank — is regressive: the better-off enjoy more of the good. The magnitude matters less than the sign for policy direction, but $|\text{CI}| > 0.3$ is "strong" by the health-economics convention (O'Donnell et al., 2008).
Cross-references
- Accessibility Equity: the Gini from the Lorenz curve equals the Gini from the summary table — they are the same computation via different routes (trapezoidal integration vs. mean-difference form). If they disagree by more than a rounding tolerance, the data has been corrupted between runs.
- Scenario Compare: plot Baseline and Proposed Lorenz curves on the same chart. A shift toward the diagonal = distributional improvement. Read specific points: at $P = 0.5$, the $L$ value is the share held by the bottom half — if it moves from 0.20 to 0.28, the plan has meaningfully redistributed toward the less-served half.
Academic References
Lorenz, M.O. (1905). "Methods of Measuring the Concentration of Wealth." Publications of the American Statistical Association, 9(70), 209–219. DOI: 10.2307/2276207
Atkinson, A.B. (1970). "On the Measurement of Inequality." Journal of Economic Theory, 2(3), 244–263. DOI: 10.1016/0022-0531(70)90039-6
Kakwani, N. (1977). "Measurement of Tax Progressivity: An International Comparison." Economic Journal, 87(345), 71–80. DOI: 10.2307/2231833
O'Donnell, O., van Doorslaer, E., Wagstaff, A., & Lindelow, M. (2008). Analyzing Health Equity Using Household Survey Data. World Bank. (A practical guide to computing concentration indices with survey weights — the methodological template for the concentration-curve output.) DOI: 10.1596/978-0-8213-6933-3
Jenkins, S.P. & Van Kerm, P. (2009). "The Measurement of Economic Inequality." In: Salverda, W., Nolan, B. & Smeeding, T.M. (eds.), Oxford Handbook of Economic Inequality. Oxford University Press. DOI: 10.1093/oxfordhb/9780199606061.013.0003
Demographic Equity Cross-Tabs
Processing ID: planx:equitycrosstab
Overview
Answers the question that every equity analysis must answer: who is under-served? While Accessibility Equity gives aggregate inequality numbers and Inequality Curves gives the distributional shape, Demographic Equity Cross-Tabs names the groups. It cross-tabulates any per-unit value by one or two population subgroup fields, dividing the value axis into population-weighted quantile classes (default: quintiles — each class holds exactly 20% of the population). For every cell (group × value class), it reports the representation ratio: the group's share of that class's population divided by its share of the total population.
Per group, the tool also reports descriptive statistics (population share, value share, weighted mean, P10, median, P90, min, max), the within-group Gini coefficient, and the Duncan & Duncan dissimilarity index of the group against the rest of the population across the value classes. The dissimilarity index (0–1) sizes segregation — how different the group's distribution across value classes is from everyone else's. A value of 0.3 means 30% of the group would need to shift value classes to match the overall distribution — a structural pattern, not random variation.
A second group field enables two-way cross-tabulation: the groups become every "A | B" combination, enabling intersectional analysis (e.g., low-income × minority neighbourhoods). The units output annotates each input feature with its value class and its group's representation ratio in that class, enabling spatial mapping of over-representation in deprivation.
Theoretical Background
Cross-tabulation of welfare by demographic subgroup is the standard method in environmental justice (EJ) screening. The US EPA's EJSCREEN and California's CalEnviroScreen both operationalise EJ as disproportionate exposure of protected subgroups (by race, income, language) to environmental hazards. The representation ratio is favoured over simple proportional comparison because it controls for group size: a small group that appears to have many people in the worst quintile might simply be a large group in absolute terms. The ratio normalises this — 2.0 means "over-represented" regardless of group size.
Duncan & Duncan's dissimilarity index (1955) is the foundational measure of residential segregation. Originally proposed to measure racial segregation across census tracts, it has been adapted to any cross-tabulation where the question is "how evenly is this group spread across these categories?" Massey & Denton (1988) validated it as one of five dimensions of segregation (the "evenness" dimension) and established the interpretive benchmarks still used today: < 0.3 = low segregation; 0.3–0.6 = moderate; > 0.6 = high. In the equity-cross-tab context, "segregation" means the group's experience is structurally different from the population average — its members cluster in particular value classes rather than being spread evenly.
The population-weighted quantile approach (each class holds equal population) is preferred over equal-interval classes (each class spans the same value range) because it prevents classes from becoming empty or near-empty when the value is heavily skewed. With fixed breaks like "0–20, 20–40, 40–60, 60–80, 80–100," an access score that never exceeds 30 would leave the top three classes empty, making representation ratios meaningless. Quantile classes guarantee a populated cross-tabulation regardless of the value distribution.
Mathematical Formulation
Population-weighted quantile class boundaries. For $Q$ classes (default $Q = 5$), the inner edges are the weighted quantiles at probabilities $\{1/Q, 2/Q, \ldots, (Q-1)/Q\}$:
$$e_q = Q\!\left(\frac{q}{Q}\right), \quad q = 1, \ldots, Q-1 \tag{5}$$Unit $i$ is assigned to class $c_i = 0, \ldots, Q-1$ where $c_i$ is the position in the sorted breaks: $c_i = q-1$ for $x_i \in (e_{q-1}, e_q]$, with $e_0 = -\infty$ and $e_Q = +\infty$.
Representation ratio. For group $g$ in value class $k$:
$$R_{g,k} = \frac{\text{pop}_{g,k} / \sum_k \text{pop}_{g,k}}{\text{pop}_{*,k} / \sum_k \text{pop}_{*,k}} = \frac{\text{pop}_{g,k}}{\text{pop}_{*,k}} \cdot \frac{W}{W_g} \tag{4}$$where $\text{pop}_{g,k}$ is the weighted population of group $g$ in class $k$, $\text{pop}_{*,k}$ is the total weighted population in class $k$, $W_g$ is the total weight of group $g$, and $W$ is the grand total weight. $R_{g,k} = 1$ for proportional representation; $> 1$ for over-representation; $< 1$ for under-representation. NaN when either the class or the group is empty.
Duncan & Duncan dissimilarity index. For group $g$ against the rest of the population across $Q$ value classes:
$$D_g = \frac{1}{2} \sum_{k=1}^{Q} \left| \frac{\text{pop}_{g,k}}{W_g} - \frac{\text{pop}_{*,k} - \text{pop}_{g,k}}{W - W_g} \right| \tag{3}$$ $$0 \leq D_g \leq 1 \tag{2}$$Within-group Gini. For group $g$ with values $\{x_i : \text{group}(i) = g\}$ and weights $w_i$:
$$G_g = \frac{\sum_{i \in g} w_i \left( x_i \cdot W_i^{\text{below}(g)} - S_i^{\text{below}(g)} \right)}{W_g \cdot S_g} \tag{1}$$Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Units layer | Vector (any) | Yes | Same as Accessibility Equity. Must have a value, a group label, and ideally a population weight. |
| Value field | Numeric | Yes | The value to cross-tabulate. |
| Group field | Any | Yes | Demographic category. District, income bracket, tenure, ethnicity, age-group — the "who" of the equity question. |
| Second group field | Any | No | For two-way cross-tabs. Groups become "A | B" combinations. |
| Population field | Numeric | No | Per-unit weight. Defaults to 1. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
INPUT | Vector (Any) | — | Units with value and group fields. |
VALUE_FIELD | Field (Numeric) | — | Per-unit value. NULL → skipped. |
GROUP_FIELD | Field | — | Primary demographic group identifier. Empty labels → skipped. |
GROUP_FIELD_B | Field | (optional) | Second group field for intersectional cross-tabs. |
POP_FIELD | Field (Numeric) | (optional) | Population weight. Same semantics as other equity tools. |
N_CLASSES | Integer | 5 | Number of population-weighted quantile classes. 2–10. 5 = quintiles (standard); 4 = quartiles; 10 = deciles (fine detail, smaller cell populations). |
BREAKS | String | "" (use quantiles) | Fixed class breaks as comma-separated numbers, e.g. "50, 100, 150". Overrides N_CLASSES. Useful for threshold-based classification (policy standards). |
OUT_CELLS | Table | — | Cross-tabulation cells: one row per group × class. |
OUT_GROUPS | Table | — | Per-group summary statistics. |
OUT_UNITS | Vector (same) | — | Input units annotated with v_class, class_label, cell_rep. |
Output Description
Cross-tab cells (OUT_CELLS)
| Field | Type | Description |
|---|---|---|
group | String | Group label (or "A | B" for two-way). |
v_class | Integer | Value class index 1..Q (1 = lowest values = worst-off). |
class_label | String | Human-readable class description: "Q1 (lowest)" or "< 50". |
pop | Double | Weighted population of this group in this class. |
class_share | Double | Group's share of this class's total population (0–1). |
rep_ratio | Double | Representation ratio. NaN if group or class is empty. |
Group summary (OUT_GROUPS)
| Field | Type | Description |
|---|---|---|
group | String | Group label. |
pop | Double | Total weighted population. |
pop_share | Double | Group's share of total population. |
val_share | Double | Group's share of total value (sum of $w_i x_i$). If val_share < pop_share, the group gets less than its population would predict. |
mean, p10, median, p90 | Double | Weighted distribution statistics. Compare p10 across groups — equal means with unequal P10s signal that the group's worst-off are much worse off. |
gini | Double | Within-group Gini. High = even within this group, the value is unequally distributed. |
dissim | Double | Duncan & Duncan dissimilarity index versus the rest. |
Units with class (OUT_UNITS)
| Field | Type | Description |
|---|---|---|
v_class | Integer | Value class of this unit (1 = lowest/worst). |
class_label | String | Label for the class. |
cell_rep | Double | Representation ratio of this unit's group in this unit's value class. NaN if the group or class is empty. Map this field — high values in class 1 = the spatial pattern of disproportionate deprivation. |
Interpretation Guide
The equity-reading protocol
- Go to class 1 (worst-served). Scan
rep_ratiofor values above 1.5. These are the groups carrying disproportionate deprivation. A ratio above 2.0 is hard to explain away — the group is at least twice as concentrated in the lowest-value quintile as chance would predict. - Check group populations. Small groups make noisy ratios. A
ratio of 3.0 based on 12 people in a group of 50 is less robust than a ratio of
1.8 based on 12,000 in 50,000. Always read the
popfield alongsiderep_ratio— flag ratios based on < 100 weighted population as tentative. - Read the dissimilarity index.
dissim> 0.3 means the group's distribution is substantially different from the population average. Values > 0.5 signal deep structural segregation across the value classes — this group's experience of the city is systematically, not randomly, different. - Compare group means AND P10s. Equal means can conceal very different lower tails. If Group A and Group B both have a mean access score of 60, but Group A's P10 is 25 and Group B's P10 is 45, Group A's worst-off decile is nearly half as well-served as Group B's — a finding the mean alone would bury.
- Map class 1 units. On the
OUT_UNITSlayer, filter tov_class = 1and the over-represented group, and map in a single colour. Equity findings only persuade when they become places on the map. A planning committee member may dispute a table cell but cannot dispute a cluster of underserved neighbourhoods on a satellite basemap.
Cross-references
- Accessibility Equity: the between/within Theil decomposition tells you whether inequality is between groups. The cross-tab tells you WHICH groups account for the between-group share. Run the equity summary first to establish that between-group inequality exists; then run the cross-tab to name it.
- Walkability Audit / Access Score: any PlanX output that produces a per-unit score can be cross-tabbed against a demographic layer. A complete equity annex for a master plan would include cross-tabs of walkability scores, 15-minute access scores, and facility travel times — all against income, tenure, and age-group — in a single appendix.
Academic References
Duncan, O.D. & Duncan, B. (1955). "A Methodological Analysis of Segregation Indexes." American Sociological Review, 20(2), 210–217. DOI: 10.2307/2088328
Massey, D.S. & Denton, N.A. (1988). "The Dimensions of Residential Segregation." Social Forces, 67(2), 281–315. DOI: 10.1093/sf/67.2.281
Talen, E. (2001). "School, Community, and Spatial Equity: An Empirical Investigation of Access to Elementary Schools in West Virginia." Annals of the Association of American Geographers, 91(3), 465–486. DOI: 10.1111/0004-5608.00254
Walker, G. (2012). Environmental Justice: Concepts, Evidence and Politics. Routledge. (Chapter 4: "Evidence of Environmental Inequality" — the methodological framework for the EJ cross-tabulation approach.) DOI: 10.4324/9780203610671
US EPA. (2019). "EJSCREEN Technical Documentation." U.S. Environmental Protection Agency. (The operational EJ screening tool that standardised the representation-ratio approach for environmental-justice analysis.) government technical documentation, no DOI] Available at: epa.gov/ejscreen
11. Transit
The Transit group lifts public transport data from the raw GTFS schedule into spatial analysis. Three tools form a pipeline: GTFS Import validates and geocodes the feed, producing stop layers and route summaries for immediate visual audit; Transit Frequency Map answers "how often does it come?" for any time window on any service day — the service-intensity view that separates genuine frequent corridors from paper routes; Transit Travel-Time Access computes door-to-door travel times using walking on the street network plus timetable riding via a RAPTOR-style earliest-arrival algorithm, answering the rider's question: "how long does it actually take?" The entire pipeline is pure Python with zero external libraries beyond NumPy — GTFS reading, service-day resolution, and timetable search all run inside QGIS.
GTFS Import and Service Stats
Processing ID: planx:gtfsimport
Overview
Loads a GTFS (General Transit Feed Specification) zip archive into QGIS as two
layers and validates the feed on import. GTFS is the de-facto global standard for
publishing public transport schedules in open data — over 10,000 transit agencies
worldwide publish GTFS feeds, covering buses, metros, trams, ferries, and
cable-cars. The tool parses the four required files (stops.txt,
routes.txt, trips.txt, stop_times.txt) plus
the calendar files, resolves service-day logic (honouring calendar exceptions),
and computes per-stop daily departure counts and per-route service-span
statistics.
Times past midnight (e.g., 25:10:00 = 1:10 AM next day = 90,600
seconds since midnight) are handled natively as seconds — the engine never
converts to datetime objects, avoiding the standard GTFS-parsing pitfall of
incorrectly assigning overnight services to the wrong calendar day. The service
day defaults to the feed's first active day (the earliest calendar-start date
whose weekday is served), which the engine determines automatically unless the
user specifies a YYYYMMDD date. Validation errors — missing required files,
non-numeric coordinates, malformed time strings — are surfaced as clear exceptions
naming the offending field.
This tool is the mandatory first step before Transit Frequency Map or Transit Travel-Time Access: it validates the feed and produces the stop layer (the geocoded front door for all downstream transit analysis in PlanX) and the route table (the service-coverage diagnostic that separates real transit from paper routes).
Theoretical Background
GTFS was originally developed by Google and TriMet (Portland, Oregon) in 2005 as "Google Transit" and was released as an open specification in 2006. It has since become the universal interchange format for public transport schedule data, maintained as a de-facto standard by MobilityData International rather than by any standards body. The specification defines a relational model of routes, trips, stops, and scheduled times that can represent any fixed-route transit service.
The critical validation challenge in GTFS parsing is time handling.
The specification permits times to exceed 24:00:00 (i.e., 25:10:00 for a bus
departing at 1:10 AM the next day), meaning that times within a trip are
monotonically increasing seconds from a "service day midnight" origin. Converting
to datetime objects requires associating each time with a date, which the
specification does not directly provide for individual stop-times (only for the
service day as a whole via calendar.txt). PlanX's approach — keeping all times as
integer seconds and resolving service days independently — avoids this
date-association problem entirely. The parse_time function accepts
hours up to 30 (accommodating even extreme overnight services) and validates
minutes and seconds strictly (0–59).
Service-day resolution follows the GTFS calendar logic exactly:
a service runs on a given day if calendar.txt lists that day's weekday as active
AND the day falls between the service's start and end dates, AND no
calendar_dates.txt exception removes it (exception_type=2), OR calendar_dates.txt
explicitly adds it (exception_type=1). The engine's active_services
function implements this logic in ~15 lines, resolving the service set for a given
YYYYMMDD date including weekday calculation from the Gregorian calendar.
Mathematical Formulation
Time to seconds. For a GTFS time string $t = h:mm:ss$ where $h \in [0, 30]$, $m \in [0, 59]$, $s \in [0, 59]$:
$$t_{\text{sec}} = h \cdot 3600 + m \cdot 60 + s \quad [\text{seconds since midnight}] \tag{3}$$Stop-frequency summary. For a service day with active service IDs $\mathcal{S}$, stop $s$'s departures count:
$$D_s = \left| \{ (trip, stop\_seq) : \text{trip.service} \in \mathcal{S},\; t_{\text{start}} \leq dep_{trip, seq} < t_{\text{end}},\; seq \neq last \} \right| \tag{2}$$ $$N_{\text{routes}}(s) = \left| \{ route\_id : \exists trip \; \text{serving} \; s \; \text{in window} \} \right| \tag{1}$$The window defaults to the full service day (0:00 to 30:00 / 06:00 next day) for GTFS Import, providing the 24-hour presence count. Transit Frequency Map applies a user-specified window (e.g., 07:00–09:00 AM peak).
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| GTFS feed | ZIP file | Yes | Valid GTFS zip containing stops.txt, routes.txt, trips.txt, stop_times.txt, and at least one of calendar.txt or calendar_dates.txt. Most transit agencies provide this as a direct download from their open-data portal. |
| Service day | String (YYYYMMDD) | No | Empty = the engine picks the feed's first active day. Weekday vs. weekend schedules can differ by 50% of trips — always verify which day is being analysed. |
Where to obtain GTFS feeds: Transit agency open-data portals (e.g., TransitFeeds.com aggregates hundreds), national open-data platforms, or direct from the agency website. Always check the feed's validity period — some agencies publish feeds covering only the current timetable period and they expire.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
FILE | File (ZIP) | — | GTFS zip archive. Must contain the four required files. The tool validates and reports specific errors for missing files, missing fields, or malformed data. |
DAY | String | "" (first active) | Service day as YYYYMMDD or YYYY-MM-DD. Hyphens are stripped automatically. Empty = engine finds the first day with any service via first_service_day. |
OUT_STOPS | Vector (Point) | — | Transit stops in WGS84 (EPSG:4326). GTFS coordinates are always WGS84 by specification. |
OUT_ROUTES | Table | — | Route summary with trips, first/last departure, and maximum stop sequence on the chosen day. |
Output Description
Stops layer (OUT_STOPS)
| Field | Type | Description |
|---|---|---|
stop_id | String | Agency stop identifier as published in stops.txt. |
name | String | Stop name. Falls back to stop_id if the name field is empty (some feeds omit stop_names on minor stops). |
departures | Integer | Total scheduled departures from this stop on the chosen service day (full 24h window). The raw presence count — sort descending to identify the network's true hubs. |
n_routes | Integer | Number of distinct route_ids serving this stop on the chosen day. Stops with n_routes > 1 form the transfer skeleton of the network. |
Route summary (OUT_ROUTES)
| Field | Type | Description |
|---|---|---|
route_id | String | Agency route identifier. |
name | String | Route short name + long name, combined: "M1 - City Centre to Airport". |
mode | String | Transit mode from the standard GTFS route_type codes: Tram, Metro, Rail, Bus, Ferry, Cable tram, Aerial lift, Funicular, Trolleybus, Monorail. "Other" for unknown codes. |
n_trips | Integer | Number of trips operated by this route on the chosen day. 4 or fewer = paper route or peak-only; 50+ = genuine frequent corridor. |
first_dep | String | Earliest departure time (HH:MM, 24h). |
last_arr | String | Latest arrival time. A route whose last arrival is 19:00 does not serve evening shifts. |
n_stops | Integer | Maximum number of stops in the longest trip pattern on this route. Diagnostic for express vs. local service. |
Interpretation Guide
Pre-analysis validation checklist
- Verify stop locations on a basemap. Agency coordinate bugs are common — stops in the ocean, on airport runways, or offset by hundreds of metres. This is the most frequent GTFS quality problem. A 30-second visual scan against OpenStreetMap catches most errors.
- Check the service day. Weekday and weekend timetables can differ by half the trips. If the engine auto-selected a day, verify it is the day you intended. A Saturday feed analysed as a weekday will understate service by 30–50%.
- Scan the route table's
n_trips. Sort descending. Routes with < 5 trips/day are not meaningful service — they are school runs, peak-hour supplements, or on-demand services that the GTFS models poorly. Map them separately or exclude them from frequency analysis. - Check
last_arr. Routes ending before 20:00 cannot serve evening economy workers. The service span is as important as the frequency for equity analysis — a dense network that shuts down at 19:00 serves commuters, not shift workers or evening students.
Cross-references
- Transit Frequency Map / Transit Travel-Time Access: these
tools read the same GTFS zip directly — they share the
load_feedfunction. The stop layer from GTFS Import is the visual baseline; the frequency and access tools provide the quantitative rider-experience view. - Walking Slope Comfort: when computing walk-to-transit times,
use Walking Slope Comfort's
time_fwd_minas the street-network edge weight. The combined pipeline — GTFS Import (stops) + Walking Slope Comfort (network) + Transit Access (door-to-door) — gives the most realistic transit accessibility model in the PlanX suite. - Accessibility Equity: feed transit access times (from Transit Travel-Time Access) as the value field into Accessibility Equity. The Gini and Theil on transit travel times reveal whether transit mobility is equally available across the population.
Academic References
Google Inc. & TriMet. (2006–present). "General Transit Feed Specification (GTFS)." MobilityData International. open specification, no DOI assigned] Available at: gtfs.org
Walker, J. (2012). Human Transit: How Clearer Thinking about Public Transit Can Enrich Our Communities and Our Lives. Island Press. (The practitioner's bible on frequency mapping, the "frequent network" concept, and the distinction between coverage and ridership service design.) trade/practice book, no DOI assigned]
Cats, O., West, J., & Eliasson, J. (2016). "A Dynamic Stochastic Model for Evaluating Congestion and Crowding Effects in Transit Systems." Transportation Research Part B: Methodological, 89, 43–57. DOI: 10.1016/j.trb.2016.04.001
Transit Frequency Map
Processing ID: planx:transitfrequency
Overview
Answers the rider's first question about any transit system: how often does it come? Counts the scheduled departures at every stop within a user-specified time window on a single service day, and produces the two numbers riders feel: departures per hour and mean headway (minutes between services). The output is the classic "frequent network" map — the sub-network of stops where a rider can arrive without consulting a timetable and expect a vehicle within ~10 minutes. This is the single most informative transit map for land-use planning because frequency, not route coverage, is what drives transit-oriented development feasibility.
The tool reads the same GTFS zip as GTFS Import and compiles the timetable for a given day, counting every departure (a vehicle leaving the stop within the window; final arrivals at terminus stops do not count). The window defaults to the morning peak (07:00–09:00) — the standard window for frequent-network mapping — but can be set to any interval including the full service day. The output stop layer includes the raw departure count, per-hour frequency, mean headway in minutes, and the number of distinct routes serving the stop in the window. A supplementary route table lists the trips each route operates within the window.
Theoretical Background
Transit frequency is the operational parameter that structures a rider's entire experience. Jarrett Walker's concept of the "frequent network" — the set of routes and stops where service is frequent enough that riders do not need to consult a timetable — is the organising principle of modern transit planning (Walker, 2012). The conventional threshold is 6 departures per hour (10 minute headway), which studies consistently find to be the point at which waiting time ceases to dominate the perceived travel-time experience (Fan et al., 2016). Below this threshold — at 15, 20, or 30 minute headways — the timetable becomes the rider's master: a missed bus means a long wait, and the entire day is structured around the schedule.
The distinction between scheduled mean headway (total window duration divided by departure count) and the actual gap distribution is important. The mean headway reported here is a screening number — it does not reveal whether departures are evenly spaced (a reliable 10-minute clockface schedule) or bunched (three buses in 5 minutes, then nothing for 25). GTFS schedule data is the "as-planned" timetable; operational bunching (three buses arriving simultaneously due to traffic) is not represented. For route-level reliability analysis, the mean headway from GTFS is a ceiling — actual headways experienced by riders are worse.
Service span — the time between the first and last departure of the day — is as important as frequency for equity. A route with 12 departures per hour during a narrow peak window (07:00–09:00) but zero service after 19:00 serves only the 9-to-5 commuter. The all-day frequent network — stops served at 6+/hour across a 16-hour span — is far rarer and far more valuable for transit- oriented density than the peak-only frequent network. Comparing frequency at different windows (morning peak, midday, evening, weekend) reveals whether a "frequent" corridor is truly all-day frequent or peak-commuter-only.
Mathematical Formulation
Departures per hour. For stop $s$ with $D_s$ departures counted in a window of duration $\Delta t = t_{\text{end}} - t_{\text{start}}$ (in seconds):
$$f_s = \frac{D_s}{\Delta t / 3600} \quad [\text{departures/hour}] \tag{3}$$Scheduled mean headway. The reciprocal, converted to minutes:
$$h_s = \frac{\Delta t}{60 \cdot \max(1, D_s)} \quad [\text{minutes}] \tag{2}$$When $D_s = 0$, $h_s = 0$ (no service — or more precisely, $h_s = \Delta t / 60$, but the engine sets it to 0 as a "no service" sentinel). This is the window-mean, not the gap distribution. For a stop with $D_s = 6$ departures in a 2-hour window: $f_s = 3.0$/hour, $h_s = 20$ min — the schedule averages one bus every 20 minutes, though individual gaps may range from 10 to 30 minutes.
Distinct routes. A route is counted if at least one of its trips departs the stop within the window:
$$R_s = \left| \{ route\_id : \exists trip \; \text{of this route serving} \; s \; \text{in window} \} \right| \tag{1}$$Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| GTFS feed | ZIP file | Yes | Same feed as GTFS Import. The tool reads it directly — no need to pre-process. |
| Service day | String (YYYYMMDD) | No | Same semantics as GTFS Import. |
| Window | Two doubles (start/end hour) | Yes | Time window in decimal hours. 7.0–9.0 = AM peak; 10.0–14.0 = midday; 16.0–19.0 = PM peak. Times > 24 allowed for overnight windows (e.g., 22.0–26.0). |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
FILE | File (ZIP) | — | GTFS zip archive. |
DAY | String | "" (first active) | Service day YYYYMMDD. |
START | Double | 7.0 | Window start (hour of day, decimal). 7.0 = 07:00. |
END | Double | 9.0 | Window end. Must exceed start. 9.0 = 09:00. For the full service day, use 0.0 and 30.0. |
OUT_STOPS | Vector (Point) | — | Stop frequency points in WGS84. |
OUT_ROUTES | Table | — | Route trips in the window. |
Output Description
Stop frequencies (OUT_STOPS)
| Field | Type | Description |
|---|---|---|
stop_id | String | Agency stop identifier. |
name | String | Stop name. |
departures | Integer | Departure count in the window. |
per_hour | Double | Departures / window hours. 6+ = "turn-up-and-go." 2–6 = moderate, timetable recommended. < 2 = infrequent, timetable required. |
headway_min | Double | Mean scheduled headway in minutes. Window duration / departures. 0 where no departures. |
n_routes | Integer | Distinct routes serving this stop in the window. 2+ routes = transfer point; the combined frequency is the sum of per-route frequencies. |
Route trips (OUT_ROUTES)
| Field | Type | Description |
|---|---|---|
route_id | String | Route identifier. |
name | String | Route short/long name. |
trips_in_window | Integer | Number of trips operated by this route within the window. |
Symbolic Representation
Map per_hour with a sequential ramp (YlOrRd or Plasma) using
manual breaks at 2, 4, 6, 8, 12 departures/hour. Class 0–2: infrequent (thin
grey circles, size 2 mm). Class 2–4: moderate (medium circles, size 3 mm). Class
4–6: approaching turn-up-and-go (size 4 mm). Class 6+: the frequent network
(large circles, size 5–6 mm, bold colour). The 6+ subnetwork IS the "frequent
network" map that transit agencies publish — overlay it on a dark basemap for an
immediately legible transit-quality exhibit.
Interpretation Guide
Frequency bands and their planning implications
| per_hour | Headway | Rider Experience | Planning Implication |
|---|---|---|---|
| 6+ | ≤10 min | Turn-up-and-go. Riders arrive at the stop without consulting a timetable. Waiting time is a minor fraction of total trip time. | Transit-oriented density is defensible. These corridors support 15-minute-frequency land uses (residential, retail, employment). |
| 4–6 | 10–15 min | Frequent enough for most. Riders check the timetable on departure but not obsessively throughout the day. | Transit-supportive density appropriate. Missing a bus costs 10–15 minutes — acceptable for discretionary trips, borderline for commute. |
| 2–4 | 15–30 min | Timetable-dependent. The rider plans around the schedule. A missed bus costs a significant wait. | Basic mobility provision. Not a basis for transit-oriented development. Coverage service, not ridership service. |
| < 2 | >30 min | Skeletal. The rider's entire day is structured around the timetable. Useful only for planned trips. | Socially necessary minimum. These stops serve captive riders who have no alternative — not a basis for densification. |
Multi-window analysis
Run the tool at three windows — morning peak (07:00–09:00), midday (10:00–14:00),
and evening (18:00–20:00) — and compare. A stop with per_hour of 8 in
the peak and 1 at midday serves commuters only. A stop with per_hour
of 5–6 across all three windows is an all-day frequent corridor — the gold
standard for transit-oriented density and the sub-network that affordable housing
policies should prioritise.
Cross-references
- GTFS Import: the 24-hour departure count from GTFS Import shows total service presence; the frequency map's windowed count shows when that presence is concentrated. Compare them: a stop with 100 daily departures that all cluster in two hours is a peak-only express hub, not an all-day transit centre.
- Transit Travel-Time Access: frequency is the input to
door-to-door time. A high-frequency corridor near the origin reduces the access
wait; a low-frequency corridor at the destination adds a long transfer penalty.
The Transit Access tool's
transit_minfield captures both. - Walking Slope Comfort: a high-frequency stop at the top of a steep hill is inaccessible to mobility-impaired riders despite the timetable. Overlay frequency with slope comfort class ≥ 3 to identify stops where terrain limits the value of the service.
Pitfalls
- Mean headway ≠ actual headway. The reported headway is the window-mean. Three buses at 08:00, 08:05, and 08:55 produce a mean headway of ~27 minutes but two of the three gaps are 5 and 50 minutes — terrible reliability. For a true picture of service evenness, check the per-route trip counts: a route with 6 trips in 2 hours should be evenly clockface (~20 min gaps).
- Overlapping routes. At stops served by multiple routes, the
per_hourreports the sum of all routes. Two routes each at 3/hour combine to 6/hour at the stop — turn-up-and-go for the passenger, even though neither route individually is. This is correct for the rider's experience (they can board either) but overstates the per-route service level. - GTFS completeness. Some agencies do not include all routes in their public GTFS — school buses, paratransit, and demand-responsive services are often absent. The frequency map shows what is in the feed, not necessarily the full transit offer.
Academic References
Walker, J. (2012). Human Transit. Island Press. (Chapters 5–6: "The Frequent Network" and "Frequency" — the definitive practitioner treatment.) trade/practice book]
Fan, Y., Guthrie, A., & Levinson, D. (2016). "Waiting time perceptions at transit stops and stations: Effects of basic amenities, gender, and security." Transportation Research Part A: Policy and Practice, 88, 251–264. DOI: 10.1016/j.tra.2016.04.012
Higgs, C., Badland, H., Simons, K., Knibbs, L.D., & Giles-Corti, B. (2019). "The Urban Liveability Index: Developing a Policy-Relevant Composite Measure." The Lancet Planetary Health, 3(S1), S21. DOI: 10.1016/S2542-5196(19)30107-X
Cats, O. (2017). "Topological Evolution of a Metropolitan Rail Network: The Case of Stockholm." Journal of Transport Geography, 62, 172–183. DOI: 10.1016/j.jtrangeo.2017.06.002
Transit Travel-Time Access
Processing ID: planx:transitaccess
Overview
Computes door-to-door travel times with public transport: walk from any origin to a transit stop on the street network, ride the timetable (with transfers), walk from the alighting stop to each destination — and compare against walking all the way. This is the transit sibling of the 15-minute-city tools and the single tool in the PlanX suite that answers the complete rider question: "how long does the whole trip actually take?"
The timetable is compiled from a GTFS zip into route patterns (sequences of stops) and trip arrays (arrival and departure times per pattern), then searched with a RAPTOR-style round-based earliest-arrival algorithm (Delling et al., 2015). Walking legs before boarding (access) and after alighting (egress) run on the street network via multi-source Dijkstra. The algorithm tracks the earliest time a passenger can stand on each stop's platform and, at each round, boards the first catchable trip (by departure time), propagates arrivals along the route pattern, and re-evaluates transfers at the next round. Walking is kept as the fallback: when transit is slower than walking (short trips, long waits), the tool reports walking as the best mode.
For each destination, the output reports walk_min (walking all the
way), transit_min (walk + ride + transfer waits + walk),
best_min (whichever is faster), saved_min (minutes
transit saves — zero or positive), and mode (Walk, Transit, or
Unreachable). The trip departs at a user-specified hour on the chosen service day
and allows up to the specified number of re-boardings (transfers).
Theoretical Background
Public transit routing from schedule data is computationally distinct from road-network routing. In a road network, the travel time on an edge is a scalar (seconds); in a timetable, the travel time between two stops depends on which trip is boarded — the earliest-arrival time at a destination is a function of the departure time, the wait for the next vehicle, the ride time, and any transfer waits. This makes the problem inherently time-dependent and discrete: the timetable is a finite set of vehicle journeys, and the passenger can only board a vehicle that departs after she arrives at the stop.
RAPTOR (Round-bAsed Public Transit Optimized Router) by Delling, Pajor & Werneck (2015) introduced the key insight that makes timetable routing tractable on realistic metropolitan networks: instead of modelling every possible connection as a graph edge, work in rounds corresponding to the number of boardings. In round $k$, a passenger arrives at a set of stops; in round $k+1$, she boards the first vehicle that departs after that arrival time and rides it as far as it goes, marking arrivals at every downstream stop. The algorithm is FIFO (First-In-First-Out) within each route pattern — a later boarding never produces an earlier downstream arrival — which means only the earliest-catchable trip on each route needs to be tracked.
PlanX implements a simplified RAPTOR (engine/transit.py,
earliest_arrival):
- Access walk. Multi-source Dijkstra from all origin nodes on the street network produces the walking time from each origin to every network node. GTFS stops snap to their nearest network node (within the access-walk limit); the access time to a stop is the walk time plus the straight-line snap offset. The departure time (user-specified hour × 3600 seconds) plus the access walk gives the earliest time the passenger stands on each reachable stop's platform.
- Round 0 (single ride). For each stop the passenger can reach by walking, find the earliest trip on each route pattern whose departure at that stop position is $\geq$ the arrival time. Propagate the trip's arrival times to all downstream stops on the pattern — these are the earliest single-ride arrivals.
- Round $k$ (transfer). Stops whose arrival times improved in
the previous round become the transfer origins. For each such stop, find the
earliest catchable trip on each pattern, propagate downstream arrivals. Stop
when no stop's arrival improves or after
max_transfersrounds. - Egress walk. From each stop with a finite arrival time, walk (multi-source Dijkstra with offset = arrival time) to every network node. The minimum of (arrival at node + egress walk) and (walk-all-the-way time) gives the destination's best arrival time.
The algorithm is not an exact RAPTOR — it does not handle footpaths as distinct transfer edges (transfers occur by arriving and re-boarding at the same stop) and the trip search is brute-force linear scan on the departure column rather than a binary search on a pre-processed index. These simplifications are deliberate: on the typical feed size used in a single-study-area analysis (most cities have < 10,000 stops and < 1,000 route patterns), the linear scan is fast enough (~seconds) and avoids the complexity of route-pattern indexing.
Mathematical Formulation
Access walk. For origin nodes $\mathcal{O}$, walking speed $v$ (m/s), and street-network edge walking times $w_{\text{sec}}(e) = \ell_e / v$:
$$t_{\text{access}}(stop_i) = \min_{o \in \mathcal{O}} \left[ d_{\text{walk}}(o, node(stop_i)) + \frac{\|stop_i - node(stop_i)\|_2}{v} \right] \tag{5}$$Stops for which $t_{\text{access}} > max\_walk\_min \times 60$ are excluded. The departure time at reachable stop $i$ is:
$$t_{\text{depart}}(i) = t_{\text{departure\_hour}} \cdot 3600 + t_{\text{access}}(stop_i) \tag{4}$$Earliest-arrival propagation (round $k$). Let $E_k[i]$ be the earliest arrival at stop $i$ after $k$ boardings ($E_0[i]$ = departure time at reachable stops). For a route pattern with stop sequence $\{s_0, s_1, \ldots, s_m\}$ and trip departures $\{d_{t,0}, d_{t,1}, \ldots\}$:
$$t_{\text{boarding}}(t, j) = \min_{t} \{ d_{t,j} : d_{t,j} \geq E_k[s_j] \} \tag{3}$$ $$E_{k+1}[s_{j'}] = \min(E_k[s_{j'}],\; a_{t, j'}) \quad \text{for} \; j' > j \tag{2}$$where $a_{t,j'}$ is trip $t$'s arrival at stop $s_{j'}$. The propagation is FIFO: if trip $t$ is the earliest catchable at stop $j$, it is also the earliest (at zero additional waiting) for all stops $j' > j$ on the same pattern.
Egress walk and final result. For destination node $d$:
$$t_{\text{transit}}(d) = \min_{i : E_K[i] < \infty} \left[ E_K[i] + d_{\text{walk}}(node(stop_i), d) + \frac{\|stop_i - node(stop_i)\|_2}{v} \right] \tag{1}$$ $$t_{\text{best}}(d) = \min(t_{\text{walk}}(d),\; t_{\text{transit}}(d))$$Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| GTFS feed | ZIP | Yes | Same feed as the other transit tools. |
| Street network | Vector lines | Yes | Projected CRS (metres). The network must cover the walking catchment of the stops. Does not need to be a prepared network — build_node_graph constructs the graph on the fly. |
| Origin(s) | Vector (any geometry) | Yes | One or more features representing the departure place. Multiple features = multiple entrances to the same origin; the best (shortest access) wins for each stop. |
| Destinations | Vector (any geometry) | Yes | Demand points to evaluate. Building centroids, job locations, address points. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
FILE | File (ZIP) | — | GTFS zip. |
DAY | String | "" (first active) | Service day YYYYMMDD. |
DEPARTURE | Double | 8.0 | Departure hour (decimal). 8.0 = 08:00. The starting time of the trip — access walks are added to this. Sweep multiple departure hours (08:00, 12:00, 18:00) to test all-day vs. peak-only service quality. |
NETWORK | Vector (Line) | — | Street network in projected CRS. |
ORIGINS | Vector (Any) | — | Departure place(s). |
DEMAND | Vector (Any) | — | Destination points. |
WALK_SPEED | Double | 4.8 | Walking speed km/h. 4.8 = average adult; 3.6 = elderly/child; 5.0 = brisk commuter. |
MAX_WALK | Double | 10.0 | Maximum access/egress walk time in minutes. Stops further than this from the origin are excluded from boarding consideration. |
MAX_TRANSFERS | Integer | 2 | Maximum re-boardings (0 = single ride only). Each transfer incurs a wait for the next vehicle. Values > 3 increase runtime with diminishing realistic utility — most passengers accept at most 2 transfers. |
OUT_DEMAND | Vector (Point) | — | Destinations annotated with travel time fields. |
Output Description
| Field | Type | Description |
|---|---|---|
walk_min | Double | Walking time (minutes) for the entire trip on the street network. The baseline — NULL if unreachable by walking. |
transit_min | Double | Transit door-to-door time (walk + wait + ride + transfers + egress walk). NULL if unreachable by transit. This is the honest cost: it includes the wait for the first catchable trip. |
best_min | Double | Minutes for the fastest mode. = min(walk_min, transit_min). NULL if unreachable by both modes. |
saved_min | Double | Minutes transit saves versus walking. = walk_min − transit_min (≥ 0). 0 when walking is faster or equal. NULL when either mode is unreachable. Negative never occurs — walking is always kept as the fallback. |
mode | String | "Walk", "Transit", or "Unreachable". The fastest mode to this destination. |
transfers_max | Integer | The user's max-transfers setting (constant across all destinations). |
Symbolic Representation
Map best_min with a sequential ramp (Viridis, reversed: dark =
short travel, bright = long). Use threshold contours at 15, 30, 45, 60 minutes
to visualise the isochrone bands. Map mode as a categorical:
"Transit" destinations in blue, "Walk" in green, "Unreachable" in red — the
spatial pattern of blue and green reveals where transit beats walking and where
it loses. For a saved_min view, use a diverging ramp centred at ~10
(the threshold for "meaningful transit advantage"): destinations with
saved_min > 10 are strong transit wins; < 5 are marginal.
Interpretation Guide
The three transit-access regimes
mode = Transit,saved_min>> 0: transit is genuinely providing mobility beyond walking. The larger the saved minutes, the more indispensable the service. Atsaved_min> 30, the destination is functionally inaccessible without transit (walking would take over an hour).mode = Walknear a rail line: the most common failure mode. The station exists, the timetable operates, but the access walk consumes so much time that walking the whole way is faster. Check: is the station correctly snapped to the network? Is the access-walk limit adequate? Is the walking speed realistic for the terrain? If all settings are correct, the destination is outside the station's effective catchment — transit does not serve it competitively.mode = Unreachable: neither walking nor transit can reach this destination within the limits (max walk distance and max transfers). The farthest-flung destinations. If a hospital or employment centre appears unreachable, the transit network has a genuine coverage gap.
Sweeping departure hours
Run the tool at multiple departure hours (08:00, 12:00, 18:00, 22:00) on the
same OD pairs and compare best_min. Destination A: 15 min at 08:00,
35 min at 12:00, 55 min at 18:00 — peak-only service. Destination B: 20, 22, 25
min across all hours — all-day reliable. A "transit-accessible" claim is only
credible when best_min is stable across the day; a single
morning-peak number hides the midday collapse.
Cross-references
- Transit Frequency Map: frequency at the boarding and transfer stops determines the wait components of transit time. A destination reachable via two high-frequency routes (wait times ~5 min each) will be markedly faster than the same geography with low-frequency routes (wait times ~15 min each), even if the in-vehicle ride time is identical.
- Walking Slope Comfort: substitute the flat-walking-speed
edge weights with Walking Slope Comfort's
time_fwd_minfield for slope-aware access and egress. This is especially important in hilly cities where a steep access walk can double the time to the nearest bus stop. - Accessibility Equity: run the transit access tool from
low-income neighbourhood origins to job-centre destinations, then feed
best_mininto Accessibility Equity to compute the Gini/Theil on transit travel times. The between-group share reveals whether transit mobility is equitably distributed across income or spatial groups.
Pitfalls
- FIFO assumption. The algorithm assumes that a later departure never produces an earlier downstream arrival on the same route — true for scheduled services but violated if express and local services share a route_id with different stopping patterns. The engine groups trips by route_id + stop sequence as the pattern key, so express/local variants with different stop patterns are separate patterns and the FIFO assumption holds per pattern.
- Access walk distance. The
MAX_WALKparameter controls both the computational cost (more stops to evaluate) and the model realism. Too short (5 min) and the tool misses viable transit options; too long (30 min) and walking-all-the-way always wins. 10 minutes (~800 m) is the standard catchment for bus stops; 15 minutes (~1200 m) for rail stations. - Single departure time. The tool departs at a precise hour. If the timetable has a gap (e.g., the bus leaves at 07:55 and the next at 08:20), departing at 08:00 will report a 20-minute wait. A departure-time sweep (from 07:30 to 08:30 in 5-minute steps) reveals this sensitivity. For planning-level analysis, run at the midpoint of the peak (08:00) as the representative time.
Academic References
Delling, D., Pajor, T., & Werneck, R.F. (2015). "Round-Based Public Transit Routing." Transportation Science, 49(3), 591–604. DOI: 10.1287/trsc.2014.0534
Conway, M.W., Byrd, A., & van der Linden, M. (2017). "Evidence-Based Transit and Land Use Sketch Planning Using Interactive Accessibility Methods on Combined Schedule and Headway-Based Networks." Transportation Research Record, 2653(1), 45–53. DOI: 10.3141/2653-06
Wessel, N., Allen, J., & Farber, S. (2017). "Constructing a Routable Transit Network from a Real-Time Vehicle Location Feed." Transportation, 44, 501–518. DOI: 10.1007/s11116-015-9663-5
Boisjoly, G. & El-Geneidy, A. (2016). "Daily Fluctuations in Transit and Job Availability: A Comparative Assessment of Time-Sensitive Accessibility Measures." Journal of Transport Geography, 52, 73–81. DOI: 10.1016/j.jtrangeo.2016.03.004
Owen, A. & Levinson, D.M. (2015). "Modeling the Commute Mode Share of Transit Using Continuous Accessibility to Jobs." Transportation Research Part A: Policy and Practice, 74, 110–122. DOI: 10.1016/j.tra.2015.02.002
12. Visibility
The Visibility group models what can be seen from where — the spatial analysis of sight, exposure, and enclosure that underpins visual impact assessment, defensible-space auditing, and urban design evaluation. Three tools explore visibility from complementary directions: Viewshed answers "what can I see" from one or more observer points over a Digital Surface Model (DSM), using a radial line-of-sight sweep with a running horizon angle — the same ray idiom as the shadow and sky-view tools in the Microclimate group. Isovist Field answers "how does open space feel" by sampling a grid of points between buildings and computing Benedikt's (1979) isovist measures — area, perimeter, radial lengths, circularity, and occlusivity — the 2-D visibility-graph companion to space syntax. Visual Exposure of Landmarks reverses the question: "from where can the landmark be seen?" — sampling the landmark's boundary as observer points and accumulating the visibility count, the standard input to heritage impact and skyline protection studies.
Viewshed (DSM)
Processing ID: planx:viewshed
Overview
Computes a visibility-count raster from one or more observer points over a Digital Surface Model (DSM — terrain plus buildings and vegetation). From each observer, azimuth rays are swept outward at half-pixel steps. Each ray maintains a running horizon angle — the maximum angular elevation of any surface encountered so far. A target cell is visible when the angle from the observer's eye to the cell's surface (plus an optional target height) exceeds the accumulated horizon. The output is a raster where each cell's value is the number of observers that can see it. With one observer, this is the classical binary viewshed (0/1). With multiple observers, it is a coverage-redundancy map — cells seen by many observers are visually exposed; cells at zero are blind spots from every tested viewpoint.
The observer's eye sits at the DSM surface plus the observer height (default: 1.6 m, standing eye level). The target's visibility is tested at the DSM surface plus the target height (default: 0 m for the bare ground). The asymmetry between these two heights is the tool's key interpretive flexibility: set observer height to 1.6 m and target height to 1.6 m for "can two people see each other"; set observer height to 5 m (CCTV pole) and target height to 0 m for surveillance coverage; set observer height to 1.6 m and target height to 0 m for "what can I see of the ground surface."
Theoretical Background
Viewshed analysis is one of the oldest terrain-analytic operations in GIS, dating to the earliest digital terrain models of the 1970s. Fisher (1993) established the foundational critique: a viewshed is not a single deterministic truth but a probabilistic envelope whose boundary depends on the algorithm (ray-based vs. horizon-based), the DSM resolution, the interpolation method, and the treatment of observer and target heights. The PlanX implementation follows the radial horizon sweep approach — the same method used in the commercial visibility-analysis packages and the shadow/SVF tools in the Microclimate group:
- Rays are cast at evenly spaced azimuths (default: 720, giving 0.5-degree angular resolution).
- Along each ray, the algorithm steps at half-pixel intervals — this oversampling is critical for accurate horizon accumulation on coarse DSMs, where a single-pixel step can skip over a narrow intervening ridge.
- The running horizon is the maximum of all surface angles seen so far on this ray — a cumulative maximum that can only rise, never fall.
- Cells with NoData in the DSM are never visible and never block — they are transparent in the ray model.
- The search radius is capped at the DSM diagonal (the longest possible line-of-sight within the raster) or a user-specified radius.
Algorithmic uncertainty (Fisher, 1993). Fisher demonstrated that viewshed boundaries from different algorithms on the same DSM can disagree by 10–30% of the terrain. The three main sources of uncertainty are: (1) the interpolation method for the ground surface between grid posts — PlanX uses linear interpolation along the ray; (2) the observer height — a difference of 0.5 m can shift the visible/non-visible boundary by dozens of metres on flat terrain; (3) the angular resolution — coarser rays (e.g., 360 directions) produce characteristic "star" artefacts where narrow visibility corridors are missed between ray angles. The default of 720 directions eliminates these artefacts for all but the narrowest urban canyons.
Applications beyond the classical viewshed. The classical question — "can the observer see that hilltop?" — has been substantially extended in the decades since Fisher's analysis. In urban planning, the dominant applications are: visual impact assessment (will the proposed building be visible from protected viewpoints?), defensible-space auditing (are there blind spots along pedestrian routes where informal surveillance fails?), CCTV/lighting coverage analysis (which areas are covered by how many cameras/lights?), and skyline protection (where can the protected landmark silhouette still be seen?). The last of these is the inverse question — answered by the Visual Exposure of Landmarks tool.
Mathematical Formulation
Observer geometry. For an observer at DSM cell $(r_0, c_0)$ with elevation $z_0$, eye height $h_{\text{obs}}$, at an azimuth $\theta$:
$$z_{\text{eye}} = z_0 + h_{\text{obs}} \tag{5}$$Ray stepping. Along the ray at azimuth $\theta$, steps are at pixel-scale intervals from the observer outward. The step in column and row per metre of ground distance at ray azimuth $\theta$ and pixel size $p$:
$$\Delta c = \frac{\sin\theta}{p}, \qquad \Delta r = -\frac{\cos\theta}{p} \tag{4}$$Horizon accumulation. At step $k$ with ground distance $t_k$, the target cell's surface angle and the target-height angle are:
$$\alpha_k^{\text{surf}} = \frac{z_k - z_{\text{eye}}}{t_k}, \qquad \alpha_k^{\text{tgt}} = \frac{z_k + h_{\text{tgt}} - z_{\text{eye}}}{t_k} \tag{3}$$The horizon before step $k$ is the cumulative maximum of surface angles:
$$H_k = \max_{j < k} \alpha_j^{\text{surf}} \tag{2}$$Cell $k$ is visible when:
$$\text{visible}(k) = \left( \alpha_k^{\text{tgt}} \geq H_k - \varepsilon \right) \tag{1}$$where $\varepsilon$ is a small tolerance ($10^{-12}$) to handle floating-point precision in the horizon comparison. NoData cells are excluded and do not contribute to $H_k$.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| DSM | Raster | Yes | Digital Surface Model (terrain + buildings + vegetation). Projected CRS with metric pixels. Resolution 0.5–5 m for urban-scale analysis. NoData = transparent to sight lines. |
| Observer points | Vector (any geometry) | Yes | Point or centroid locations of the observers. Each contributes one viewshed; the final raster sums all contributions. For a single-viewpoint study, provide one point. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
DSM | Raster | — | Surface model in projected CRS. |
OBSERVERS | Vector (Any) | — | Observer locations. Multiple features = multi-observer viewshed; the output count per cell is the number of observers seeing it. |
OBSERVER_HEIGHT | Double | 1.6 | Observer eye height above the DSM surface (metres). 1.6 = standing adult. 5.0 = CCTV pole. 0.2 = seated child. 20 = mid-rise balcony. |
TARGET_HEIGHT | Double | 0.0 | Target height above the DSM surface. 0 = bare ground. 1.6 = standing person. >0 for "can a person there be seen." Set both heights to 1.6 for mutual visibility. |
RADIUS | Double | 0.0 (unlimited) | Maximum view distance in map units. 0 = DSM diagonal (the full raster extent). Set a finite radius (e.g., 500 m) for local-scale visibility and faster computation. |
DIRECTIONS | Integer | 720 | Number of azimuth rays. 720 = 0.5-degree resolution, smooth edges. 360 = 1-degree, adequate for most terrain-scale viewsheds. 90 = coarse but fast for quick screening. |
OUTPUT | Raster | — | Visibility count raster. Integer values 0–N where N = number of observers. NoData = DSM was NoData at this cell. |
Output Description
The output is a single-band integer raster with the same extent, pixel size, and CRS as the input DSM. Cell values are the count of observers that see the cell, ranging from 0 (blind spot from all observers) to $N$ (seen by every observer). Cells where the DSM is NoData are set to a NoData sentinel value (-1), distinguishing "not visible" from "not evaluated."
The log reports per-observer statistics: the percentage of raster cells seen by each observer (visible share within the radius) and the overall percentage seen by at least one observer.
Symbolic Representation
For a single-observer viewshed, display as a binary layer: visible cells in one colour (e.g., light warm tone at 50% opacity) over a hillshade of the DSM — this is the classic viewshed exhibit. For multi-observer viewsheds, use a sequential ramp (Viridis or Inferno) on the count: 0 = dark (blind), ≥3 = bright (robustly visible). Overlay observer points as a distinct symbol (star, eye icon). The visible/non-visible boundary is the key analytic feature — style it by outlining the non-zero cells with a thin (0.3 mm) bright line for emphasis.
Interpretation Guide
Diagnostic patterns
- Disconnected visible patches behind a ridge: the DSM has a narrow ridge blocking the sight line, but the ray's half-pixel step correctly clears it — this is a genuine "behind-the-horizon" visibility patch, common in undulating terrain. These patches are the most counter-intuitive viewshed results but are physically correct: the observer can see the far hillside above the intervening ridge.
- Radial "star" pattern: too few ray directions. The
characteristic star-shaped viewshed boundary, where narrow wedges of
visibility alternate with blind wedges at the ray spacing, indicates that
angular resolution is too coarse. Increase
DIRECTIONSto 720 or 1440. - Sudden visibility cutoff at a straight line: likely a DSM artefact — a tiling boundary, a NoData strip, or a building footprint edge that the DSM does not represent smoothly. Verify the DSM quality at the cutoff line.
Cross-references with other PlanX tools
- Visual Exposure of Landmarks: the inverse question. Run Viewshed from a proposed viewpoint to see what it offers; run Visual Exposure from a landmark to see who can see it.
- Shadow Casting: the same radial-sweep engine with the same DSM and pixel size, but asking "is the sun above the horizon" rather than "is the cell above the horizon." Run both on the same DSM for a combined solar + visual assessment of a proposed massing.
- Sky View Factor: the same horizon-accumulation approach but integrated over the full hemisphere rather than tested at discrete target cells. A cell with low SVF (deep urban canyon) will also have low visibility — the two are correlated but not identical: a narrow canyon with sight lines along the street axis may have high visibility in one direction but low SVF overall.
- Walkability / Street Comfort: overlay 0-count (blind) cells from Viewshed with pedestrian route bundles. Low-visibility segments on high-footfall routes are the defensible-space shortlist — these are the locations where natural surveillance is absent and people feel unsafe.
Pitfalls
- DSM vegetation representation. A DSM includes tree canopies as solid surfaces — a dense street tree canopy will block sight lines that are open at ground level beneath the canopy. The viewshed answer is "as seen from the eye position," which for a ground-level observer may differ from a DSM that does not distinguish canopy from trunk. For visibility analysis in wooded areas, consider a DTM (bare-earth) + building massing model rather than a full DSM.
- Earth curvature. At observation ranges beyond ~10 km, Earth curvature begins to significantly affect the horizon. The PlanX engine operates in flat-Earth Cartesian coordinates (the projected CRS). For regional-scale viewsheds (>20 km range), a geodetic correction is needed — the tool does not apply one.
- Building interiors. The DSM represents the building envelope, not the occupant's eye. A window on the 10th floor of a building whose DSM surface is at the 20th floor's roof will show the occupant as "below the surface" — invisible. For high-rise residential visibility, place observers at balcony heights, not at the building footprint centroid.
Academic References
Fisher, P.F. (1993). "Algorithm and Implementation Uncertainty in Viewshed Analysis." International Journal of Geographical Information Systems, 7(4), 331–347. DOI: 10.1080/02693799308901965
Llobera, M. (2003). "Extending GIS-Based Visual Analysis: The Concept of Visualscapes." International Journal of Geographical Information Science, 17(1), 25–48. DOI: 10.1080/713811741
Wheatley, D. (1995). "Cumulative Viewshed Analysis: A GIS-Based Method for Investigating Intervisibility, and Its Archaeological Application." In: Lock, G. & Stancic, Z. (eds.), Archaeology and Geographical Information Systems, 171–185. Taylor & Francis. book chapter, no DOI assigned]
De Floriani, L. & Magillo, P. (2003). "Algorithms for Visibility Computation on Terrains: A Survey." Environment and Planning B: Planning and Design, 30(5), 709–728. DOI: 10.1068/b12979
Isovist Field
Processing ID: planx:isovistfield
Overview
Samples a grid of points over open space (between buildings) and computes isovist measures at every point — the 2-D visibility polygon defined by what can be seen from that standing location. An isovist (Benedikt, 1979) is the set of all points in space visible from a given vantage point, bounded by the first opaque surfaces (building walls) or by a maximum sighting distance. It is the visibility-graph companion to space syntax: while axial and segment analysis measure the configurational properties of the street network, isovist fields measure the experiential properties of open space — how large it feels, how enclosed, how connected visually to adjacent spaces.
Buildings are rasterised to a boolean obstacle grid ($\text{True} = \text{blocked}$) at the user-specified cell size. Rays are cast from each free grid cell at evenly spaced azimuths until the first blocked cell, a range limit, or the grid edge. The ray endpoints define a polygon whose geometric properties are computed via the shoelace formula (area), Euclidean vertex-to-vertex distances (perimeter), and radial lengths. The tool reports seven metrics per sample point: iso_area, iso_perim, min_rad, max_rad, mean_rad, circularity, and occlusivity.
Theoretical Background
Benedikt's isovist (1979). Michael Benedikt introduced the isovist as a formal geometric construct for quantifying the visual experience of architectural space. In a seminal paper in Environment and Planning B, he defined an isovist as "the set of all points visible from a given vantage point in space" and derived its geometric properties — area, perimeter, radial lengths, and various moments — as descriptors of spatial experience. An isovist with large area but small minimum radial (you can see far in one direction but a wall is close in another) reads differently from an isovist with the same area but uniform radials (a circular plaza). The isovist field — the continuous map of these measures across all points in open space — was proposed by Benedikt as the spatial-analogue of a potential field: a scalar landscape of visibility whose gradients, ridges, and basins encode the experience of moving through the environment.
Batty's extension (2001). Michael Batty generalised the isovist into a graph-theoretic framework by connecting points whose isovists overlap (the visibility graph) and applying network analysis measures (closeness, betweenness) to this visibility graph. The resulting visibility graph analysis (VGA), implemented in Turner's depthmapX software (Turner et al., 2001), became the standard computational pipeline for architectural and urban visibility analysis. PlanX's isovist field tool computes the raw isovist measures at grid points — the first step of VGA — but leaves the graph-construction step to the user (the point layer can be exported to an external VGA tool for network analysis).
Interpretive framework. The seven isovist metrics form a complementary set:
- Area = perceived spaciousness. The most visceral measure: a plaza is large-area, an alley is small-area.
- Perimeter = complexity of the visible boundary. High perimeter at modest area = a jagged, articulated space (a medieval square with projecting facades). Low perimeter at modest area = a simple rectangular room.
- Circularity ($4\pi A / P^2$) = shape of the visibility envelope. High (>0.7) = compact, plaza-like — the isovist is approximately circular, the space feels centred. Low (<0.3) with high max_rad = corridor-like — the space is elongated along a sight line, the space is a movement channel.
- Occlusivity = the share of rays terminated by a building surface rather than by distance or the grid edge. High occlusivity = walls define the space (urban rooms, courtyards). Low occlusivity with large area = the view extends to the distance limit — an open field with no spatial definition.
- min_rad = intimacy. How close the nearest wall stands. Low min_rad (a wall at arm's length) is the sensation of enclosure; high min_rad (the nearest wall is at a distance) is exposure.
- max_rad = vista depth. The longest unobstructed sight line. High max_rad corridors are the visual axes that structure urban composition — the boulevard terminating at a monument, the street aligned with a distant hill.
Mathematical Formulation
Isovist polygon. For a vantage point at grid cell $(r_0, c_0)$ with $n_{\text{rays}}$ at azimuths $\theta_k = 2\pi k / n_{\text{rays}}$, each ray marches outward one pixel-step at a time until the first blocked cell, the range limit $R_{\max}$, or the grid boundary. The reached distance along ray $k$ is $r_k$, and the ray endpoint in map coordinates is:
$$x_k = r_k \cdot \sin\theta_k, \qquad y_k = r_k \cdot \cos\theta_k \tag{7}$$The isovist is the polygon with vertices $\{(x_0, y_0), (x_1, y_1), \ldots, (x_{n-1}, y_{n-1})\}$. Area via shoelace:
$$A = \frac{1}{2} \left| \sum_{k=0}^{n-1} (x_k y_{k+1} - x_{k+1} y_k) \right| \quad (\text{with } n \equiv 0) \tag{6}$$ $$P = \sum_{k=0}^{n-1} \sqrt{(x_{k+1} - x_k)^2 + (y_{k+1} - y_k)^2} \tag{5}$$ $$\text{circularity} = \frac{4\pi A}{P^2} \quad (\leq 1, = 1 \text{ for a circle}) \tag{4}$$Radial statistics. For the $n$ radials $\{r_0, \ldots, r_{n-1}\}$:
$$\bar{r} = \frac{1}{n} \sum r_k, \qquad r_{\min} = \min r_k, \qquad r_{\max} = \max r_k \tag{3}$$Occlusivity. Let $n_{\text{blocked}}$ be the number of rays that terminated at a building cell (blocked by an obstacle). Rays terminated by the range limit or the grid edge are not occluded:
$$\text{occlusivity} = \frac{n_{\text{blocked}}}{n_{\text{rays}}} \tag{2}$$ $$\text{occlusivity} \in [0, 1] \tag{1}$$Performance optimisation. The isovist_field engine pre-computes the direction vectors for all rays (the $t \cdot dr$ and $t \cdot dc$ arrays of size $n_{\text{steps}} \times n_{\text{rays}}$) so that each sample point reuses the same ray geometry — only the origin offset changes. The cost is therefore $O(N_{\text{free\_cells}} \cdot n_{\text{rays}} \cdot \bar{n}_{\text{steps}})$ where $\bar{n}_{\text{steps}}$ is the mean ray length before termination.
Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Buildings | Vector (Polygon) | Yes | Building footprints. Projected CRS required. Multi-polygon handling: each feature's geometry is intersected with the grid cells. Overlapping buildings are unioned in the grid (a cell is blocked if ANY building occupies it). |
| Study extent | Extent (bounding box) | No | Analysis area. Empty = building-layer extent. Set manually to frame a specific district. The extent should include, and extend slightly beyond, the area of interest. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
BUILDINGS | Vector (Polygon) | — | Building footprints. Projected CRS. |
EXTENT | Extent | (optional) | Study area bounding box. Omit to use the building layer's extent. |
CELL | Double | 10.0 | Grid cell size in map units (metres). 5 m = fine gradation, captures narrow passages but produces many points (a 500×500 m extent = 10,000 cells). 10 m = standard urban-scale analysis. 20 m = coarse, for city-scale screening. |
N_RAYS | Integer | 180 | Rays per point. 180 = 2-degree resolution — smooth isovist polygons. 90 = 4-degree, angular but faster. 360 = 1-degree, for very fine isovist boundaries. |
MAX_DIST | Double | 200.0 | Maximum sight distance in map units (metres). The perceptual horizon — isovist area asymptotes at this distance even if no building blocks the view. 200 m captures the walking-scale visual experience; 500 m for city-scale vistas; 100 m for intimate courtyard/street analysis. |
OUT_POINTS | Vector (Point) | — | Isovist-measured grid points (one per free cell). |
Output Description
| Field | Type | Range | Description |
|---|---|---|---|
iso_area | Double | 0–~125,000 | Isovist area (m²). At MAX_DIST = 200 m, the theoretical maximum is $\pi \times 200^2 \approx 125,664$ m² (full circle). Typical urban values: 500–5,000 (alleys/courtyards), 5,000–30,000 (streets/plazas), 30,000+ (large open spaces/fields). |
iso_perim | Double | 0–~1,260 | Isovist perimeter (m). Maximum ~$2\pi \times 200 \approx 1,257$ at full-circle with 200 m radius. |
min_rad | Double | 0–200 | Shortest radial (m). Intimacy — how close the nearest wall stands. < 5 m = intimate enclosure; < 2 m = arm's length (a narrow alley). |
max_rad | Double | 0–200 | Longest radial (m). Vista depth — the furthest unobstructed sight line. Near MAX_DIST = open field or long axial view corridor. |
mean_rad | Double | 0–200 | Mean radial length. The average sight distance in all directions. Compare with iso_area: $\pi \cdot \overline{r}^2$ approximates area only for a circle. |
circular | Double | 0–1 | Circularity ($4\pi A / P^2$). > 0.7 = compact, room-like, gathering space. < 0.3 with long max_rad = corridor, movement channel. < 0.3 with short radials = highly irregular/enclosed. |
occlus | Double | 0–1 | Fraction of rays blocked by buildings. 0 = view extends to MAX_DIST in all directions (open field). 1 = every ray hits a building wall (deep enclosure, a courtyard). Irrelevant when MAX_DIST is very small relative to the gaps between buildings. |
Symbolic Representation
Map iso_area with a sequential ramp (Viridis, 7 quantile classes)
for the classic openness map: bright cells = plazas and wide streets; dark cells =
alleys and narrow passages. The gradient between adjacent bright
and dark cells is the spatial drama — use a continuous colour ramp (not discrete
classes) to preserve it. Map circular with a diverging ramp (RdYlGn)
to separate gathering spaces (green, high circularity) from movement corridors
(red, low circularity). Map occlus with a warm sequential ramp
(OrRd) for the enclosure landscape: high occlusivity cells in deep red are the
urban rooms. For publication, use a three-panel layout: area, circularity, and
occlusivity side-by-side — the combined reading of spaciousness, shape, and
enclosure describes spatial experience more completely than any single panel.
Interpretation Guide
The isovist typology
| Type | Area | Circ. | Occl. | Space | Urban Element |
|---|---|---|---|---|---|
| Room | 500–5,000 | >0.6 | >0.7 | Compact, highly enclosed by buildings, roughly circular isovist. | Courtyard, square, plaza surrounded by buildings. |
| Corridor | 1,000–10,000 | <0.3 | >0.5 | Elongated, building-defined, low circularity, long max_rad. | Street canyon, boulevard, alley. |
| Gateway | 500–2,000 | 0.3–0.6 | 0.3–0.6 | Moderate size, moderate enclosure — the transition point between two distinct spatial regions. | Street opening onto plaza, bridge entrance, gate. |
| Field | >20,000 | variable | <0.3 | Large area, mostly limited by distance, not by walls. | Park, waterfront, open landscape, undeveloped lot. |
Cross-references with other PlanX tools
- Space Syntax: the two visibility approaches are complementary. Space syntax measures the configurational properties of the street network (how connections structure movement). Isovist fields measure the experiential properties of open space (how enclosure structures perception). High NACH segments that also have low isovist area and high occlusivity are movement corridors in deep canyons — the most stressful urban walking environments.
- Building Form Metrics: overlay isovist area with building shared-wall ratio. High shared-wall fabric (terraces) produces narrow, deep isovists; low shared-wall fabric (detached houses with setbacks) produces wide, shallow isovists. The shift in mean isovist area at a fabric boundary is the visual signature of a morphological transition.
- Viewshed (DSM): for terrain-scale visibility. Isovist field is the 2-D, building-defined, planimetric complement to the 3-D viewshed. Run both for a combined planimetric + DSM visibility assessment of a city centre.
Pitfalls
- Grid resolution vs. passage width. If a narrow passage
(e.g., a 2 m alley) is smaller than the grid cell (e.g., 10 m), the passage may
be entirely blocked by the rasterisation — no free cells exist inside it, and
the isovist field shows two disconnected spaces instead of a connected one.
Reduce
CELLto below the narrowest passage of interest. - Grid-edge artefacts. Cells near the grid edge have
artificially small isovist areas because rays terminate at the edge. Exclude
cells within ~
MAX_DISTof the study-area boundary from statistics; or set the study extent generously beyond the area of interest. - Computational cost. The cost scales linearly with $|free cells| \times n_{\text{rays}}$. A 500×500 m grid at 5 m cells = 10,000 points × 180 rays × ~40 steps/ray ≈ grid building takes longer than the isovist computation itself. Start with 10 m cells and 90 rays at a 200 m max distance; refine only where analysis demands it.
Academic References
Benedikt, M.L. (1979). "To Take Hold of Space: Isovists and Isovist Fields." Environment and Planning B: Planning and Design, 6(1), 47–65. DOI: 10.1068/b060047
Batty, M. (2001). "Exploring Isovist Fields: Space and Shape in Architectural and Urban Morphology." Environment and Planning B: Planning and Design, 28(1), 123–150. DOI: 10.1068/b2725
Turner, A., Doxa, M., O'Sullivan, D., & Penn, A. (2001). "From Isovists to Visibility Graphs: A Methodology for the Analysis of Architectural Space." Environment and Planning B: Planning and Design, 28(1), 103–121. DOI: 10.1068/b2684
Franz, G. & Wiener, J.M. (2008). "From Space Syntax to Space Semantics: A Behaviorally and Perceptually Oriented Methodology for the Efficient Description of the Geometry and Topology of Environments." Environment and Planning B: Planning and Design, 35(4), 574–592. DOI: 10.1068/b33050
Conroy Dalton, R. & Dalton, N. (2001). "OmniVista: An Application for Isovist Field and Path Analysis." In: Peponis, J. et al. (eds.), Proceedings of the 3rd International Space Syntax Symposium, Atlanta, pp. 25.1–25.10. conference proceedings, no DOI assigned]
Visual Exposure of Landmarks
Processing ID: planx:visualexposure
Overview
Answers the inverse viewshed question: from where can a landmark be seen? Instead of placing an observer and testing which targets are visible (Viewshed), this tool places observers on the landmark (by sampling its footprint boundary) and tests which cells in the surrounding terrain can see them. The output is a raster where each cell's value is the number of landmark-sample-points visible from that cell — a measure of silhouette completeness. Cells seeing all samples see the whole landmark (the postcard view); cells seeing a few samples see glimpses between buildings; cells at zero cannot see the landmark at all.
The tool samples the landmark polygon boundary at regular intervals (default:
every 10 m, capped at 200 points), places a virtual observer at the DSM surface
plus an optional extra height (for a spire, antenna, or dome that the DSM grid
may not resolve at the landmark's footprint), sweeps a viewshed from each sample
point, and accumulates the per-cell count. The observer on the landmark "looks
outward" at the target height — the tool tests whether a person standing at a
given cell (EYE_HEIGHT, default: 1.6 m) could see the landmark
silhouette. The visible count per cell is the number of landmark sample points
with an unobstructed line of sight.
Theoretical Background
Visual exposure analysis emerged from two planning requirements: heritage impact assessment and skyline/view-cone protection. UNESCO World Heritage operational guidelines and most national heritage protection frameworks (English Heritage, ICOMOS) require quantitative assessment of the visual impact of new development on protected landmarks and their settings. The standard method is the Zone of Visual Influence (ZVI), which maps the area from which a proposed development would be visible. Visual Exposure of Landmarks applies the same logic but reversed: the landmark is the fixed element and the question is what territory it visually commands.
Fisher (1996) extended viewshed analysis to landscape planning, introducing the concept of cumulative visibility — aggregating viewsheds from multiple points on or near the feature of interest to create a probabilistic or fuzzy visibility surface. This is the ancestor of the PlanX visual exposure tool: instead of a single binary viewshed from one viewpoint, the exposure raster measures viewing redundancy — how many independent sight lines connect the target cell to the landmark.
Silhouette completeness as a visual-quality metric. The count of visible sample points is a proxy for how much of the landmark's bulk is visible. A cell that sees 180 of 200 sample points sees nearly the entire silhouette — the landmark dominates the view. A cell that sees 5–10 sample points sees a sliver between two buildings — the landmark is present but not visually significant. The transition from zero to non-zero (the landmark's visual catchment boundary) is the ZVI analogue; the transition from low-count to high-count (the landmark's visual dominance zone) is the heritage-conservation analogue — these are the corridors where the landmark's visual presence should be protected from obstruction.
Mathematical Formulation
Landmark sampling. Given landmark footprint polygon vertices $v_1, v_2, \ldots, v_m$, the boundary is densified to a maximum segment length of $\Delta s$ (the sample step), producing a ring of $N$ sample points (capped at 200):
$$\{\mathbf{p}_1, \mathbf{p}_2, \ldots, \mathbf{p}_N\} \subset \partial(\text{landmark}) \tag{5}$$Viewshed from each sample point. For each $\mathbf{p}_i$ at DSM cell $(r_i, c_i)$, the observer height is the extra height parameter $h_{\text{extra}}$ (the DSM surface at the landmark's location is the ground level; the extra height adds the feature's elevation above the DSM — a spire atop a dome whose DSM grid does not resolve it):
$$z_{\text{eye}}^{(i)} = z_{\text{DSM}}(r_i, c_i) + h_{\text{extra}} \tag{4}$$The viewshed from $\mathbf{p}_i$ uses the standard radial horizon sweep
(identical to the Viewshed tool) with target height = EYE_HEIGHT
(observer on the ground looking at the landmark):
The search radius caps the exposure calculation — cells beyond the radius are not tested:
$$\text{exposure\_radius} = \begin{cases} R & \text{if } R > 0 \\ \text{raster diagonal} & \text{otherwise} \end{cases} \tag{1}$$Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| DSM | Raster | Yes | Same requirements as Viewshed. Projected CRS, metric pixels. Must cover the landmark and the surrounding visibility territory. |
| Landmark footprint(s) | Vector (Polygon) | Yes | Building or structure footprints. Multiple polygons = multiple landmarks whose combined visibility is the output. A church, a minaret, a tower — anything whose visual significance is to be assessed. |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
DSM | Raster | — | Surface model in projected CRS. |
LANDMARKS | Vector (Polygon) | — | Landmark footprints. The boundary is sampled for observer points. |
EXTRA_HEIGHT | Double | 0.0 | Height above the DSM at the landmark location (metres). For a spire or antenna not resolved by the DSM pixel. For a 50 m minaret on a DSM that shows the mosque at 15 m, set EXTRA_HEIGHT = 35 (50 − 15). |
SAMPLE_STEP | Double | 10.0 | Boundary sampling interval in map units (metres). Smaller = denser sample, more viewsheds to compute. Capped at 200 sample points — very large landmarks are automatically down-sampled. |
EYE_HEIGHT | Double | 1.6 | Observer eye height at the target cell (metres). This is the height of a person looking at the landmark, not the landmark's height. |
RADIUS | Double | 0.0 | Exposure radius. 0 = unlimited (full DSM extent). For city-scale landmarks, 5,000–10,000 m is often sufficient. |
OUTPUT | Raster | — | Landmark visibility count raster. Cell value = number of sample points visible from here. NoData = DSM was NoData at this cell. |
Output Description
A single-band integer raster with the same extent and resolution as the DSM. Cell values range from 0 (landmark not visible from this cell) to $N$ (all $N$ sample points visible — the full silhouette). NoData where the DSM has no value.
The log reports the number of sample points used and the percentage of valid DSM cells that see the landmark (at least one sample point visible — the ZVI share). For multiple landmarks, this is the combined exposure.
Symbolic Representation
Map the exposure count with a sequential ramp (Inferno or Plasma). Use manual
breaks at meaningful thresholds: 0 (hidden), 1–5 (glimpses), 6–25% of
N (partial view), 26–75% (substantial view), 76–100% (full
silhouette = postcard view). The zero/non-zero boundary is the landmark's visual
catchment — outline it with a 0.5 mm bright line. The high-count corridors
radiating along major street axes are the view cones that heritage plans protect
through height restrictions — overlay these on the zoning map to identify
conflicts between development capacity and view protection.
For before/after impact assessment: run the tool on the existing DSM (baseline), insert the proposed building massing into the DSM (raster arithmetic: replace DSM cells under the building footprint with the building's roof elevation), rerun, and subtract: $\Delta(r, c) = \text{exposure}_{\text{before}}(r, c) - \text{exposure}_{\text{after}}(r, c)$. The difference raster shows every cell where the proposed building obstructs the landmark view, with the magnitude of the count drop as the severity of the impact. This is the definitive heritage- impact exhibit.
Interpretation Guide
Exposure count as visual quality
- High-count cells (76–100% of sample points): the landmark dominates the view. These are the protected view corridors — urban-design policy should preserve their unobstructed status. Height restrictions, building setbacks, and view-cone easements are the standard tools.
- Mid-count cells (26–75%): partial views between buildings. The landmark is present in the townscape but not dominant. New development in front of these cells should be assessed for whether it blocks the remaining visible portions.
- Low-count cells (1–5 sample points): glimpses between narrow gaps — one specific street alignment, a gap between two high-rises. Glimpses are fragile: a single-storey extension can eliminate them. They merit protection only if the glimpse corridor is culturally significant (e.g., a historic street axis aligned on the landmark).
- Zero-count cells: the landmark is hidden. If a cell at zero is in a publicly accessible location less than 500 m from the landmark, the obstruction is local and substantial — a building immediately in front of the viewer. These cells are the most informative for understanding why a landmark is "invisible" from close quarters.
Before/after impact assessment protocol
- Baseline: run Visual Exposure on the current DSM. Save the exposure raster as the heritage baseline.
- Proposed: insert the proposed building's envelope into the DSM (set DSM cells under the footprint to the building height). Rerun the exposure analysis identically.
- Difference: $\text{baseline} - \text{proposed}$. Positive cells = views lost. The magnitude is the number of landmark sample points that this cell can no longer see — the visual impact severity.
- Interpretation: a cell that loses 50+ sample points (substantial silhouette reduction) is a significant adverse visual impact. A cell that drops from 3 to 0 (loses a glimpse) is a minor adverse impact — but if the glimpse was along a protected view axis, it may still be unacceptable.
Cross-references with other PlanX tools
- Viewshed: the forward question. Run both on the same DSM with the same radius — the Viewshed from a protected viewpoint identifies what that viewpoint sees, while the Visual Exposure of the landmark those viewpoints protect identifies who can see it. The overlap between the two maps is the mutual visibility zone — cells that can both see the landmark AND be seen from the protected viewpoint.
- Shadow Casting: for a combined solar + visual impact assessment of a proposed tall building. Run shadow casting on the existing and proposed DSM, and visual exposure of nearby landmarks on both. The proposed building may cast shadow OR block a landmark view (or both) — the impact assessment should cover both.
Pitfalls
- Extra height confusion. The
EXTRA_HEIGHTparameter adds to the DSM surface at the landmark footprint, not to the landmark's actual height. If the landmark is a 30 m tower and the DSM already resolves it at 30 m,EXTRA_HEIGHTshould be 0 (or the tower height minus the DSM value at that location). The tool does not automatically detect the feature's height from the DSM — the user must measure and set it. - Sample cap. For very large landmarks (>2,000 m perimeter at 10 m sample step), the 200-point cap downsamples the boundary. A landmark sampled at 200 points still provides adequate exposure mapping — the angular density of sample points relative to the surrounding DSM cells is typically sufficient — but the silhouette-completeness interpretation (count = proportion of landmark visible) becomes approximate for very large structures.
- Vertical landmarks. A very tall, narrow landmark (chimney, minaret, spire) may be represented by only one or a few DSM pixels at the footprint. The boundary sampling still produces a ring of points whose viewshed origin differs in planimetric position but not in DSM elevation — for a truly vertical feature, the variation in visibility count per target cell is driven by horizontal obscuration alone, not by the landmark's vertical extent.
Academic References
Fisher, P.F. (1996). "Extending the Applicability of Viewsheds in Landscape Planning." Photogrammetric Engineering & Remote Sensing, 62(11), 1297–1302. journal article, no DOI available]
Mouflis, G.D., Gitas, I.Z., Iliadou, S., & Mitri, G.H. (2008). "Assessment of the Visual Impact of Marble Quarry Expansion (1984–2000) on the Landscape of Thasos Island, NE Greece." Landscape and Urban Planning, 86(1), 92–102. DOI: 10.1016/j.landurbplan.2008.01.001
Chmielewski, S., Lee, D.J., Tompalski, P., Chmielewski, T.J., & Wężyk, P. (2016). "Measuring Visual Pollution by Outdoor Advertisements in an Urban Street Using Intervisibility Analysis and Public Surveys." International Journal of Geographical Information Science, 30(4), 801–818. DOI: 10.1080/13658816.2015.1104316
Llobera, M. (2007). "Reconstructing Visual Landscapes." World Archaeology, 39(1), 51–69. DOI: 10.1080/00438240601136496
13. Population and Housing
The Population and Housing group translates demographic projections into spatial planning targets. Its four algorithms form a pipeline: Population Projection produces the horizon-year population; Housing Needs Assessment converts population into required dwellings; Residential Capacity tests whether current zoning can physically deliver those dwellings; and Allocate Population Growth distributes the increment across parcels so that downstream demand-driven tools (Facility Adequacy, Green Access, Transit Access) have spatial population surfaces to consume. Every algorithm is a screening tool -- the mathematics is deterministic and fully auditable, but the assumptions (migration rates, household size, vacancy targets, zoning discount factors) are policy choices that must be documented and scenario-tested.
Population Projection (Cohort-Component)
Processing ID: planx:populationprojection
1. Overview
Projects an age-structured population forward in discrete time steps using the cohort-component method, the global standard for demographic projection since the mid-20th century. The algorithm constructs a Leslie matrix from per-step survival rates and age-specific fertility rates, applies it repeatedly for the chosen horizon, and adds net migration after each step. Results are floored at zero -- population cannot go negative.
The projection is single-sex (total population), the standard screening simplification. For a two-sex projection, run the tool twice with sex-specific rates. Rates remain constant over the projection horizon -- producing a "what current trends imply" conditional projection, not a forecast. The horizon-year total and age structure feed directly into the Housing Needs Assessment and Facility Adequacy tools.
2. Theoretical Background
2.1 Academic lineage
The cohort-component method traces its mathematical foundation to Leslie (1945), who demonstrated that the age-structured population projection could be expressed as a single matrix multiplication: $\mathbf{n}_{t+1} = \mathbf{L} \mathbf{n}_t$, where $\mathbf{L}$ is a $k \times k$ matrix with fertility rates on the first row, survival probabilities on the sub-diagonal, and the final survival rate on the bottom-right diagonal to retain the open-ended oldest age group. This deceptively simple formulation turned what had been a tedious arithmetic exercise (tracking each cohort separately) into a one-line matrix operation, and it opened the door to analytical population mathematics: stable population theory, reproductive value, sensitivity analysis via eigen-decomposition, and stochastic projections.
Keyfitz extended the framework throughout the 1960s-1970s, formalising the link between the Leslie matrix and the stable population model and showing that the dominant eigenvalue of $\mathbf{L}$ equals the intrinsic growth rate $e^r$. Keyfitz & Caswell (2005, 3rd ed.) remains the canonical reference for applied mathematical demography, covering projection, stable theory, multi-state models, and perturbation analysis in a unified matrix framework. Rogers (1975, 1995) generalised the method to the multiregional case, adding origin-destination migration matrices to project population by age and region simultaneously -- the foundation of all modern sub-national demographic projection systems. Preston, Heuveline & Guillot (2001) provide the clearest textbook exposition of the standard cohort-component algorithm, including the demographic balancing equation and the construction of the Leslie matrix from age-specific rates.
2.2 From projection to forecast
A critical distinction, articulated by Romaniuc (1990) and elaborated by Burch (2018), separates three uses of the cohort-component algorithm: (a) prediction -- attempting to know the future, which demographers have largely abandoned beyond the very short term (~5 years); (b) simulation -- using the model to understand demographic dynamics and the relative influence of fertility, mortality, and migration on age structure, without making claims about a specific population (the "what-if" mode); and (c) prospective analysis -- working out plausible futures for a specific population, typically through scenario variants (low/medium/high migration). The PlanX implementation is designed for modes (b) and (c): the same engine, fed different migration assumptions, generates the scenario range that planning should respond to.
2.3 Assumptions and limitations
- Constant rates. Fertility and survival do not change over the projection horizon. This is the standard screening assumption, not a claim about behavioural stability. For long horizons (>20 years), the assumption becomes increasingly tenuous -- demographic transition theory predicts declining fertility and increasing longevity, which constant-rate projections will miss.
- Single-sex. The model tracks total population, not males and females separately. Births are assigned to the youngest age group using total fertility rates applied to the entire population. A two-sex model would apply fertility rates only to females and track the sex ratio at birth.
- No spatial disaggregation. The projection is aspatial -- one population vector for the entire study area. For spatially disaggregated projections, use Pop Allocate to distribute the horizon total, or implement a Rogers-style multiregional model.
- Migration is exogenous. Net migration is a fixed per-step vector added after the survival/fertility update. It does not respond to population pressure, housing supply, or economic conditions.
- Equal age-group widths. The Leslie matrix assumes all age groups have the same width (e.g. 5 years). The step duration should match this width.
3. Mathematical Formulation
Let the population be partitioned into $k$ age groups of equal width (e.g. 5-year groups: 0-4, 5-9, ..., 80+). Define:
- $\mathbf{n}_t \in \mathbb{R}^k_{\geq 0}$ -- population vector at step $t$; $n_{t,a}$ is the population in age group $a$.
- $s_a \in [0, 1]$ -- survival rate: share of age group $a$ surviving into age group $a+1$ per step. The last rate $s_{k-1}$ retains people in the terminal (open-ended) group.
- $f_a \geq 0$ -- fertility rate: births per person in age group $a$ per step. Non-zero only for childbearing ages.
- $m_a \in \mathbb{R}$ -- net migration per step for age group $a$ (may be negative for net out-migration).
Leslie matrix. The $k \times k$ projection matrix $\mathbf{L}$ is constructed as:
$$L_{0,a} = f_a \quad \text{for } a = 0, \ldots, k-1 \tag{1}$$ $$L_{a+1,a} = s_a \quad \text{for } a = 0, \ldots, k-2 \tag{2}$$ $$L_{k-1,k-1} = L_{k-1,k-1} + s_{k-1} \tag{3}$$All other entries are zero. Equation (3) adds the final survival rate to the bottom-right diagonal entry (which already carries $s_{k-2}$ from the sub-diagonal pattern for the penultimate group), keeping the oldest survivors in the terminal group rather than letting them age out of the model.
Projection step. For each step from $t$ to $t+1$:
$$\mathbf{n}_{t+1} = \max\left(0,\; \mathbf{L} \cdot \mathbf{n}_t + \mathbf{m}\right) \tag{4}$$where $\max(0, \cdot)$ is applied element-wise to prevent negative population. The migration vector $\mathbf{m}$ is added after the survival-and-birth update in each step. If no migration field is provided, $\mathbf{m} = \mathbf{0}$.
Output array. The full projection is stored as a $(\text{steps}+1) \times k$ matrix where row 0 is the starting population and each subsequent row is one projection step:
$$\mathbf{P} = \begin{bmatrix} n_{0,0} & n_{0,1} & \cdots & n_{0,k-1} \\ n_{1,0} & n_{1,1} & \cdots & n_{1,k-1} \\ \vdots & \vdots & \ddots & \vdots \\ n_{S,0} & n_{S,1} & \cdots & n_{S,k-1} \end{bmatrix} \tag{5}$$Per-step totals. The total population at each step is the row sum $T_s = \sum_a P_{s,a}$. The growth rate between steps $s-1$ and $s$ is:
$$g_s = 100 \cdot \left(\frac{T_s}{T_{s-1}} - 1\right) \quad [\%] \tag{6}$$4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Age-group table | Vector (no geometry) | Yes | One row per age group, ordered youngest to oldest. Must have numeric fields for population, survival, and fertility. At least 2 rows required. Equal-width groups (e.g. all 5-year) are assumed but not enforced -- using varying widths will produce distorted dynamics. |
Where to obtain rates: National statistical offices publish age-specific fertility rates (ASFR) and life tables from which survival ratios can be computed. The UN Population Division provides quinquennial estimates and projections for all countries. For sub-national projections, scale national rates by local age structure differentials where known (e.g. student towns have different mortality profiles). Migration is the hardest component -- historical net migration can be estimated as the residual of the demographic balancing equation, but forward assumptions are inherently policy-dependent.
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
INPUT | Vector layer | -- | Age-group table with one row per group, ordered youngest to oldest. |
AGE_FIELD | Field (string) | -- | Age-group label (e.g. "0-4", "5-9"). Used in output labelling only. |
POP_FIELD | Field (Numeric) | -- | Starting population count per age group. Negative values are floored to 0. |
SURVIVAL_FIELD | Field (Numeric) | -- | Per-step survival rate (0-1). Clamped to [0, 1]. The last row's value retains people in the terminal open-ended group. |
FERTILITY_FIELD | Field (Numeric) | -- | Births per person per step. Non-negative; zero outside childbearing ages. |
MIGRATION_FIELD | Field (Numeric) | -- (optional) | Net migration per step per age group. Can be negative (out-migration). If omitted, zero migration is assumed. |
STEPS | Integer | 4 | Number of projection steps. Range 1-40. With 5-year groups, 4 steps = 20-year horizon; 8 steps = 40 years. |
STEP_YEARS | Integer | 5 | Years per step (for output labelling only; does not affect the mathematics). Should match the age-group width. |
OUT_PROJECTION | Vector (table) | -- | Full projection: one row per step x age group. |
OUT_TOTALS | Vector (table) | -- | Per-step totals: population, growth %, net migration. |
6. Output Description
Projection table (OUT_PROJECTION):
| Field | Type | Description |
|---|---|---|
step | Integer | Projection step (0 = baseline) |
year_offset | Integer | Years from baseline (step x step_years) |
age_group | String | Age-group label from the input table |
population | Double | Projected population in this age group at this step |
Totals table (OUT_TOTALS):
| Field | Type | Description |
|---|---|---|
step | Integer | Projection step (0 = baseline) |
year_offset | Integer | Years from baseline |
population | Double | Total population across all age groups |
growth_pct | Double | Growth rate from previous step (%, 0 for baseline) |
net_migration | Double | Total net migration per step (0 for baseline) |
7. Symbolic Representation
Chart each step's age structure as a population pyramid (horizontal bars, males left if two-sex, females right). Plot the per-step totals as a line chart with confidence bands if scenario variants (low/medium/high migration) were run. Colour-code the pyramid bars by broad age group: 0-14 (green, pre-working), 15-64 (blue, working age), 65+ (orange, post-working). The dependency ratio -- (0-14 + 65+) / (15-64) -- is the single most policy-relevant summary statistic from the projection and should be tracked across steps.
8. Interpretation Guide
8.1 Age structure beats total
A flat total population trajectory can conceal violent age-structure shifts. Common patterns to watch for:
- School-age bulge arriving at step 2-3: fertility was high recently, and the large 0-4 cohort will hit primary school in 1-2 steps. Classroom demand will surge even if total population is stable.
- Over-65 wave: the large 55-64 cohort ages into post-retirement in 2-3 steps. This drives demand for accessible housing, health facilities, and public transport -- and reduces average household size, which increases the dwelling-unit need even if total population is falling (feed this to Housing Needs Assessment).
- Youth bulge (15-29): labour-market entry pressure. If jobs are scarce, this predicts out-migration; if jobs are plentiful, this is a demographic dividend.
8.2 The migration assumption IS the debate
Fertility and mortality change slowly and predictably. Migration does not. In most urban-planning contexts, the debate about "how many people will there be" is actually a debate about migration assumptions. The tool separates natural change from migration in the totals table, making this explicit. Run at least three variants -- low migration (zero or negative), medium (recent trend), high (policy target) -- and plan infrastructure to the range, not the central line. A plan that works only under the medium-migration assumption is fragile.
8.3 Cross-references
- Feed
populationfrom the horizon step to Housing Needs Assessment (POP_FUTUREparameter). - Feed the 5-14 age rows to Facility Adequacy to size school demand per step.
- The 65+ trajectory drives accessibility and health-facility standards.
- Compare against Residential Capacity: can the zoning absorb the projected growth? If not, either the projection is too high (migration will be constrained by supply) or the zoning is too restrictive.
8.4 Pitfalls
- Constant-rate extrapolation over long horizons. A 40-year projection with constant 2024 fertility rates implicitly assumes no demographic transition. Most developing cities will see declining fertility; most ageing cities will see increasing survival. Directional error accumulates with horizon length.
- Ignoring the household-size transition. A growing total population with falling household size (more singles, more elderly living alone) can generate more housing demand than a larger population with stable household size. The Housing Needs Assessment captures this -- feed it scenarios, not a single value.
9. Academic References
Leslie, P.H. (1945). "On the Use of Matrices in Certain Population Mathematics." Biometrika, 33(3), 183-212. DOI: 10.1093/biomet/33.3.183 verified
Keyfitz, N. & Caswell, H. (2005). Applied Mathematical Demography, 3rd ed. Springer. DOI: 10.1007/b139042 verified
Preston, S., Heuveline, P. & Guillot, M. (2001). Demography: Measuring and Modeling Population Processes. Wiley-Blackwell.
Rogers, A. (1995). Multiregional Demography: Principles, Methods and Extensions. John Wiley, New York.
Romaniuc, A. (1990). "Population Projection as Prediction, Simulation and Prospective Analysis." Population Bulletin of the United Nations, 29, 16-31.
Burch, T.K. (2018). "Cohort Component Projection: Algorithm, Technique, Model and Theory." In: Model-Based Demography. Demographic Research Monographs. Springer, Cham. DOI: 10.1007/978-3-319-65433-1_9 verified
Wheldon, M.C., Raftery, A.E., Clark, S.J. & Gerland, P. (2013). "Reconstructing Past Populations With Uncertainty From Fragmentary Data." Journal of the American Statistical Association, 108(501), 96-110. DOI: 10.1080/01621459.2012.737729 verified
===ALGORITHM===Housing Needs Assessment
Processing ID: planx:housingneeds
1. Overview
Computes the number of additional dwelling units that a plan must deliver by the horizon year, using the standard housing-needs identity employed in statutory planning systems worldwide: future population divided by household size yields households; a vacancy allowance is added to permit market fluidity; the existing stock, replacement losses, and any backlog of unfit or overcrowded units are netted out. The result -- positive means dwellings to build, negative means surplus -- is accompanied by every intermediate calculation so the output is fully auditable.
The tool is designed as a batchable identity: it takes six scalars and produces a metric/value table. For scenario analysis, run it repeatedly with different household-size and vacancy assumptions. The typical workflow chains it after Population Projection (horizon population) and before Residential Capacity (can the zoning deliver this need?).
2. Theoretical Background
2.1 The housing-needs identity in planning systems
The needs identity formalises what every housing plan implicitly does: estimate future households, allow for vacancies (a well-functioning market requires some empty units for mobility -- typically 3-5%), subtract what already exists, and add units lost to demolition or absorbed by overcrowding. Variants of this identity underpin the Regional Housing Needs Allocation (RHNA) process in California (since 1969), the Oregon Housing Needs Analysis (OHNA) under HB 2001/2889, the British Columbia HNR Method (2024), and the DRCOG Regional Housing Needs Assessment in Colorado. All share the same structure; they differ in which components are mandatory, how vacancy targets are calibrated, and whether they include a "demand buffer" for local housing-market pressure.
The identity is deliberately simple. Its power lies not in the arithmetic but in making every assumption visible: household size, vacancy target, replacement rate, and backlog are each a policy parameter, not a hidden constant. When a plan claims "we need X units," this tool shows exactly which assumption each component of X rests on.
2.2 Household size as the dominant lever
Liu et al. (2003), in a landmark Nature paper, demonstrated that household dynamics (declining average household size due to fewer children, more divorce, more elderly living alone) can be a larger driver of housing demand and resource consumption than population growth itself. A 0.2-person drop in average household size -- from 2.6 to 2.4, a common trajectory in urbanising societies -- generates more additional dwelling demand from the same population than a decade of moderate growth. This insight is the reason the household-size parameter is the most consequential dial in the entire population-and-housing pipeline. Testing household-size scenarios (e.g. 2.8, 2.5, 2.2) is not sensitivity analysis -- it is the honest needs range.
2.3 Vacancy and market function
A housing market with zero vacancy cannot function: nobody can move, new households cannot form, and prices rise without limit. The standard planning assumption is a target vacancy rate of 3-5%, drawn from the observation that well-functioning rental markets historically maintained roughly this level (CMHC, BC HNR Method; Oregon OHNA uses 5% as the 75th percentile of national vacancy 1980-2000). The vacancy allowance $\text{vacancy\_target} \times \text{households}$ adds "slack" units to the target stock. Critically, this is a target, not a forecast of actual vacancy -- if the plan delivers exactly the target stock and vacancy stays at 2%, the shortfall is 1% of stock, which in large cities can be thousands of units.
2.4 The backlog question
The backlog parameter captures existing unmet need: overcrowded households (by occupancy standards), units unfit for habitation, and concealed households (adults living with parents/friends who would form independent households if suitable housing existed). Most statutory methodologies now include a backlog component (OHNA calls it "current need" including underproduction and homelessness; BC HNR includes "extreme core housing need" and "suppressed households"). If you set backlog to zero, you are asserting that today's housing conditions are adequate -- a claim that should be documented, not defaulted to.
3. Mathematical Formulation
Let:
- $P$ -- horizon population (from Population Projection or external source)
- $h$ -- average household size at the horizon
- $v \in [0, 0.5]$ -- vacancy allowance as a share (e.g. 0.05 = 5%)
- $D$ -- existing dwelling stock (units)
- $R \geq 0$ -- replacement/demolition losses over the planning period
- $B \geq 0$ -- backlog of unfit/overcrowded units to absorb
Step 1 -- Future households:
$$H = \frac{P}{h} \tag{1}$$Step 2 -- Target dwelling stock (with vacancy allowance):
$$S_{\text{target}} = H \cdot (1 + v) \tag{2}$$Step 3 -- Net need (positive = units to deliver; negative = surplus):
$$N = S_{\text{target}} - D + R + B \tag{3}$$Substituting (1) and (2) into (3) yields the full identity in one line:
$$N = \frac{P}{h} \cdot (1 + v) - D + R + B \tag{4}$$Every term is exposed as an output row: the user (and any reviewer of the plan) can trace exactly how $N$ was derived from the six inputs.
4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Horizon population | Scalar | Yes | From Population Projection tool or external demographic forecast. The population of the study area at the plan horizon year. |
| Household size | Scalar | Yes | Expected average persons per household at the horizon. Obtain from census trend extrapolation or national projections. Typical urban values: 2.0-3.0. Declining trend is near-universal. |
| Existing dwellings | Scalar | Yes | Current dwelling stock count. From census, property tax register, or building-permit database. Include all tenure types. |
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
POP_FUTURE | Double | 10000.0 | Horizon population (min 0). Feed from Population Projection. |
HH_SIZE | Double | 2.5 | Average household size at the horizon (0.5-15.0). The single most influential parameter -- scenario-test this. |
EXISTING | Double | 3500.0 | Current dwelling stock (min 0). |
VACANCY | Double | 0.05 | Vacancy allowance share (0-0.5). Standard range 0.03-0.05. 0 = no slack in the market. |
REPLACEMENT | Double | 0.0 | Units lost to demolition/obsolescence over the planning period (min 0). |
BACKLOG | Double | 0.0 | Existing backlog to absorb -- overcrowded/unfit units (min 0). Zero = assert current conditions are adequate. |
OUT_SUMMARY | Vector (table) | -- | Metric/value table with every intermediate calculation. |
6. Output Description
| Field | Type | Description |
|---|---|---|
metric | String | Name of the calculation step |
value | Double | Numeric result for that step |
Rows:
| Metric | Meaning |
|---|---|
| Horizon population | $P$ as entered |
| Household size | $h$ as entered |
| Future households | $H = P / h$ |
| Vacancy allowance | $v$ as entered |
| Target stock (units) | $S_{\text{target}}$ |
| Existing dwellings | $D$ as entered |
| Replacement losses | $R$ as entered |
| Backlog | $B$ as entered |
| Dwellings needed | $N$ (the final answer; negative = surplus) |
7. Symbolic Representation
The output is a table, not a map. Present it as a waterfall chart: start with horizon population, step down through each division and adjustment, and land on dwellings needed. Each bar is one output row. Colour positive contributions (additions to need) in warm tones, negative contributions (deductions) in cool tones. The chart makes immediately visible which assumption dominates the result -- typically household size or backlog.
8. Interpretation Guide
8.1 The sensitivity spread IS the honest range
A single run produces a single number. That number is fragile. Run at least these variants:
- Household size: base, base - 0.3, base + 0.3 (e.g. 2.5, 2.2, 2.8)
- Vacancy: 0.03 (tight market), 0.05 (healthy), 0.07 (loose)
- Backlog: zero (optimistic), estimated, estimated x 2 (pessimistic)
The spread between the lowest-need combination and the highest-need combination is the honest planning range. If the plan's housing target falls outside this range, justify why.
8.2 Surplus with housing stress = type mismatch
A negative need (surplus) coexisting with observable housing stress (high rents, overcrowding, homelessness) means the mismatch is not in unit count but in type, tenure, affordability, or location. The identity counts units, not bedrooms, not affordability, not location. A surplus of 4-bedroom suburban houses does nothing for 1-person renters needing city-centre studios. When this pattern appears, the plan needs a tenure/type disaggregation -- this tool identifies the macro-level adequacy; complementary market analysis addresses the distributional question.
8.3 Zero backlog, zero replacement = implicit optimism
Setting both to zero asserts: (a) every existing dwelling is fit and adequately occupied, and (b) no dwelling will be lost to fire, demolition, conversion, or obsolescence over the plan period. Both assertions are almost certainly false. If you lack local data, use national/regional benchmarks: typical annual demolition rates are 0.1-0.3% of stock; backlog estimates can be derived from census overcrowding statistics (more than 1 person per room) or dwelling-condition surveys. Note the omission explicitly rather than defaulting to zero silently.
8.4 Cross-references
- Feed
needto Residential Capacity: if capacity < need, the plan must upzone, expand the urban boundary, or challenge its population/household-size assumptions. - If capacity > need but affordability remains poor, the issue is allocation, not quantity -- the zoning allows units in the wrong places or at the wrong price points.
- Run the Scenario Pipeline (LUTI-lite) with the horizon population and household numbers to test whether the land-use plan can physically accommodate the projected households.
9. Academic References
Liu, J., Daily, G.C., Ehrlich, P.R. & Luck, G.W. (2003). "Effects of household dynamics on resource consumption and biodiversity." Nature, 421, 530-533. DOI: 10.1038/nature01359 verified
Bramley, G. (2007). "The sudden rediscovery of housing supply as a key policy challenge." Housing Studies, 22(2), 221-241. DOI: 10.1080/02673030601132847 verified
Meen, G. & Nygaard, C. (2010). "Housing and the economy." In: Malpass, P. & Rowlands, R. (eds) Housing, Markets and Policy. Routledge.
Bibby, P., Henneberry, J. & Halleux, J.-M. (2020). "Under the radar? 'Soft' residential densification." EPB: Urban Analytics and City Science, 47(1), 102-118. DOI: 10.1177/2399808318772842 verified
Holmans, A.E. (2013). "New estimates of housing demand and need in England, 2011 to 2031." Town & Country Planning, 82(10), 435-441.
State of Oregon DAS (2024). Oregon Housing Needs Analysis Methodology Report.
Province of British Columbia (2024). HNR Method Technical Guidance -- Guidelines for Housing Needs Reports.
===ALGORITHM===Residential Capacity
Processing ID: planx:residentialcapacity
1. Overview
Computes the remaining dwelling-unit capacity of every parcel under current zoning. For each parcel: potential floorspace = parcel area x floor-area ratio (FAR); buildable floorspace = max(0, potential - existing floorspace); dwelling units = floor(buildable x net-to-gross efficiency / average unit size). The flooring is deliberately conservative -- fractional units do not exist. Outputs a parcel layer with buildable floorspace and unit capacity, plus an optional district-level roll-up. The total capacity, suitably discounted (typically to 50-70% over a plan horizon), is compared against the Housing Needs Assessment to determine whether the plan's zoning can physically deliver the required dwellings.
2. Theoretical Background
2.1 Floor Area Ratio as the zoning instrument
Floor Area Ratio (FAR) -- the ratio of total building floor area to parcel area -- is the most widely used instrument for regulating built density in zoning ordinances worldwide. Originating in the 1916 New York City Zoning Resolution and formalised in the 1961 revision, FAR replaced height-and-setback rules with a single, economically meaningful parameter: a developer can spread the permitted floor area over few storeys (low-rise, large footprint) or many storeys (tower, small footprint), but the total buildable area is fixed by FAR x parcel area. In residential capacity analysis, FAR serves as the upper bound on potential floorspace from which existing development is subtracted to yield remaining capacity.
2.2 Capacity, not supply
The distinction between zoning capacity (what rules allow) and market supply (what gets built) is fundamental. Capacity analysis identifies the physical upper bound of the current zoning envelope. Multiple factors cause actual development to fall short:
- Ownership fragmentation and assembly. A parcel may be zoned for 200 units, but if it is divided among 40 owners, assembly risk makes the capacity theoretical. Bibby, Henneberry & Halleux (2020) document the "soft densification" that occurs through piecemeal subdivision and infill, which rarely exhausts zoned capacity.
- Development viability. Zoning may permit 10 storeys on a site where construction costs exceed achievable sales/rental values beyond 6 storeys. The "effective" FAR is lower than the "nominal" FAR.
- Heritage, environmental, and infrastructure constraints. Overlay designations, flood zones, slope instability, and sewer/water capacity limits can render portions of a parcel unbuildable regardless of FAR.
- Market absorption. Even where zoning and viability align, a local market may absorb only a fraction of capacity within a plan horizon (e.g. 50-100 units/year in a medium-sized city).
Standard planning practice applies a discount factor of 50-70% to theoretical capacity for horizon-year planning. This is not pessimism -- it is empirical observation across dozens of plan reviews.
2.3 Net-to-gross efficiency
The efficiency factor $e \in [0.1, 1.0]$ (default 0.85) accounts for the share of gross floorspace that is actually sellable/rentable residential area. The remaining 15% (in the default) goes to common circulation (corridors, stairs, lifts), service cores, plant rooms, and structural elements. In high-rise typologies with double-loaded corridors, efficiency may drop to 0.75-0.80; in walk-up or point-block typologies, it can reach 0.90. The parameter exists so the analyst can calibrate to local building typologies -- use 0.80 for suburban apartment blocks, 0.90 for terrace/semi-detached.
3. Mathematical Formulation
Let parcel $i$ have area $A_i$ (in square map units, typically m$^2$) and zoning floor-area ratio $\text{FAR}_i$. The potential floorspace is:
$$F_i^{\text{pot}} = A_i \cdot \max(0, \text{FAR}_i) \tag{1}$$If existing floorspace $E_i$ is provided, the buildable floorspace is the residual after subtracting what already stands:
$$F_i^{\text{build}} = \max\left(0,\; F_i^{\text{pot}} - E_i\right) \tag{2}$$Finally, the dwelling-unit capacity is the buildable floorspace multiplied by the net-to-gross efficiency $e$ and divided by the average unit size $u$, rounded down to whole dwellings:
$$C_i = \left\lfloor \frac{F_i^{\text{build}} \cdot e}{u} \right\rfloor \tag{3}$$where $\lfloor \cdot \rfloor$ is the floor function (greatest integer less than or equal to the argument). The rounding-down is conservative: a parcel with 0.9 units of capacity is reported as 0, not 1.
The total theoretical capacity across all $n$ parcels is:
$$C_{\text{total}} = \sum_{i=1}^{n} C_i \tag{4}$$and the planning capacity (for comparison against housing need) is:
$$C_{\text{plan}} = d \cdot C_{\text{total}} \tag{5}$$where $d \in [0.3, 0.7]$ is the discount factor (not applied by the tool; applied by the analyst post-hoc).
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
PARCELS | Vector (Polygon) | -- | Parcel layer. Must be in a projected CRS (area in m$^2$). |
FAR_FIELD | Field (Numeric) | -- | Floor area ratio per parcel. Non-numeric or missing values counted as 0 with a warning. |
EXISTING_FIELD | Field (Numeric) | -- (optional) | Existing above-ground floorspace (m$^2$). Omit to compute gross capacity ignoring existing development. |
DISTRICT_FIELD | Field | -- (optional) | Grouping field for the district roll-up (e.g. neighbourhood, planning zone). |
UNIT_SIZE | Double | 90.0 | Average dwelling size in m$^2$ (10-1000). Typical: 60-80 m$^2$ for apartments, 100-150 m$^2$ for houses. |
EFFICIENCY | Double | 0.85 | Net-to-gross efficiency (0.1-1.0). 0.85 = 15% of floorspace is non-sellable. |
OUT_PARCELS | Vector (Polygon) | -- | Parcel output with capacity fields. |
OUT_DISTRICTS | Vector (table) | -- | District roll-up: total area, buildable floorspace, and units per district. |
6. Output Description
Parcel output (OUT_PARCELS):
| Field | Type | Description |
|---|---|---|
buildable_m2 | Double | Remaining buildable floorspace (m$^2$) after subtracting existing. 0 = at or above zoned capacity. |
cap_units | Integer | Dwelling-unit capacity (rounded down to whole units). |
(Plus all original parcel fields.)
District roll-up (OUT_DISTRICTS):
| Field | Type | Description |
|---|---|---|
district | String | District identifier from the grouping field |
area_m2 | Double | Total parcel area in the district |
buildable_m2 | Double | Total buildable floorspace in the district |
cap_units | Integer | Total unit capacity in the district |
8. Interpretation Guide
8.1 Report both theoretical and discounted capacity
Quote two numbers: the raw tool output (theoretical zoning capacity) and the discounted figure (50-70% of theoretical). The theoretical number answers "what does the zoning allow?"; the discounted number answers "what is likely to materialise in the plan horizon?" Both are honest if labelled. A plan that claims the theoretical figure as the deliverable target without discounting will face implementation failure.
8.2 Concentration risk
Plot cap_units by parcel. If the top 3 parcels account for more
than 50% of total capacity, the supply is fragile: one
landowner stalling, one viability issue, or one infrastructure bottleneck can
eliminate half the plan's housing pipeline. A healthy capacity distribution has
the top 10% of parcels contributing no more than 20-25% of total units.
8.3 cap_units = 0 with high FAR = built-out districts
Parcels where cap_units = 0 despite a high FAR are
built-out: the existing development already exceeds or meets
the zoning envelope. These districts cannot contribute additional units without
an upzoning (increase in FAR). Map them -- they are the "full" districts that
will resist growth absorption unless policy changes.
8.4 Cross-references
- Compare discounted total capacity against Housing Needs Assessment need. If capacity < need, the gap quantifies the required upzoning or expansion.
- Feed
cap_unitsto Allocate Population Growth as the weight field -- this ensures scenario population lands where zoning can absorb it. - Feed parcels to Scenario Pipeline (LUTI-lite) as development sites with capacity constraints.
- Overlay with Plan Performance Report to show the capacity/need balance in the dashboard.
8.5 Pitfalls
- Assuming 100% take-up. No city achieves full build-out of its zoning envelope within a plan horizon. Always discount.
- Ignoring the existing-floorspace field. Without
EXISTING_FIELD, the tool computes gross capacity -- units that could exist on a vacant site. Most parcels are not vacant. Providing existing floorspace converts gross to net (remaining) capacity, which is what the plan actually needs to know. - Unit size mismatch. If zoning permits luxury apartments (150 m$^2$) but need is for affordable units (60 m$^2$), the tool will under-count potential units by a factor of 2.5. Run with the unit size that matches the plan's tenure target, not the market's current average.
9. Academic References
Bibby, P., Henneberry, J. & Halleux, J.-M. (2020). "Under the radar? 'Soft' residential densification." EPB: Urban Analytics and City Science, 47(1), 102-118. DOI: 10.1177/2399808318772842 verified
Ewing, R. & Cervero, R. (2010). "Travel and the built environment: a meta-analysis." Journal of the American Planning Association, 76(3), 265-294. DOI: 10.1080/01944361003766766 verified
Seattle Department of Planning and Development (2014). Zoned Development Capacity Model Primer.
ABAG (2021). Draft RHNA Methodology Report 2023-2031. Association of Bay Area Governments.
Ewing, R., Pendall, R. & Chen, D. (2002). Measuring Sprawl and Its Impact. Smart Growth America.
Cheshire, P. & Sheppard, S. (2002). "The welfare economics of land use planning." Journal of Urban Economics, 52(2), 242-269. DOI: 10.1016/S0094-1190(02)00003-7 verified
===ALGORITHM===Allocate Population Growth
Processing ID: planx:popallocate
1. Overview
Distributes a population increment across spatial units (parcels or zones) using largest-remainder apportionment, the Hare-Niemeyer method. Given a total increment $T$ and a weight $w_i$ per unit, the algorithm computes the quota $T \cdot w_i / \sum w_j$, assigns the integer floor to each unit, and allocates the remaining $R$ units one-by-one to the units with the largest fractional remainders. The result sums exactly to $T$ -- no rounding error, no drift. Weights can come from a capacity field (e.g. remaining dwelling units from Residential Capacity), a custom field, or default to uniform (each unit gets an equal share).
This is the bridge between an aggregate growth figure and a spatial population distribution: the allocated population, added to the current baseline, becomes the horizon-year demand surface that downstream tools (Facility Adequacy, Green Access, Transit Access, noise/air receivers) consume.
2. Theoretical Background
2.1 Apportionment theory
The problem of allocating an integer total proportionally to weights -- the apportionment problem -- has been studied since the founding of the United States, where the Constitution requires seats in the House of Representatives to be apportioned among states by population. The largest- remainder method (Hamilton's method, also known as Hare-Niemeyer or Vinton's method) was the first method adopted (1792-1840) and remains the third most commonly used electoral system worldwide after d'Hondt and Sainte-Lague (Pukelsheim, 2017).
The method is defined by three properties:
- Quota rule. Each unit's allocation is either the floor or the ceiling of its exact quota -- it never deviates by more than one unit from the ideal proportional share.
- Exact summation. The sum of all allocations equals the total, by construction.
- Determinism. Ties in fractional remainders are broken by index order (the first unit with a given remainder wins). This makes the allocation reproducible: same inputs produce the same output every time.
However, the method does exhibit the Alabama paradox (increasing the total can decrease a unit's allocation) and the population paradox (a unit whose weight grows faster than another can lose seats). In the planning context, these paradoxes are immaterial because the total increment and weights are scenario parameters, not empirical measurements -- the method's guarantee of exact summation outweighs the theoretical imperfections (Balinski & Young, 2001).
2.2 Weights encode the story
The weight field is the spatial policy. Three common choices:
- Capacity-weighted: growth follows zoning -- units with more remaining dwelling capacity receive more population. This is the "plan-led" scenario.
- Custom-weighted: growth follows an externally defined suitability score, land value, accessibility index, or policy priority. Whatever story the field encodes, the allocation reproduces it proportionally.
- Uniform: every unit receives an equal share -- the null-hypothesis allocation against which weighted scenarios are compared.
3. Mathematical Formulation
Let there be $n$ spatial units with weights $w_i \geq 0$, and let the total population increment to allocate be $T > 0$ (integer). Define the total weight $W = \sum_{i=1}^{n} w_i$.
Step 1 -- Quota calculation. Each unit's exact proportional share (quota) is:
$$q_i = T \cdot \frac{w_i}{W} \tag{1}$$If $W = 0$ (all weights zero), uniform weights $w_i = 1$ are substituted.
Step 2 -- Integer allocation. Assign the integer floor to each unit:
$$a_i = \lfloor q_i \rfloor \tag{2}$$The remainder (unallocated units) is:
$$R = T - \sum_{i=1}^{n} a_i \tag{3}$$Step 3 -- Largest-remainder distribution. Define the fractional remainder $r_i = q_i - a_i$. Sort units by $r_i$ descending, breaking ties by ascending index $i$. Assign one additional unit to each of the first $R$ units in this sorted order:
$$a_i \leftarrow a_i + 1 \quad \text{for the } R \text{ units with largest } r_i \tag{4}$$The final allocation $\mathbf{a} = (a_1, \ldots, a_n)$ satisfies:
$$\sum_{i=1}^{n} a_i = T \quad \text{and} \quad a_i \in \{\lfloor q_i \rfloor, \lceil q_i \rceil\} \tag{5}$$5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
PARCELS | Vector (Polygon/Point) | -- | Spatial units to receive population. Points or polygons accepted. |
INCREMENT | Integer | 100 | Total population to allocate (min 0). |
CAPACITY_FIELD | Field (Numeric) | -- (optional) | Remaining dwelling capacity per unit. If provided and no weight field given, the allocation is proportional to capacity. Non-numeric treated as 0. |
WEIGHT_FIELD | Field (Numeric) | -- (optional) | Custom allocation weight per unit. Overrides capacity field. Non-numeric treated as 0. |
OUTPUT | Vector | -- | Input features with allocated field appended. |
6. Output Description
| Field | Type | Description |
|---|---|---|
allocated | Integer | Population assigned to this unit. Sums to INCREMENT across all features. 0 for zero-weight units. |
(Plus all original input fields.)
8. Interpretation Guide
8.1 allocated is a distribution, not a forecast
The allocation is a bookkeeping operation: it places the increment exactly, proportional to the chosen weights. The result is only as meaningful as the weight field. Capacity-weighted allocation says "if growth follows zoning, here is where people land." Custom-weighted allocation says "if growth follows [your variable], here is where people land." Always state the weight basis alongside the result.
8.2 Zero-weight units get nothing
Check that protected areas, water bodies, parks, and fully built-out parcels carry zero weight before interpreting the map. A unit with zero allocated population may be (a) intentionally excluded (protected), (b) at capacity (zero remaining units), or (c) missing a weight value. Verify which case applies by cross-referencing against the source data.
8.3 Building the horizon-year population layer
The output allocated field is the increment,
not the total. To create the horizon-year population layer that downstream
tools consume: add allocated to the current population field (if
one exists) or create a new field horizon_pop = allocated + baseline.
If starting from zero (greenfield allocation), allocated is the
total.
8.4 Scenario comparison
Run one allocation per scenario weight scheme and compare the spatial distributions using Scenario Compare (A/B):
- Capacity-weighted: compact infill scenario -- population concentrates where zoning permits density.
- Greenfield-weighted: expansion scenario -- population spreads to undeveloped land at the urban edge.
- Accessibility-weighted: transit-oriented scenario -- population concentrates near high-frequency transit.
The spatial pattern differences between these allocations drive all downstream metrics (access scores, facility adequacy, emissions). A small change in total population allocated differently can produce larger changes in downstream metrics than a large change allocated identically.
9. Academic References
Pukelsheim, F. (2017). Proportional Representation: Apportionment Methods and Their Applications. Springer. DOI: 10.1007/978-3-319-64707-4 verified
Balinski, M.L. & Young, H.P. (2001). Fair Representation: Meeting the Ideal of One Man, One Vote, 2nd ed. Brookings Institution Press.
Marshall, A.W., Olkin, I. & Pukelsheim, F. (2002). "A majorization comparison of apportionment methods in proportional representation." Social Choice and Welfare, 19, 885-900. DOI: 10.1007/s003550200164 verified
Schuster, K., Pukelsheim, F., Drton, M. & Draper, N.R. (2003). "Seat biases of apportionment methods for proportional representation." Electoral Studies, 22, 651-676. DOI: 10.1016/S0261-3794(02)00012-8 verified
Hammer, M. & Weber, K. (2010). "Apportionment methods." The Stata Journal, 12(3), 375-392. DOI: 10.1177/1536867X1201200303 verified
14. Green Infrastructure
The Green Infrastructure group evaluates urban green space from two complementary perspectives: access (can people reach green spaces of adequate size?) and connectivity (do green patches form a functional ecological network?). The two tools are designed to be used together: Green Space Access answers the planning-standard question ("does every resident have a park within X metres?"), while Urban Green Connectivity answers the ecological question ("which patches are critical to keeping the green network whole?"). A site that scores well on access but poorly on connectivity may serve recreation but not biodiversity; a site that scores well on connectivity but poorly on access serves ecology but not people. The best green-infrastructure plans close both gaps.
===ALGORITHM===Green Space Access
Processing ID: planx:greenaccess
1. Overview
Evaluates whether every demand point (building, census block, address) can
reach publicly accessible green spaces of different size classes within the
distances specified by a park hierarchy standard. The
hierarchy is a free-text parameter of the form
min_ha=max_distance, ... -- for example,
0.5=300, 2=800, 10=2000 specifies three classes: pocket parks
(at least 0.5 ha, within 300 m), neighbourhood parks (at least 2 ha, within
800 m), and district parks (at least 10 ha, within 2 km). Distances are
measured on the street network (multi-source Dijkstra from all qualifying
greens), with the residual straight-line snap distance added to the network
distance. The output reports, per demand point, the network distance to the
nearest qualifying green space of each class, whether the distance standard is
met (ok=1/0), and how many classes are satisfied in total. A population-
weighted coverage summary per class completes the output.
2. Theoretical Background
2.1 Park hierarchy standards
The idea that green spaces should be classified by size and expected to serve populations within a specified catchment distance is a cornerstone of urban planning standards worldwide. The concept was formalised in the UK by English Nature's Accessible Natural Greenspace Standard (ANGSt), first published in 1995 (Harrison et al.) and updated in 2010 (Nature Nearby) and again in 2023 as the Accessible Greenspace Standards under the Green Infrastructure Framework. ANGSt specified that everyone should have: an accessible natural greenspace of at least 2 ha within 300 m; at least 20 ha within 2 km; at least 100 ha within 5 km; and at least 500 ha within 10 km. The 2023 revision added a Doorstep Greenspace criterion (0.5 ha within 200 m) as an alternative for dense urban areas where 2 ha within 300 m is physically unachievable.
Similar hierarchy standards exist internationally:
- China (Shenzhen): community park within 500 m, city park within 2 km, natural park within 5 km (Li et al., 2019).
- Germany (Berlin): playground within 500 m, neighbourhood park within 1 km, district park within 3 km.
- WHO recommendation (2016): urban residents should have access to public green space of at least 0.5 ha within 300 m linear distance.
The hierarchy standard is the parameter -- the tool does not hard-code any particular standard. Bring your own regulation.
2.2 Network vs. Euclidean distance
The choice of distance metric has substantial consequences for the results. Higgs, Fry & Langford (2012) systematically compared Euclidean buffers, network distance, and travel-time isochrones for green-space accessibility assessment in Wales. They found that Euclidean (straight-line) methods overestimate the served population by 15-40% compared to network methods, because a green space that is 280 m "as the crow flies" may require a 500 m walk if a river, railway, or walled superblock stands in between. The PlanX implementation uses network distance with a straight-line snap offset (the distance from the demand point to the nearest network node, plus the distance from the green space to its nearest network node), which is the standard compromise between full network routing (expensive) and Euclidean approximation (inaccurate).
2.3 Per-capita green provision
A secondary metric logged by the tool is city-wide green area per capita (total green area / total population). The WHO recommends a minimum of 9 m$^2$ per capita, with an ideal of 50 m$^2$ (in practice, observed values range from <1 m$^2$ in dense informal settlements to >100 m$^2$ in low-density garden cities). This metric can mask severe spatial inequity: a city with one 100-ha park at the edge and dense population at the centre scores well on per-capita area but abysmally on access. The access tool exists to expose exactly that discrepancy.
3. Mathematical Formulation
Let the hierarchy define $K$ classes, each a pair $(s_k, d_k)$ where $s_k$ is the minimum area (ha) and $d_k$ is the maximum network distance (metres). Let $\mathcal{G}$ be the set of $M$ green spaces with areas $A_j$ and representative points (centroids or entrance points). A green space qualifies for class $k$ if:
$$A_j \geq s_k \cdot 10\,000 \quad [\text{m}^2] \tag{1}$$For each class $k$, let $\mathcal{Q}_k = \{j \in \mathcal{G} : A_j \geq s_k \cdot 10\,000\}$ be the qualifying subset. A multi-source Dijkstra run from all qualifying greens assigns to each network node $v$ the shortest-path distance to the nearest qualifying green, adjusted by the snap offset:
$$D_k(v) = \min_{j \in \mathcal{Q}_k} \left[ d_{\text{net}}(g_j, v) + \delta_j \right] \tag{2}$$where $d_{\text{net}}(g_j, v)$ is the shortest-path distance on the street network from the snap-node of green $j$ to node $v$, and $\delta_j$ is the straight-line distance from green $j$'s representative point to its snap-node.
For each demand point $i$ (mapped to its nearest network node $v_i$), the class-$k$ distance is:
$$d_{k,i} = \delta_i^{\text{demand}} + D_k(v_i) \tag{3}$$where $\delta_i^{\text{demand}}$ is the straight-line snap distance from demand point $i$ to $v_i$.
The standard-compliance flag for demand point $i$ and class $k$ is:
$$\text{ok}_{k,i} = \begin{cases} 1 & \text{if } d_{k,i} \leq d_k \text{ and is finite} \\ 0 & \text{otherwise} \end{cases} \tag{4}$$The classes met for demand point $i$ is:
$$M_i = \sum_{k=1}^{K} \text{ok}_{k,i} \tag{5}$$The population-coverage share for class $k$ is:
$$\text{Coverage}_k = \frac{\sum_{i: \text{ok}_{k,i}=1} \text{pop}_i}{\sum_i \text{pop}_i} \tag{6}$$5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | -- | Street network. Must be in projected CRS. Crossing lines should share nodes (use Prepare Network first). |
DEMAND | Vector (any geometry) | -- | Demand points (buildings, blocks, addresses). Centroids used for polygon inputs. |
POP_FIELD | Field (Numeric) | -- (optional) | Population per demand point. Omitted = each point counts as 1 person. |
GREENS | Vector (Polygon) | -- | Public green space polygons. Representative points (centroids) used for all network queries. |
HIERARCHY | String | "0.5=300, 2=800, 10=2000" | Park hierarchy: min_ha=max_dist pairs separated by commas or semicolons. The standard for your jurisdiction. |
OUT_DEMAND | Vector (Point) | -- | Demand points with access metrics appended. |
OUT_SUMMARY | Vector (table) | -- | Coverage summary per hierarchy class. |
6. Output Description
Demand output (OUT_DEMAND):
| Field | Type | Description |
|---|---|---|
d_c1, d_c2, ... | Double | Network distance to nearest qualifying green for classes 1, 2, ... (null if unreachable) |
ok_c1, ok_c2, ... | Integer (0/1) | Whether the distance standard is met for each class |
classes_met | Integer | Number of hierarchy classes satisfied (0 to K). 0 = green desert. |
(Plus all original demand fields.)
Summary output (OUT_SUMMARY):
| Field | Type | Description |
|---|---|---|
class | Integer | Hierarchy class number (1, 2, ...) |
min_ha | Double | Minimum green-space size for this class |
max_dist | Double | Maximum distance standard for this class |
covered_pop | Double | Population meeting the standard for this class |
coverage_pct | Double | Percentage of total population covered |
n_greens | Integer | Number of green spaces qualifying for this class |
8. Interpretation Guide
8.1 The coverage ladder
The summary table forms a coverage ladder: coverage typically decreases as the class index increases (small pocket parks cover most people; large district parks cover far fewer). Cities commonly score 80-95% on class 1 (pocket parks within 300 m) and 30-50% on class 3 (district parks within 2 km). A sharp drop between classes indicates that green space is fragmented into many small pieces without the large destination parks that make a green network useful for recreation and biodiversity.
8.2 Green deserts (classes_met = 0)
Demand points with classes_met = 0 are green
deserts: they fail every hierarchy class. Map them and overlay on
population density. The combination of high population density and zero classes
met defines the planning priority: a new green space here will serve more
people per hectare than anywhere else. If land acquisition is impossible (dense
old city), consider pocket parks, green roofs, or street-tree planting as
partial mitigations.
8.3 Green per capita vs. access
The log reports city-wide green area per capita. This number can be misleading. A city of 1 million with a 500-ha forest at the northern boundary has 5 m$^2$ per capita and looks adequate -- but if the entire population lives in the southern half beyond a 2-km walk, the access metric will be near zero. Always report per-capita area and access coverage together. When they disagree, the access metric is the more policy-relevant number for everyday recreation.
8.4 Cross-references
- Service Areas (Isochrones): where a demand point fails the distance standard but a qualifying green lies just beyond a barrier (river, railway, motorway), the remedy is a crossing, not a new park. Use Service Areas to verify that the barrier is the problem.
- Urban Green Connectivity: a site that meets access standards but sits in a low-dPC fragmented patch serves people but not ecology. Run both tools and compare the priority maps.
- Scenario Pipeline (LUTI-lite): test the effect of new green spaces on the coverage ladder by adding candidate park polygons to the greens layer and re-running.
8.5 Pitfalls
- Using Euclidean distance when the network is available. Straight-line access overstates coverage by 15-40% (Higgs et al., 2012). The network is always worth the extra computation.
- Centroid snap for large parks. A 100-ha park is represented by its centroid. If the demand point is near the park edge but the centroid is far (on the other side of the park), the network distance will be overstated. For large parks, consider creating multiple entrance points manually.
- Standards without population weights. Coverage by area ("80% of the city is within 300 m of a park") is less informative than coverage by population. Always use the population field when available.
9. Academic References
Higgs, G., Fry, R. & Langford, M. (2012). "Investigating the implications of using alternative GIS-based techniques to measure accessibility to green space." Environment and Planning B, 39(2), 326-343. DOI: 10.1068/b37130 verified
Handley, J., Pauleit, S., Slinn, P., Barber, A., Baker, M., Jones, C. & Lindley, S. (2003). "Accessible Natural Greenspace Standards in Towns and Cities." English Nature Research Report 526.
Natural England (2010). Nature Nearby: Accessible Natural Greenspace Guidance. NE265.
Li, L., Du, Q., Ren, F. & Ma, X. (2019). "Assessing Spatial Accessibility to Hierarchical Urban Parks by Multi-Types of Travel Distance in Shenzhen, China." International Journal of Environmental Research and Public Health, 16(6), 1038. DOI: 10.3390/ijerph16061038 verified
WHO Regional Office for Europe (2016). Urban green spaces and health: A review of evidence. Copenhagen.
Wang, S., Wang, M. & Liu, Y. (2021). "Access to urban parks: Comparing spatial accessibility measures using three GIS-based approaches." Computers, Environment and Urban Systems, 90, 101713. DOI: 10.1016/j.compenvurbsys.2021.101713 verified
Tzoulas, K., Korpela, K., Venn, S., Yli-Pelkonen, V., Kazmierczak, A., Niemela, J. & James, P. (2007). "Promoting ecosystem and human health in urban areas using Green Infrastructure." Landscape and Urban Planning, 81(3), 167-178. DOI: 10.1016/j.landurbplan.2007.02.001 verified
===ALGORITHM===Urban Green Connectivity
Processing ID: planx:greenconnectivity
1. Overview
Evaluates the green network as a connected system rather than a collection of isolated patches. Two patches are considered linked when their edge-to-edge separation is at most a user-specified maximum gap distance. The algorithm builds a graph where patches are nodes and links represent proximity, finds connected components via depth-first search, and computes two indices from Saura & Pascual-Hortal (2007): the Probability of Connectivity (PC) -- the equivalent probability that two random points in the green system fall within the same connected component -- and the per-patch importance (dPC) -- the percentage of PC lost if that patch and its links were removed. The output identifies which patches are structurally critical: small stepping-stone patches often carry disproportionately large dPC values, making the case for their protection.
2. Theoretical Background
2.1 Habitat availability, not just connectivity
Pascual-Hortal & Saura (2006) established that landscape connectivity must be considered within the wider concept of habitat availability: a patch itself is a space where connectivity occurs. The integral index of connectivity (IIC) and later the probability of connectivity (PC) integrate both within-patch area (how much habitat each patch provides) and between-patch connectivity (whether patches are linked) into a single measure. This resolves a fundamental flaw of earlier indices: a landscape of one large patch (covering the entire study area) should score maximum connectivity, not zero. Most earlier indices returned zero for this case because they defined connectivity only between distinct patches.
Saura & Pascual-Hortal (2007) introduced PC and demonstrated through a systematic 13-property evaluation that it is the only index among those tested that: (a) does not increase with fragmentation, (b) correctly handles single-patch landscapes, (c) detects the critical importance of stepping-stone patches, and (d) has a bounded range [0, 1]. The binary version used in PlanX (all pairs within the gap counted as connected with weight 1) is the simplest form; the full probabilistic PC weights connections by a dispersal kernel (e.g. exponential decay with distance). The binary version is adequate for planning screening where the gap threshold is the policy parameter.
2.2 Graph-theoretic foundation
The approach treats green patches as nodes in a planar graph where an edge exists between patches $i$ and $j$ when $\text{distance}(i, j) \leq d_{\max}$. This is a proximity graph, specifically a distance-threshold graph (also called a geometric graph or unit-disk graph in computational geometry). The connected components of this graph are the functional green networks -- sets of patches that a target organism or pedestrian can traverse without crossing a gap wider than $d_{\max}$. The choice of $d_{\max}$ is the critical parameter: 100 m models pedestrian permeability, 50 m models small-mammal dispersal (hedgehogs), 500 m models bird movement. Run at 2-3 different gaps to test robustness.
2.3 The stepping-stone paradox
A key finding from Saura & Pascual-Hortal's empirical application to goshawk habitat in Catalonia was that the maximum dPC value (1.27%) belonged to a single 1 km$^2$ stepping-stone patch -- 0.04% of total habitat area -- whose removal would disconnect two large habitat clusters. This is the planning argument the tool operationalises: hectares understate ecological role. A small patch with high dPC is not a candidate for development; it is the keystone of the green network.
3. Mathematical Formulation
Let there be $n$ patches with areas $a_i > 0$ (in m$^2$). Let $\mathcal{E} = \{(i, j) : \text{dist}(i, j) \leq d_{\max}, i < j\}$ be the set of edges linking patches whose edge-to-edge distance is at most the maximum gap $d_{\max}$.
Connected components. The graph $G = (\{1,\ldots,n\}, \mathcal{E})$ is partitioned into $C$ connected components $\mathcal{C}_1, \ldots, \mathcal{C}_C$ via depth-first search. Each patch $i$ receives a component label $\ell_i \in \{0, \ldots, C-1\}$.
Binary Probability of Connectivity (PC). Summing over components, the PC index is the probability that two randomly chosen points within the total green area fall in the same component:
$$\text{PC} = \frac{\sum_{c=1}^{C} \left(\sum_{i \in \mathcal{C}_c} a_i\right)^2}{\left(\sum_{i=1}^{n} a_i\right)^2} \tag{1}$$The numerator sums the squared component areas; the denominator is the square of total green area $A^2$. PC ranges from $1/n$ (all $n$ patches isolated and equal-sized) to $1.0$ (fully connected system).
Per-patch importance (dPC). For each patch $i$, compute the PC of the system with patch $i$ (and all its incident edges) removed. The importance of patch $i$ is the percentage decrease in PC:
$$\text{dPC}_i = 100 \cdot \frac{\text{PC} - \text{PC}^{-i}}{\text{PC}} \quad [\%] \tag{2}$$where $\text{PC}^{-i}$ is the PC index computed on the sub-system of $n-1$ patches after removing patch $i$. If PC = 0, dPC$_i = 0$ by definition.
Component-level statistics. For each component $c$, the total area is:
$$A_c = \sum_{i \in \mathcal{C}_c} a_i \tag{3}$$The largest component share is $\max_c A_c / A$, and the number of components $C$ is a direct measure of fragmentation.
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
GREENS | Vector (Polygon) | -- | Green patches. Must be in projected CRS. At least 2 patches; max 400. |
MAX_GAP | Double | 100.0 | Maximum edge-to-edge gap to count patches as linked (map units). This IS the policy parameter -- state it with every result. Run 2-3 values to test robustness. |
OUT_PATCHES | Vector (Polygon) | -- | Patches with connectivity attributes appended. |
OUT_SUMMARY | Vector (table) | -- | One-row connectivity summary. |
6. Output Description
Patch output (OUT_PATCHES):
| Field | Type | Description |
|---|---|---|
comp_id | Integer | Connected component identifier (1-based). Patches in the same component share the same comp_id. |
area_m2 | Double | Patch area (m$^2$). From input geometry. |
comp_m2 | Double | Total area of this patch's component (m$^2$). |
dpc | Double | Patch importance: percent of PC lost if this patch is removed. 0 = no network role. |
Summary output (OUT_SUMMARY):
| Field | Type | Description |
|---|---|---|
metric | String | Metric name |
value | Double | Metric value |
Metrics: Patches, Links, Components, PC index, Largest component (m$^2$), Top patch dPC.
8. Interpretation Guide
8.1 dPC is the protection-priority list
Sort patches by dPC descending. The top-ranked patch is the one whose loss most fragments the green network. The planning surprise -- documented by Saura & Pascual-Hortal in their goshawk study and replicated in countless applications -- is that a small stepping-stone patch often carries the highest dPC. Its hectares understate its role completely. This is the evidence exhibit for protecting a site whose area-based metrics would not flag it as significant.
However, also check the largest component in area terms: its patches may have low individual dPC (removing any one barely moves PC) but the component as a whole is the ecological backbone. Protection priorities should balance individual dPC (keystones) and component membership (backbone).
8.2 PC as scenario currency
Rerun the tool with a candidate intervention (new park, green corridor, pocket park) added to the patches layer. The change in PC quantifies the connectivity gain. Compare interventions:
- New 2-ha park connecting to an existing component → PC gain through added area + added connectivity
- New 0.2-ha stepping stone bridging two large components → PC gain almost entirely through connectivity (the area is trivial, the topological role is enormous)
The stepping stone often wins. This is the argument that saves small parcels from development: not because of their intrinsic habitat value (which may be modest) but because they are the glue holding the green network together.
8.3 The max_gap parameter IS the ecological model
The gap threshold encodes the mobility assumption. 100 m suits pedestrians and sedentary species; 500 m suits birds and mobile mammals. Always state the gap with every result. Run at 2-3 gaps: if the critical-patch list is stable across gaps, the findings are robust to ecological uncertainty; if it flips (entirely different patches at the top for 50 m vs. 500 m), the network assessment is gap-sensitive and both results should be reported.
8.4 Cross-references
- Green Space Access: overlay high-dPC patches on the access coverage map. A patch that is critical for connectivity AND serves high population is the double-win investment.
- Land-Cover Change Analysis: run transition analysis between two land-cover dates and check whether high-dPC patches experienced loss. A dPC top-10 patch that lost area between t1 and t2 is a conservation failure.
- Land-Use Allocation Optimizer: use the dPC field as a constraint (protect top-dPC patches from development allocation).
9. Academic References
Saura, S. & Pascual-Hortal, L. (2007). "A new habitat availability index to integrate connectivity in landscape conservation planning: Comparison with existing indices and application to a case study." Landscape and Urban Planning, 83(2-3), 91-103. DOI: 10.1016/j.landurbplan.2007.03.005 verified
Pascual-Hortal, L. & Saura, S. (2006). "Comparison and development of new graph-based landscape connectivity indices: towards the priorization of habitat patches and corridors for conservation." Landscape Ecology, 21(7), 959-967. DOI: 10.1007/s10980-006-0013-z verified
Taylor, P.D., Fahrig, L., Henein, K. & Merriam, G. (1993). "Connectivity is a vital element of landscape structure." Oikos, 68(3), 571-573. DOI: 10.2307/3544927 verified
Urban, D. & Keitt, T. (2001). "Landscape connectivity: a graph-theoretic perspective." Ecology, 82(5), 1205-1218. DOI: 10.1890/0012-9658(2001)082[1205:LCAGTP]2.0.CO;2 verified
Moilanen, A. & Nieminen, M. (2002). "Simple connectivity measures in spatial ecology." Ecology, 83(4), 1131-1145. DOI: 10.1890/0012-9658(2002)083[1131:SCMISE]2.0.CO;2 verified
Benedict, M.A. & McMahon, E.T. (2006). Green Infrastructure: Linking Landscapes and Communities. Island Press.
Kong, F., Yin, H., Nakagoshi, N. & Zong, Y. (2010). "Urban green space network development for biodiversity conservation." Landscape and Urban Planning, 95(1-2), 16-27. DOI: 10.1016/j.landurbplan.2009.11.001 verified
15. Urban Growth
The Urban Growth group provides the analytical backbone for understanding and projecting urban expansion. Three tools form a logical pipeline: Land-Cover Change Analysis diagnoses the historical pattern of conversion (what became what, at what rate, and whether the transitions are systematic or random); Urban Growth Simulation (CA) projects the spatial pattern of future expansion under specified demand, suitability, and constraint conditions; and Urban Sprawl Metrics quantifies the efficiency and form of that expansion through the SDG 11.3.1 LCRPGR indicator and complementary shape metrics. Together, they answer the three questions every growth-management plan must address: where did growth go (change analysis), where will it go under current trends (simulation), and is the resulting pattern efficient or wasteful (sprawl metrics)?
===ALGORITHM===Land-Cover Change Analysis
Processing ID: planx:landcoverchange
1. Overview
Cross-tabulates two integer-class land-cover rasters cell by cell to produce the standard transition matrix -- the fundamental accounting table of land-change science. For every ordered pair of classes, the matrix reports the number of cells that were class $i$ at time 1 and class $j$ at time 2, plus the corresponding area in hectares (using the cell size of the first raster). The diagonal entries are persistence; off-diagonal entries are conversions. Two output tables are produced: a full transitions table (one row per from-to pair with non-zero count) and a class summary table (per-class area at both dates, persistence, gains, losses, and net change). The log identifies the single largest conversion by cell count -- typically the headline finding of the study.
2. Theoretical Background
2.1 The transition matrix in land-change science
The transition matrix (also called the cross-tabulation matrix, change matrix, or confusion matrix when applied to classification accuracy) is the de facto standard for reporting post-classification land-cover change. Its intellectual foundations lie in discrete-time Markov chain theory, where a transition probability matrix $P$ describes the probability of moving from state $i$ to state $j$ in one time step. In land-change applications, the matrix is typically expressed in area units (cell counts or hectares) rather than probabilities, because land change is not a stationary Markov process and the "probability" interpretation is tenuous over anything but the shortest time intervals.
Pontius, Shusas & McEachern (2004) provided the canonical methodological treatment, demonstrating that the naive interpretation of the largest off-diagonal entry as the "most important change" can be misleading. A large transition from class A to class B may occur simply because A and B are the two largest classes, not because B is systematically targeting A. They introduced the decomposition of total change into quantity change (net) and allocation change (swap), showing that net change can dramatically underestimate total landscape dynamism -- a landscape with zero net forest change may have simultaneously lost forest here and gained it there, a very different ecological story from stability.
2.2 Intensity analysis and systematic transitions
Aldwaik & Pontius (2012) formalised intensity analysis, a hierarchical framework that tests whether observed transition intensities deviate from a uniform null model at three levels: time interval (is the overall rate of change uniform across intervals?), category (does each category gain/lose with uniform intensity?), and transition (does each gaining category target or avoid particular losing categories?). A transition is systematic when the observed intensity significantly exceeds the uniform expectation, implying a structured process (policy, market preference, ecological constraint) rather than random allocation. PlanX does not implement the full intensity analysis framework, but the transition matrix it produces is the input that would feed it.
2.3 Classification error and the noise floor
Every land-cover map contains classification error (typically 5-20% depending on class complexity and sensor resolution). In a transition matrix, classification error manifests as impossible or highly implausible transitions: water to forest, urban to bare soil, forest to water -- transitions that violate the known physical dynamics of the landscape over the study period. The proportion of cells in such transitions provides an estimate of the data's noise floor: real changes should be interpreted against this baseline. Pontius et al. (2004) recommend reporting the persistence-adjusted transition intensities and flagging transitions that are smaller than the estimated classification error.
2.4 Category aggregation effects
Pontius & Malizia (2004) demonstrated that aggregating land-cover categories (e.g. from Level II to Level I in the Anderson classification) systematically reduces total change and net change, but can either increase or decrease swap (location change). This is because transitions between aggregated categories move onto the diagonal (persistence), making the landscape appear more stable than it is. The principle is: always analyse at the finest available categorical resolution, then aggregate for reporting only with an explicit caveat about the hidden within-class dynamics.
3. Mathematical Formulation
Let $L_1$ and $L_2$ be two integer-class rasters of identical dimensions $R \times C$, representing land cover at time 1 and time 2. Let $\mathcal{C} = \{c_1, \ldots, c_K\}$ be the sorted union of class values appearing in either raster, with $K = |\mathcal{C}|$.
Transition matrix. The raw count matrix $\mathbf{M} \in \mathbb{N}^{K \times K}$ is defined element-wise as:
$$M_{a,b} = \left|\left\{(r, c) : L_1[r, c] = c_a \;\land\; L_2[r, c] = c_b \;\land\; \text{valid}(r,c)\right\}\right| \tag{1}$$where $\text{valid}(r,c)$ excludes cells where either raster contains NoData. The corresponding area matrix in hectares is:
$$M^{\text{ha}}_{a,b} = M_{a,b} \cdot \frac{\text{pixel}^2}{10\,000} \tag{2}$$Per-class statistics. For each class $a$:
$$\text{persisted}_a = M_{a,a} \quad \text{(diagonal)} \tag{3}$$ $$\text{lost}_a = \sum_{b \neq a} M_{a,b} = \left(\sum_b M_{a,b}\right) - M_{a,a} \tag{4}$$ $$\text{gained}_a = \sum_{b \neq a} M_{b,a} = \left(\sum_b M_{b,a}\right) - M_{a,a} \tag{5}$$ $$\text{net}_a = \text{gained}_a - \text{lost}_a \tag{6}$$Total change decomposition. The total change $\Delta$ (sum of all off-diagonal cells) can be decomposed as:
$$\Delta = \sum_{a} \text{lost}_a = \sum_{a} \text{gained}_a = \text{Net} + \text{Swap} \tag{7}$$where Net = $\frac{1}{2}\sum_a |\text{net}_a|$ (half the sum of absolute net changes) and Swap = $\Delta - \text{Net}$.
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
RASTER_T1 | Raster (Integer) | -- | Land-cover classification at time 1. Must share extent and cell size with T2. |
RASTER_T2 | Raster (Integer) | -- | Land-cover classification at time 2. Non-integer values are rounded to nearest integer. |
CLASS_NAMES | String | "" (optional) | Class labels: "1=Urban, 2=Forest, 3=Water, ..." for readable output. Unlabelled codes appear as their numeric value. |
OUT_MATRIX | Vector (table) | -- | Transition matrix: one row per non-zero from-to pair. |
OUT_CLASSES | Vector (table) | -- | Class summary: one row per class with gains/losses/net. |
6. Output Description
Transition matrix (OUT_MATRIX):
| Field | Type | Description |
|---|---|---|
from_class | String | Class at time 1 (label or code) |
to_class | String | Class at time 2 (label or code) |
cells | Integer | Number of cells in this transition |
area_ha | Double | Area in hectares (cells x pixel$^2$ / 10000) |
kind | String | "Persistence" (diagonal) or "Conversion" (off-diagonal) |
Class summary (OUT_CLASSES):
| Field | Type | Description |
|---|---|---|
class | String | Class label or code |
t1_ha | Double | Total area at time 1 (ha) |
t2_ha | Double | Total area at time 2 (ha) |
persisted_ha | Double | Area unchanged between dates (ha) |
lost_ha | Double | Area that transitioned away from this class (ha) |
gained_ha | Double | Area that transitioned into this class (ha) |
net_ha | Double | Net change: gained minus lost (ha). Positive = growth; negative = decline. |
8. Interpretation Guide
8.1 Read the biggest off-diagonal cells
The transition matrix tells one story at a time. Sort by area_ha
descending and filter to kind = "Conversion". The top row is the
dominant land conversion -- e.g. "Farmland --> Urban, 412 ha." This single
sentence defines the study's narrative.
8.2 Never report net change alone
A class with near-zero net change can have massive gross changes (large gains AND large losses in different locations). This is spatial displacement -- forest cleared here, planted there -- and it is fundamentally different from stability. Report persistence, loss, and gain alongside net. The class summary table provides all four; quote them.
8.3 Impossible transitions estimate data quality
Scan the transition table for physically implausible conversions: water to forest in 5 years, urban to farmland at scale. The combined area of these transitions, as a percentage of total changed area, is a rough estimate of classification error in your input data. If impossible transitions account for 15% of all change, a real transition of 10% should be treated cautiously -- it may be within the noise floor. For rigorous treatment, use an error matrix (if available) to adjust transition probabilities.
8.4 Cross-references
- Feed the urban class from both rasters to Urban Sprawl Metrics for the SDG 11.3.1 LCRPGR calculation.
- Use the urban class at time 2 as the seed for Urban Growth Simulation (CA) to project future expansion.
- Overlay high-loss classes on the Plan Performance Report to track whether the plan's land-use policies are being observed.
9. Academic References
Pontius, R.G., Shusas, E. & McEachern, M. (2004). "Detecting important categorical land changes while accounting for persistence." Agriculture, Ecosystems & Environment, 101(2-3), 251-268. DOI: 10.1016/j.agee.2003.09.008 verified
Aldwaik, S.Z. & Pontius, R.G. (2012). "Intensity analysis to unify measurements of size and stationarity of land changes by interval, category, and transition." Landscape and Urban Planning, 106(1), 103-114. DOI: 10.1016/j.landurbplan.2012.02.010 verified
Pontius, R.G. & Malizia, N.R. (2004). "Effect of Category Aggregation on Map Comparison." In: Geographic Information Science (GIScience 2004). LNCS 3234, Springer, pp. 251-268. DOI: 10.1007/978-3-540-30231-5_17 verified
Pontius, R.G. & Millones, M. (2011). "Death to Kappa: birth of quantity disagreement and allocation disagreement for accuracy assessment." International Journal of Remote Sensing, 32(15), 4407-4429. DOI: 10.1080/01431161.2011.552923 verified
Alo, C.A. & Pontius, R.G. (2008). "Identifying systematic land-cover transitions using remote sensing and GIS." Environment and Planning B, 35(2), 280-295. DOI: 10.1068/b32091 verified
Comber, A.J. (2008). "The use of correspondence analysis to explore land cover change." Computers, Environment and Urban Systems, 32(4), 259-270. DOI: 10.1016/j.compenvurbsys.2008.03.003 verified
Mertens, B. & Lambin, E.F. (2000). "Land-cover-change trajectories in Southern Cameroon." Annals of the Association of American Geographers, 90(3), 467-494. DOI: 10.1111/0004-5608.00205 verified
===ALGORITHM===Urban Growth Simulation (CA)
Processing ID: planx:growthsim
1. Overview
Simulates the spatial pattern of urban expansion using a constrained cellular automaton (CA) in the tradition of the SLEUTH model (Clarke & Gaydos, 1998). At each growth step, every non-urban, unconstrained cell receives a score:
$$\text{score} = \text{suitability} \cdot (\beta + w \cdot N_{\text{urban}}) + \epsilon$$where $\beta$ is a base term (enabling leapfrog/spontaneous growth in highly suitable but isolated cells), $w$ is a neighbourhood weight (making growth cling to the existing urban fabric -- edge growth), $N_{\text{urban}}$ is the share of the 8 Moore-neighbour cells that are already urban, and $\epsilon \sim U(0, 10^{-9})$ is a deterministic tie-breaking jitter. The top-scoring cells convert to urban until the step's share of the total land demand (in hectares, converted to cell count) is met. Suitability is internally normalised to [0, 1]; constraint cells (water, protected areas) are blocked; NaN cells in the suitability raster never convert. The same inputs plus the same random seed produce the same map every run -- the model is fully deterministic and thus safe for scenario comparison.
2. Theoretical Background
2.1 Cellular automata in urban modelling
Cellular automata divide the landscape into a regular grid of cells, each occupying one of a finite set of states (urban/non-urban in the simplest case). State transitions are governed by rules that depend on the cell's current state and the states of neighbouring cells. The approach was first applied to urban systems by Tobler (1970) in a model of Detroit, and systematised by Couclelis (1985, 1989) who articulated the theoretical justification: cities exhibit emergent macro-scale patterns (segregation, clustering, sprawl) that arise from micro-scale decision rules applied repeatedly over space and time. CA captures this emergence without requiring a top-down optimising agent.
Batty (1997) provided the definitive primer on CA and urban form, arguing that the approach's strength lies not in predictive accuracy but in its ability to generate "possible futures" -- spatially explicit what-if scenarios that make the consequences of policy choices visible. White & Engelen (1993) developed the first operational CA for land-use dynamics in Cincinnati, demonstrating that simple neighbourhood rules could reproduce fractal urban patterns observed in real cities. Clarke & Gaydos (1998) introduced SLEUTH (Slope, Land use, Exclusion, Urban, Transportation, Hillshade), which remains the most widely applied urban CA model with over 100 documented applications worldwide (Chaudhuri & Clarke, 2013).
2.2 The three CA growth archetypes
The PlanX CA uses two of SLEUTH's four growth types, parameterised explicitly:
- Edge (organic) growth -- controlled by $w$, the neighbourhood weight. Cells adjacent to existing urban fabric score higher. This produces contiguous expansion at the urban fringe, the dominant growth mode in most cities. High $w$ discourages leapfrogging.
- Spontaneous (diffusive) growth -- controlled by $\beta$, the base term. Even an isolated cell with zero urban neighbours can convert if its suitability is high enough (score $= \text{suit} \cdot \beta$). This produces leapfrog development -- new urban patches detached from the main fabric. High $\beta$ scatters growth; low $\beta$ (approaching 0) confines all growth to the urban edge.
The two growth types not implemented (road-influenced growth and slope resistance) can be partially encoded through the suitability raster: assign higher suitability near roads and lower suitability on steep slopes.
2.3 Determinism and scenario comparison
A key design choice is full determinism given the random seed. The jitter $\epsilon \sim U(0, 10^{-9})$ is so small that it only breaks ties among cells with identical scores -- the spatial pattern is otherwise determined by suitability and neighbourhood. This means that two runs with the same inputs produce identical outputs, and differences between scenarios (trend vs. plan) are attributable entirely to parameter changes, not to stochastic variation. This property is essential for planning applications: a stochastic model would require Monte Carlo averaging to distinguish scenario effects from run-to-run noise.
3. Mathematical Formulation
Let the study area be an $R \times C$ grid. Define:
- $U \in \{0, 1\}^{R \times C}$ -- urban mask (1 = urban, 0 = non-urban)
- $S \in \mathbb{R}^{R \times C}$ -- raw suitability values (any scale)
- $K \in \{0, 1\}^{R \times C}$ -- constraint mask (1 = blocked, never urban)
Suitability normalisation. The raw suitability is linearly rescaled to [0, 1] using only finite values:
$$S^{\text{norm}}_{r,c} = \frac{S_{r,c} - S_{\min}}{S_{\max} - S_{\min}} \cdot \mathbf{1}[\text{finite}(S_{r,c})] \tag{1}$$where $S_{\min}$ and $S_{\max}$ are the minimum and maximum of all finite suitability values. NaN cells receive $S^{\text{norm}} = 0$.
Neighbourhood urban share. The Moore (8-neighbour) urban share around cell $(r,c)$ is:
$$N_{r,c} = \frac{1}{8} \sum_{dr=-1}^{1} \sum_{dc=-1}^{1} \mathbf{1}[(dr,dc) \neq (0,0)] \cdot U_{r+dr, c+dc} \tag{2}$$Edge cells count fewer neighbours; the divisor remains 8 (missing neighbours are implicitly non-urban).
Transition score. For each non-urban ($U_{r,c}=0$), unconstrained ($K_{r,c}=0$) cell:
$$\text{score}_{r,c} = S^{\text{norm}}_{r,c} \cdot \left(\beta + w \cdot N_{r,c}\right) + \epsilon_{r,c} \tag{3}$$where $\epsilon_{r,c} \sim U(0, 10^{-9})$ is drawn from
numpy.random.default_rng(seed).
Demand allocation. Let $D$ be the total demand in cells, spread evenly (modulo last step) over $T$ iterations. At step $t$, the allotment is $d_t$ cells. The $d_t$ available cells with the highest scores convert to urban:
$$U_{r,c} \leftarrow 1 \quad \text{for the } d_t \text{ cells with largest } \text{score}_{r,c} \tag{4}$$The year-of-conversion raster $Y \in \{-1, 0, 1, \ldots, T\}^{R \times C}$ records the step at which each cell converted (0 = initially urban, $t$ = converted at step $t$, -1 = never urban).
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
SEED | Raster | -- | Seed urban mask (any non-zero, finite value = urban). Typically the urban class from a land-cover map. |
SUITABILITY | Raster | -- | Development suitability. Any numeric scale; normalised internally. From Suitability Lab, MCDA, or a distance-to-roads layer. |
CONSTRAINTS | Raster | -- (optional) | Exclusion zones: any non-zero, finite value = never develop. Water bodies, protected areas, hazard zones, green belt. |
DEMAND_HA | Double | 50.0 | Total land demand in hectares (min 0.01). Converted to cells internally; if demand exceeds available cells, growth saturates with a warning. |
ITERATIONS | Integer | 5 | Number of growth steps (1-100). Demand is split evenly across steps; more steps = finer sequence resolution. |
NEIGH_WEIGHT | Double | 1.0 | Edge-growth pull (0-10). 0 = no neighbourhood effect (allocation by suitability alone). High values make growth cling to existing urban fabric. |
BASE | Double | 0.1 | Leapfrog-growth allowance (0-1). 0 = no spontaneous growth. 0.5+ = substantial scatter. Low base with high suitability cells = planned satellite towns. |
RNG_SEED | Integer | 0 | Seed for tie-breaking jitter only. Same seed = same map every run. |
OUTPUT | Raster | -- | Year-of-conversion raster. 0 = initial urban, 1..T = step converted, NoData = still open at horizon. |
6. Output Description
| Band | Type | Values | Description |
|---|---|---|---|
| Year of conversion | Float32 | -1 (NoData), 0, 1..T | 0 = initially urban (seed). k = converted at growth step k. NoData = never converted (still open land at the horizon). |
Log output per step: number of cells converted and area (ha). Final log: total urban fabric at horizon and net growth.
8. Interpretation Guide
8.1 This is a WHERE model, not a WHEN forecast
The demand parameter sets how much land converts; the model only chooses where. Step numbers encode sequence ("this converts before that"), not calendar years. If you need calendar-year output, calibrate the number of steps to match the time interval between your historical land-cover maps and set demand to the observed historical absorption rate.
8.2 The two growth regimes
Sweep the neighbourhood weight $w$ and base term $\beta$ to explore growth regimes:
- Low $w$ (0-0.5), low $\beta$ (0-0.1): suitability- dominated. Growth goes wherever the suitability raster says, with weak spatial structure. Produces scattered, fragmented patterns. If this matches observed growth, the city has weak planning control.
- High $w$ (1-3), low $\beta$ (0-0.1): edge-dominated. All growth clings to the existing urban fabric. Produces compact, contiguous expansion. The classic "compact city" scenario.
- High $w$ (1-3), moderate $\beta$ (0.3-0.5): mixed. Most growth is contiguous, but particularly suitable sites further out can leapfrog. The most realistic regime for most cities.
8.3 The conflict analysis
The most policy-relevant product of this tool is not the growth map itself but the conflict overlay: intersect the converted cells (year > 0) with farmland, flood zones, planned green wedges, and environmentally sensitive areas. Each conflict is a planning argument: "under current trends, 60 ha of the designated green wedge would be consumed by step 4." This sentence justifies the constraint. Run without constraints (trend) and with constraints (plan) -- the difference map shows exactly what the plan must resist and where displaced growth lands instead.
8.4 Cross-references
- Feed the horizon-year urban mask to Urban Sprawl Metrics to score the scenario's compactness, fragmentation, and SDG 11.3.1 ratio.
- Use Land-Cover Change Analysis on historical data to calibrate the demand rate and check whether the CA's spatial pattern qualitatively matches observed growth.
- Scenario Pipeline (LUTI-lite): embed the CA growth simulation as the land-supply module.
8.5 Pitfalls
- Ignoring the suitability raster's provenance. If the suitability raster is a simple distance-to-roads layer, the model will grow along roads. That is correct behaviour given the input, but it is not a land-use model. Use a multi-criteria suitability (MCDA) from Suitability Lab for defensible projections.
- Ignoring demand calibration. Demand should be tied to population projections and historical land-consumption rates. Arbitrary demand produces arbitrary-looking maps. Run Housing Needs Assessment first, then estimate demand as need x average unit land-take.
- Edge effects. Cells at the raster boundary have fewer neighbours (the Moore neighbourhood is clipped). This produces a slight inward bias at the edge -- growth may avoid the raster boundary. Buffer the study area by a few kilometres if the boundary coincides with the urban fringe.
9. Academic References
Clarke, K.C. & Gaydos, L.J. (1998). "Loose-coupling a cellular automaton model and GIS: long-term urban growth prediction for San Francisco and Washington/Baltimore." International Journal of Geographical Information Science, 12(7), 699-714. DOI: 10.1080/136588198241617 verified
Batty, M. (1997). "Cellular automata and urban form: a primer." Journal of the American Planning Association, 63(2), 266-274. DOI: 10.1080/01944369708975918 verified
White, R. & Engelen, G. (1993). "Cellular automata and fractal urban form: a cellular modelling approach to the evolution of urban land-use patterns." Environment and Planning A, 25(8), 1175-1199. DOI: 10.1068/a251175 verified
Chaudhuri, G. & Clarke, K.C. (2013). "The SLEUTH Land Use Change Model: A Review." International Journal of Environmental Resources Research, 1(1), 88-105.
Jantz, C.A., Goetz, S.J. & Shelley, M.K. (2003). "Using the SLEUTH urban growth model to simulate the impacts of future policy scenarios on urban land use in the Baltimore-Washington metropolitan area." Environment and Planning B, 31(2), 251-271. DOI: 10.1068/b2983 verified
de Almeida, C.M., Batty, M., Monteiro, A.M.V. et al. (2003). "Stochastic cellular automata modeling of urban land use dynamics: empirical development and estimation." Computers, Environment and Urban Systems, 27(5), 481-509. DOI: 10.1016/S0198-9715(02)00042-X verified
Jantz, C.A., Goetz, S.J., Donato, D. & Claggett, P. (2010). "Designing and implementing a regional urban modeling system using the SLEUTH cellular urban model." Computers, Environment and Urban Systems, 34(1), 1-16. DOI: 10.1016/j.compenvurbsys.2009.08.003 verified
===ALGORITHM===Urban Sprawl Metrics
Processing ID: planx:sprawlmetrics
1. Overview
Computes SDG Indicator 11.3.1 -- the ratio of the Land Consumption Rate (LCR) to the Population Growth Rate (PGR) -- plus three complementary shape metrics that characterise the form of urban expansion: patch count (number of separate urban islands in the horizon-year mask), largest-patch share (what fraction of total urban area sits in the single largest contiguous patch), and edge density (metres of urban/non-urban boundary per hectare of urban area). Input is two binary urban-extent rasters (any non-zero = urban) and the corresponding population figures. The LCRPGR ratio is the global standard for monitoring urban land-use efficiency; the shape metrics explain how the land was consumed -- compactly, raggedly, or through leapfrog fragmentation.
2. Theoretical Background
2.1 SDG 11.3.1 -- rationale and interpretation
SDG Target 11.3 calls on countries to "enhance inclusive and sustainable urbanization and capacity for participatory, integrated and sustainable human settlement planning and management." Indicator 11.3.1 operationalises sustainable urbanisation as land-use efficiency: is the city consuming land at a rate commensurate with its population growth? The ratio is designed so that:
- LCRPGR $\approx$ 1.0: land and population grow in step -- the footprint expands, but at the same rate as the people filling it. This is the baseline, not necessarily optimal.
- LCRPGR > 1.0: land consumption outpaces population growth -- the city sprawls. Each additional resident occupies more land on average than before. Common values: 1.5-3.0 for sprawling cities.
- LCRPGR < 1.0: population grows faster than land consumption -- the city densifies. The per-capita land footprint shrinks.
- LCRPGR negative: one component is negative (declining population or shrinking urban extent). Requires case-by-case interpretation.
UN-Habitat (2018) recommends reporting two secondary indicators alongside LCRPGR: (a) built-up area per capita, and (b) total change in built-up area, to prevent misreading a single ratio. Corbane et al. (2017) note that a single LCRPGR value can miss areas where the built-up footprint shrinks due to disaster, de-urbanisation, or reclassification.
2.2 Beyond the ratio: shape matters
The LCRPGR ratio, while internationally standardised, collapses the spatial pattern of growth into a single number. Schwarz (2010) analysed 231 European cities and identified five dimensions of urban form -- density, centrality, compactness, land-use mix, and polycentricity -- none of which is captured by LCRPGR alone. The shape metrics in this tool address the compactness/fragmentation dimension:
- Patch count. Rising patch count at constant total area means growth is fragmenting into detached islands -- the leapfrog pattern. Falling patch count means infill is merging previously separate urban patches.
- Largest-patch share. A high share (0.7+) indicates a monocentric city with a dominant contiguous core. A falling share signals polycentric decentralisation or fragmentation.
- Edge density. High edge density at stable patch count = ragged, dendritic growth along roads. Rising edge density at rising patch count = scattered development, the most infrastructure-expensive pattern.
2.3 Limitations of the indicator
As UN-Habitat's own metadata notes, the LCRPGR ratio has known limitations: (a) it can be unstable when population growth is near zero (the denominator approaches 0); (b) aggregating across cities of different sizes and growth regimes can wash out meaningful patterns; (c) it does not distinguish between greenfield development (consuming agricultural/natural land) and brownfield redevelopment (recycling already-urbanised land). For planning applications, always report the raw LCR and PGR alongside the ratio, and triangulate with the shape metrics.
3. Mathematical Formulation
Let $U_1, U_2 \in \{0, 1\}^{R \times C}$ be binary urban masks at times 1 and 2, and $P_1, P_2$ be the corresponding population totals. Let $\text{pixel}$ be the cell size in map units (metres).
Urban areas. The total urban area at each time, in map units squared:
$$A_t = \left(\sum_{r,c} U_t[r,c]\right) \cdot \text{pixel}^2 \quad \text{for } t \in \{1, 2\} \tag{1}$$Land Consumption Rate (LCR). The annualised rate of urban area change (unitless, typically expressed per annum):
$$\text{LCR} = \frac{\ln(A_2 / A_1)}{y} \tag{2}$$where $y$ is the number of years between the two observation dates (not used in the PlanX implementation, which computes the numerator only -- the user divides by $y$ for the annualised rate).
Population Growth Rate (PGR). Similarly:
$$\text{PGR} = \frac{\ln(P_2 / P_1)}{y} \tag{3}$$LCRPGR ratio (SDG 11.3.1). The core indicator:
$$\text{LCRPGR} = \frac{\text{LCR}}{\text{PGR}} = \frac{\ln(A_2 / A_1)}{\ln(P_2 / P_1)} \tag{4}$$The years $y$ cancel out; the ratio is time-independent. If $A_1 = 0$, $A_2 = 0$, $P_1 = 0$, $P_2 = 0$, or PGR $= 0$, the result is NaN.
Patch metrics (on time-2 mask). Connected components of the urban mask are identified using 4-neighbour (von Neumann) connectivity:
$$\text{n\_patches} = |\mathcal{P}(U_2)| \tag{5}$$where $\mathcal{P}(U_2)$ is the set of connected urban components.
$$\text{largest\_share} = \frac{\max_{p \in \mathcal{P}} |p|}{\sum_{p \in \mathcal{P}} |p|} \tag{6}$$Edge density. The total length of the urban/non-urban boundary (counting each orthogonal adjacency as one pixel width), divided by the total urban area expressed in hectares:
$$\text{edge\_density} = \frac{L_{\text{edge}} \cdot \text{pixel}}{A_2 / 10\,000} \quad [\text{m/ha}] \tag{7}$$where $L_{\text{edge}}$ is the count of cell-face adjacencies where one cell is urban and the other is not (raster edges count as boundary).
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
URBAN_T1 | Raster | -- | Urban extent at time 1 (any non-zero, finite value = urban). |
URBAN_T2 | Raster | -- | Urban extent at time 2. Must share extent and cell size with T1. |
POP_T1 | Double | 100000.0 | Population at time 1 (min 1). Must correspond to the area covered by URBAN_T1. |
POP_T2 | Double | 120000.0 | Population at time 2 (min 1). Must correspond to the area covered by URBAN_T2. |
OUT_SUMMARY | Vector (table) | -- | Metric/value table with LCRPGR and all shape metrics. |
6. Output Description
| Field | Type | Description |
|---|---|---|
metric | String | Metric name |
value | Double | Metric value (null if undefined) |
Metrics (12 rows):
| Metric | Meaning |
|---|---|
| Urban area t1 (ha) | $A_1$ in hectares |
| Urban area t2 (ha) | $A_2$ in hectares |
| Urban growth (pct) | $100 \cdot (A_2/A_1 - 1)$ |
| Population t1 | $P_1$ as entered |
| Population t2 | $P_2$ as entered |
| Population growth (pct) | $100 \cdot (P_2/P_1 - 1)$ |
| Land consumption rate (LCR) | $\ln(A_2/A_1)$ |
| Population growth rate (PGR) | $\ln(P_2/P_1)$ |
| LCRPGR (SDG 11.3.1) | LCR / PGR |
| Urban patches (t2) | Number of separate urban islands |
| Largest patch share | Fraction of total urban area in the largest contiguous patch |
| Edge density (m per ha) | Urban boundary length per hectare of urban area |
8. Interpretation Guide
8.1 LCRPGR thresholds and benchmarks
From UN-Habitat's global monitoring and academic studies:
- 0.0 to 0.5: strong densification. Population grows much faster than the footprint. Typical of rapidly urbanising developing-country cities with high-density informal settlements.
- 0.5 to 1.0: moderate densification. The city is becoming more compact.
- 1.0 to 1.5: moderate sprawl. The per-capita land consumption is rising. Most OECD cities fall in this range.
- 1.5 to 3.0: classic sprawl range. Land consumption at 1.5-3x the rate of population growth. Associated with car-dependent, low-density suburban expansion.
- > 3.0: extreme sprawl or an artefact of near-zero population growth. Check the raw PGR -- if PGR < 0.01, the ratio is meaningless and the raw LCR should be reported instead.
8.2 Always report the components
Never quote LCRPGR alone. Always report: LCRPGR = X, with LCR = Y and PGR = Z, over the period [t1 to t2]. A ratio of 2.0 could mean LCR = 0.04 and PGR = 0.02 (steady sprawl) or LCR = 0.002 and PGR = 0.001 (near-stasis, unstable ratio). The components disambiguate.
8.3 Shape metrics diagnose the cost
The shape metrics explain how the land was consumed and, indirectly, what infrastructure it will cost:
- Falling largest-patch share + rising patch count: the city is leapfrog-fragmenting. Each new patch requires its own road connection, water supply, sewerage, and (if large enough) bus route. This is the most expensive growth pattern per capita.
- Rising edge density at stable patch count: the existing urban patch is growing ragged edges -- dendritic fingers along roads, creating a high ratio of infrastructure length to served population.
- Stable or falling edge density + rising largest-patch share: infill is consolidating the urban fabric. This is the least expensive growth pattern and should show up in falling per-capita infrastructure costs.
8.4 Cross-references
- Urban Growth Simulation (CA): run the CA for each scenario, then run Sprawl Metrics on the horizon-year mask. Compare LCRPGR and shape metrics across scenarios to rank alternatives by form efficiency.
- Land-Cover Change Analysis: the urban class areas at t1 and t2 from the transition matrix should align with the Sprawl Metrics urban area inputs. If they do not, the urban-class definitions differ.
- Scenario Compare (A/B): present the LCRPGR and shape metrics side by side for the trend and plan scenarios.
8.5 Pitfalls
- Urban-extent definition sensitivity. The LCRPGR ratio depends critically on how "urban" is defined. A binary threshold (built-up density > 50%) produces different results than a morphological definition (contiguous built-up area > 20 ha). Always document the urban-extent definition alongside the result.
- Spatial mismatch of population and urban extent. If the population figure covers an administrative boundary that does not match the urban-extent raster's spatial domain, the ratio is invalid. The urban rasters and population figures must refer to the same geographic area.
- Unstable ratio with slow growth. If population growth is 0.5% or less over the observation period, LCRPGR is unreliable. Report the raw LCR and note the instability.
9. Academic References
UN-Habitat (2018). SDG Indicator 11.3.1 Training Module: Land Use Efficiency. United Nations Human Settlement Programme, Nairobi.
Schwarz, N. (2010). "Urban form revisited -- Selecting indicators for characterising European cities." Landscape and Urban Planning, 96(1), 29-47. DOI: 10.1016/j.landurbplan.2010.01.007 verified
Corbane, C., Politis, P., Siragusa, A., Kemper, T. & Pesaresi, M. (2017). LUE User Guide: A tool to calculate the Land Use Efficiency and the SDG 11.3 indicator with the Global Human Settlement Layer. Publications Office of the EU. DOI: 10.2760/212689 verified
Ewing, R. & Hamidi, S. (2014). "Measuring urban sprawl and validating sprawl measures." Landscape and Urban Planning, 125, 16-27.
Angel, S., Parent, J., Civco, D.L. & Blei, A.M. (2011). Making Room for a Planet of Cities. Lincoln Institute of Land Policy.
Melchiorri, M., Pesaresi, M., Florczyk, A.J., Corbane, C. & Kemper, T. (2019). "Principles and Applications of the Global Human Settlement Layer as Baseline for the Land Use Efficiency Indicator." ISPRS International Journal of Geo-Information, 8(2), 96. DOI: 10.3390/ijgi8020096 verified
Schiavina, M., Melchiorri, M., Corbane, C. et al. (2022). "Multi-scale estimation of land use efficiency (SDG 11.3.1) across 25 years using global open and free data." Scientific Data, 9, 394. DOI: 10.1038/s41597-022-01523-4 verified
16. Cycling
The Cycling group assesses the bikeability of the street network through the Level of Traffic Stress (LTS) framework. Two tools form a diagnosis-to-intervention pipeline: Cycling Stress (LTS) classifies every street segment LTS 1-4 based on vehicle speed, lane count, traffic volume (AADT), and cycling infrastructure type, producing the stress map; Low-Stress Connectivity drops all segments above a chosen threshold and finds the connected components (islands) of the remaining all-ages network, identifying the barriers that fragment it. Together, they answer the two foundational cycling-planning questions: how stressful is the network (LTS map), and can people actually get anywhere on the low-stress portion (connectivity islands)?
===ALGORITHM===Cycling Stress (LTS)
Processing ID: planx:cyclingstress
1. Overview
Classifies every street segment into one of four Levels of Traffic Stress (LTS) using a simplified Mekuria/Furth screening rule. The classification depends on three road attributes -- posted speed (km/h), number of travel lanes, and annual average daily traffic (AADT) -- plus a cycling infrastructure type field, which distinguishes three regimes:
- Separated paths (infrastructure =
path): physically separated from motor traffic. Always LTS 1. - Painted bike lanes (infrastructure =
lane): on-street but with a dedicated lane. LTS 2 if speed $\leq$ 50 km/h AND lanes $\leq$ 3; otherwise LTS 3. - Mixed traffic (anything else, or default): sharing the road with motor vehicles. LTS 1-4 based on speed, lanes, and AADT thresholds.
All thresholds are editable as key=value text, so an agency can
re-tune the classifier to its own design standards. Every segment attribute
field is optional -- missing values fall back to user-specified defaults. The
output appends LTS class (1-4), human-readable label, segment length, and the
attribute values actually used (speed_used, lanes_used, aadt_used, infra_used)
for full auditability, plus a length-share summary by LTS class.
2. Theoretical Background
2.1 The four types of cyclists
LTS classification rests on Geller's (2006) taxonomy of cyclist types, derived from survey research in Portland, Oregon:
- "Strong and Fearless" (~1% of population): will ride anywhere, regardless of traffic conditions. These riders are already cycling; infrastructure investment does not change their behaviour.
- "Enthused and Confident" (~7%): comfortable on most streets but prefer dedicated facilities. Will use bike lanes and cycle tracks.
- "Interested but Concerned" (~60%): would like to cycle but are deterred by traffic stress. They will ride only on low-stress routes: quiet streets, protected lanes, separated paths. This is the target demographic for cycling policy -- converting even a fraction of this group from car to bike transforms mode share.
- "No Way No How" (~32%): will not cycle under any circumstances. Not a target for infrastructure investment.
Geller's proportions are city-specific; subsequent studies (Dill & McNeil, 2013) found similar splits with the "interested but concerned" group consistently the largest. The LTS framework maps these four types to stress levels: LTS 1 = children (and the "no way no how" group, if they could be persuaded), LTS 2 = "interested but concerned" adults, LTS 3 = "enthused and confident," LTS 4 = "strong and fearless."
2.2 From Dutch standards to LTS criteria
Mekuria, Furth & Nixon (2012) developed the LTS classification by translating Dutch bikeway design standards (CROW, 2007) into a set of numeric criteria applicable to North American road data. Dutch standards have been proven on a population basis to attract essentially equal male/female shares and high cycling rates across all age groups (Pucher & Buehler, 2008). The LTS criteria encode the Dutch insight that stress is determined by the interaction of speed, volume, number of lanes, and degree of separation:
- At low speeds (30 km/h or less) and low volumes (AADT < 1,000), mixed traffic on two-lane roads can achieve LTS 1 -- the "quiet street" model typical of Dutch woonerven (home zones).
- As speed or volume increases, progressively more separation is required: painted lanes (LTS 2) for moderate-speed two-lane roads, cycle tracks (LTS 1) for any road with speed > 50 km/h or more than 2 lanes.
- Multi-lane arterials with speed > 50 km/h and no cycling infrastructure are LTS 4 -- they are effectively unusable by anyone except the "strong and fearless."
2.3 Weakest-link logic
A fundamental principle of the LTS framework, emphasised by Furth et al. (2016), is that the stress of a route is determined by its most stressful link, not by an average. A 5-km route on LTS 1-2 streets that crosses one LTS 4 intersection is an LTS 4 route for the "interested but concerned" rider. This is why the Low-Stress Connectivity tool matters: it identifies exactly which high-stress segments sever the network. Reducing LTS 4 road-km by 50% sounds impressive; reducing LTS 4 gaps by 50% is what actually grows the cycling network.
2.4 Empirical validation
Mekuria, Furth & Nixon (2012) validated the LTS classification on San Jose, California, finding that only 4.7% of home-to-work trips up to 6 miles were connected at LTS 2, providing a plausible explanation for the city's low cycling mode share. The study demonstrated that a modest slate of 32 miles of strategic improvements (closing LTS 4 gaps) would nearly triple the percentage of connected trips. Furth, Mekuria & Nixon (2016) further refined the classification with specific criteria for crossings (intersections) -- signalised vs. unsignalised, presence of refuge islands, number of lanes to cross -- which the PlanX simplified version does not implement but which the editable rule table brings closer.
3. Mathematical Formulation
Let each segment $i$ have attributes speed $v_i$ (km/h), lane count $l_i$, AADT $a_i$ (vehicles/day), and infrastructure type $t_i \in \{\text{path}, \text{lane}, \text{mixed}\}$.
Default LTS rules. The classification uses a threshold table with the following defaults:
| Rule key | Default value | Meaning |
|---|---|---|
path_lts | 1 | LTS for separated paths |
lane_lts2_speed | 50 | Max speed for lane = LTS 2 |
lane_lts2_lanes | 3 | Max lanes for lane = LTS 2 |
lane_lts_low | 2 | LTS when lane meets criteria |
lane_lts_high | 3 | LTS when lane fails criteria |
mixed_lts1_speed | 30 | Max speed for mixed = LTS 1 |
mixed_lts1_lanes | 2 | Max lanes for mixed = LTS 1 |
mixed_lts1_aadt | 1000 | Max AADT for mixed = LTS 1 |
mixed_lts2_speed | 30 | Max speed for mixed = LTS 2 |
mixed_lts2_lanes | 2 | Max lanes for mixed = LTS 2 |
mixed_lts3_speed | 50 | Max speed for mixed = LTS 3 |
Classification logic. For each segment $i$, the LTS class $L_i \in \{1, 2, 3, 4\}$ is assigned according to the decision tree:
If $t_i$ = "path": $L_i = \text{path\_lts}$ (1)
Else if $t_i$ = "lane":
Else (mixed traffic):
$$L_i = \begin{cases} 1 & \text{if } v_i \leq \text{mixed\_lts1\_speed} \land l_i \leq \text{mixed\_lts1\_lanes} \land a_i < \text{mixed\_lts1\_aadt} \\ 2 & \text{else if } v_i \leq \text{mixed\_lts2\_speed} \land l_i \leq \text{mixed\_lts2\_lanes} \\ 3 & \text{else if } v_i \leq \text{mixed\_lts3\_speed} \\ 4 & \text{otherwise} \end{cases} \tag{2}$$Low-stress share. The share of the network length that is LTS 2 or lower (the "all-ages network" benchmark):
$$\text{Share}_{\text{LTS 1-2}} = \frac{\sum_{i: L_i \leq 2} \ell_i}{\sum_i \ell_i} \tag{3}$$where $\ell_i$ is the segment length in metres.
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | -- | Street network in projected CRS. Should be prepared (nodes at intersections). |
SPEED_FIELD | Field (Numeric) | -- (optional) | Posted speed or prevailing speed (km/h). Missing = default speed. |
LANES_FIELD | Field (Numeric) | -- (optional) | Number of travel lanes (both directions). Missing = default lanes. |
AADT_FIELD | Field (Numeric) | -- (optional) | Annual Average Daily Traffic (vehicles/day). Missing = default AADT. |
INFRA_FIELD | Field (String) | -- (optional) | Cycling infrastructure type: "path", "lane", or anything else (= mixed). Case-insensitive. Missing = default infra. |
DEFAULT_SPEED | Double | 50.0 | Fallback speed when no field or missing value (min 0). |
DEFAULT_LANES | Double | 2.0 | Fallback lane count (min 1). |
DEFAULT_AADT | Double | 0.0 | Fallback AADT (min 0). |
DEFAULT_INFRA | String | "mixed" | Fallback infrastructure type. Must be path/lane/mixed. |
RULES | String | (see table above) | Editable threshold table as key=value pairs. Unknown keys error (to prevent silent misclassification). |
OUTPUT | Vector (Line) | -- | Network segments with LTS attributes. |
SUMMARY | Vector (table) | -- | Length-share summary by LTS class. |
6. Output Description
Segment output (OUTPUT):
| Field | Type | Description |
|---|---|---|
lts | Integer (1-4) | Level of Traffic Stress class |
lts_label | String | Human-readable label ("LTS 1 low stress" ... "LTS 4 high stress") |
length_m | Double | Segment length in metres |
speed_used | Double | Speed value actually used in classification (from field or default) |
lanes_used | Double | Lane count actually used |
aadt_used | Double | AADT value actually used |
infra_used | String | Infrastructure type actually used (lowercased) |
Summary output (SUMMARY):
| Field | Type | Description |
|---|---|---|
lts | Integer | LTS class (1-4) |
label | String | Human-readable label |
length_m | Double | Total segment length in this class |
share_len | Double | Fraction of total network length (0-1) |
segments | Integer | Number of segments in this class |
8. Interpretation Guide
8.1 The four-class stress map
Style the output by LTS class using the international convention:
- LTS 1 (green): separated paths and the quietest streets. Suitable for children. The "all-ages" network.
- LTS 2 (yellow): bike lanes on moderate streets, very quiet shared roads. Suitable for the mainstream adult population. The "interested but concerned" network.
- LTS 3 (orange): bike lanes on faster roads, moderate-speed mixed traffic. Suitable for "enthused and confident" riders only.
- LTS 4 (red): everything else -- fast, busy, or multi-lane roads with no cycling provision. The "strong and fearless" domain.
8.2 Read LTS geographically, not just statistically
An LTS 1-2 network-length share of 70% sounds adequate. But if those LTS 1-2 segments are all local streets severed from each other by LTS 4 arterials every 500 metres, the effective cycling network may serve only trips within a single block. Always pair LTS classification with Low-Stress Connectivity to check whether the low-stress fabric actually forms a connected network.
8.3 Short red gaps in long green corridors
The signature opportunity on an LTS map: a 5-km LTS 1-2 corridor (e.g. a cycle route along a greenway) broken by ONE 200-m LTS 4 segment (e.g. a crossing of a 4-lane arterial without a signal). This 200-m gap blocks the entire corridor. Fixing it -- with a protected crossing, a traffic signal, or a short cycle track -- unlocks 5 km of network for the investment of 200 m of infrastructure. The cost-effectiveness ratio (unlocked low-stress km / new infrastructure km) is the metric that should drive the capital programme.
8.4 Scenario testing
Edit the INFRA_FIELD values in the source data to simulate
proposed interventions:
- Change a segment from "mixed" to "lane" to test a painted bike lane.
- Change from "lane" to "path" to test a protected cycle track.
- Change the speed field (or adjust the rules) to test a 30 km/h zone.
Rerun the classifier and compare the before/after LTS 1-2 share. The LTS 1-2 gained (km) / intervention length (km) ratio is the network-efficiency metric for the intervention.
8.5 Cross-references
- Low-Stress Connectivity: the mandatory companion tool. Run LTS first, then connectivity second.
- Network Centrality: overlay betweenness centrality on the LTS map. High-betweenness, high-LTS segments are the arterial corridors that sever the cycling network -- these are the priority gaps to close.
- Transit Frequency Map: LTS 1-2 access to high-frequency transit stops is the multimodal sweet spot. Map LTS 1-2 segments within 400 m of frequent transit stops.
8.6 Pitfalls
- Default values hide missing data. If 90% of segments use the default speed (50 km/h) because the speed field is empty, the LTS map is essentially a map of infrastructure type only. Report the share of segments using defaults in the output documentation.
- Intersections are not modelled. The simplified rule classifies segments only. A route may be entirely LTS 1-2 on its links but require crossing an unsignalised 6-lane road at an LTS 4 intersection. The Low-Stress Connectivity tool partially addresses this through node-level graph connectivity, but does not classify intersections explicitly.
- AADT data is often noisy or missing. In the default rules, AADT only affects mixed-traffic LTS 1 classification. If AADT data is unreliable, the rule effectively collapses to speed + lanes, which is less discriminating.
9. Academic References
Mekuria, M.C., Furth, P.G. & Nixon, H. (2012). Low-Stress Bicycling and Network Connectivity. Mineta Transportation Institute Report 11-19.
Furth, P.G., Mekuria, M.C. & Nixon, H. (2016). "Network Connectivity for Low-Stress Bicycling." Transportation Research Record, 2587(1), 41-49. DOI: 10.3141/2587-06 verified
Geller, R. (2006). Four Types of Cyclists. Portland Office of Transportation.
Dill, J. & McNeil, N. (2013). "Four Types of Cyclists? Examination of Typology for Better Understanding of Bicycling Behavior and Potential." Transportation Research Record, 2387(1), 129-138. DOI: 10.3141/2387-15 verified
Pucher, J. & Buehler, R. (2008). "Making Cycling Irresistible: Lessons from The Netherlands, Denmark and Germany." Transport Reviews, 28(4), 495-528. DOI: 10.1080/01441640701806612 verified
Winters, M., Davidson, G., Kao, D. & Teschke, K. (2011). "Motivators and deterrents of bicycling: comparing influences on decisions to ride." Transportation, 38, 153-168. DOI: 10.1007/s11116-010-9284-y verified
CROW (2007). Design Manual for Bicycle Traffic. CROW Record 25, Ede, The Netherlands.
NACTO (2014). Urban Bikeway Design Guide, 2nd ed. National Association of City Transportation Officials.
===ALGORITHM===Low-Stress Connectivity
Processing ID: planx:lowstressislands
1. Overview
Finds the connected components ("islands") of the cycling network that remain after dropping all segments whose LTS exceeds a chosen threshold (typically 2 for an all-ages network). The algorithm takes a street network with pre-computed LTS values (from the Cycling Stress tool), removes high-stress segments, and performs a depth-first search on the remaining primal graph to identify connected components. Low-stress segments receive their island ID and the island's total length; high-stress segments are preserved with island ID = 0 so they remain visible as barriers on the map.
Optionally, if origin and destination layers are provided, the summary reports the population share that can reach a destination on the low-stress network: origin points are snapped to the nearest network node, and the population of origins whose node lies in an island that contains at least one destination node is counted. This is the screening answer to "can people access schools/shops/transit at low stress?" using network topology only (no routing, no detour criterion).
2. Theoretical Background
2.1 From stress classification to network connectivity
LTS classification alone does not tell a planner whether the low-stress network is useful. A network can be 80% LTS 1-2 by length yet provide zero connected trips if every LTS 1-2 segment is an isolated cul-de-sac separated from every other by LTS 4 arterials. Mekuria, Furth & Nixon (2012) introduced the concept of low-stress islands -- connected subgraphs of the street network within which cycling at the chosen LTS threshold is possible without encountering a high-stress link. The number, size, and spatial arrangement of islands provide a far more informative picture of network functionality than aggregate stress shares.
2.2 The island count as a connectivity metric
In the limit of a perfectly connected all-ages network, the island count at LTS 2 is 1: every node is reachable from every other at low stress. A city with 50 islands at LTS 2 has, in effect, 50 separate cycling networks that do not connect to each other -- a resident of island A cannot cycle to a destination in island B without encountering a stress level that exceeds their tolerance. The number of islands is a coarse but powerful metric: fewer islands = better connectivity. However, the size distribution matters: one giant island (80% of the network) plus 49 tiny islands (local streets severed by arterials) is very different from 50 equal-sized islands (pervasively fragmented grid).
2.3 Destination reachability as a policy KPI
Furth, Mekuria & Nixon (2016) proposed "percent trips connected" -- the fraction of origin-destination pairs in the regional trip table that are linked by a low-stress path with no excessive detour -- as the gold-standard connectivity metric. Computing this requires a regional trip table and full shortest-path routing on the low-stress subnetwork, which is computationally intensive. The PlanX implementation provides a simpler screening alternative: destination-island reachability. An origin is "served" if its snapped network node lies in an island that contains at least one destination node. This is a binary, non-routed metric: it answers "is there at least one accessible destination?" rather than "can I reach my specific destination?" -- but it requires no trip table and runs in linear time.
2.4 The strategic-gap logic
The most powerful output of the island analysis is the gap map: high-stress segments (island_id = 0) that separate two large low-stress islands. Each such gap is a candidate for a protected crossing, traffic calming, or cycle track that would merge two islands. The population- weighted merge gain -- population of island A + population of island B that would newly be connected -- is the cost-effectiveness metric for gap-closing interventions. In the San Jose case study, Mekuria et al. demonstrated that a strategically chosen 32 miles of gap closures would nearly triple the percentage of connected work trips, from 4.7% to 12.8% -- because each closure merged multiple islands simultaneously.
3. Mathematical Formulation
Let $G = (V, E)$ be the primal street graph with $|V|$ nodes and $|E|$ edges. Each edge $e$ has an LTS class $L_e \in \{1, 2, 3, 4\}$ and length $\ell_e$. For a chosen threshold $\tau \in \{1, 2, 3, 4\}$, define the low-stress edge set:
$$E_{\text{low}} = \{e \in E : L_e \leq \tau\} \tag{1}$$The low-stress subgraph is $G_{\text{low}} = (V, E_{\text{low}})$.
Connected components. A depth-first search on $G_{\text{low}}$ partitions the nodes into $C$ components, assigning each node $v$ a component label $\ell(v) \in \{0, 1, \ldots, C-1\}$. Isolated nodes (degree 0 in $G_{\text{low}}$) each form their own component. Each edge $e = (u, v)$ receives the label of its nodes:
$$\ell(e) = \begin{cases} \ell(u) & \text{if } e \in E_{\text{low}} \text{ and } \ell(u) = \ell(v) \\ -1 & \text{otherwise (high-stress edge or inconsistent)} \end{cases} \tag{2}$$The component length (total low-stress length belonging to component $c$) is:
$$\Lambda_c = \sum_{e \in E_{\text{low}} : \ell(e) = c} \ell_e \tag{3}$$Low-stress share of the network:
$$S_{\text{low}} = \frac{\sum_{e \in E_{\text{low}}} \ell_e}{\sum_{e \in E} \ell_e} \tag{4}$$Destination-island reachability. Let $\mathcal{O} \subset V$ be the set of network nodes nearest to origin features, with associated population $p_v$ per origin. Let $\mathcal{D} \subset V$ be the set of network nodes nearest to destination features. Define the served islands:
$$\mathcal{I}_{\text{served}} = \{\ell(v) : v \in \mathcal{D}, \ell(v) \geq 0\} \tag{5}$$The reachable population is the sum of population at origins whose node lies in a served island:
$$P_{\text{reach}} = \sum_{v \in \mathcal{O} : \ell(v) \in \mathcal{I}_{\text{served}}} p_v \tag{6}$$The population reach share is $P_{\text{reach}} / \sum_{v \in \mathcal{O}} p_v$.
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
NETWORK | Vector (Line) | -- | Street network with LTS field (output of Cycling Stress). Must be in projected CRS. |
LTS_FIELD | Field (Numeric) | -- | LTS class per segment (1-4). Non-numeric values treated as LTS 4 with warning. |
THRESHOLD | Integer | 2 | Maximum LTS for "low-stress" (1-4). 2 = all-ages network; 3 = confident-rider network; 4 = everything (single island). |
ORIGINS | Vector (any geometry) | -- (optional) | Origins with population (e.g. census blocks, buildings). Centroids used for polygon inputs. |
POP_FIELD | Field (Numeric) | -- (optional) | Population per origin feature. Omitted = 1 per origin. |
DESTINATIONS | Vector (any geometry) | -- (optional) | Destinations to test reachability against (e.g. schools, shops, transit stops). |
OUTPUT | Vector (Line) | -- | Network segments with island attributes. |
SUMMARY | Vector (table) | -- | Connectivity summary with optional population-reach KPI. |
6. Output Description
Segment output (OUTPUT):
| Field | Type | Description |
|---|---|---|
lowstress | Integer (0/1) | 1 = segment is at or below the LTS threshold; 0 = high stress (barrier) |
island_id | Integer | Island (component) identifier (1-based). 0 = barrier segment (not part of any island). |
island_m | Double | Total length of this segment's island (metres). Barrier segments get 0. |
(Plus all original network fields including LTS class.)
Summary output (SUMMARY):
| Field | Type | Description |
|---|---|---|
metric | String | Metric name |
value | Double | Metric value |
note | String | Additional information (empty string if none) |
Metrics: Threshold LTS, Segments, Low-stress segments, Low-stress length (m), Network length low-stress share, Low-stress islands, Largest island length (m). Plus (if origins + destinations provided): Destination islands, Population reaching a destination island, Population reach share.
8. Interpretation Guide
8.1 The island map IS the cycling map
The island map tells an honest story that the official "bike network" map
may obscure. Style the output by island_id: each island gets a
distinct colour; barrier segments (island_id = 0) get a thin red line. A map
showing dozens of small coloured islands separated by red barriers -- however
much green paint exists on the ground -- reveals a cycling network that cannot
deliver cross-city trips. A map showing one or two dominant coloured islands
with few red barriers reveals a functional network.
8.2 Barrier segments = the work programme
Select all segments where island_id = 0 AND the segment
separates two large islands (the islands on either side can be identified by
the component labels of the adjacent nodes). Each such segment is a candidate
intervention. Rank them by the combined population (or combined island length)
of the two islands they separate. The top-ranked gap is the single most
consequential missing link in the cycling network -- close it, and the network
merges two large islands into one.
8.3 The population-reach KPI
If origins and destinations were provided, the summary's Population reach share is the headline KPI for cycling-network adequacy. For example: "At LTS 2, 34% of residents can reach a primary school on the low-stress network." Track this KPI across scenarios:
- Base case (current network) → reach share X%.
- After closing gap A (protected crossing on arterial) → reach share Y%.
- After closing gap B (cycle track along corridor) → reach share Z%.
The KPI gain per dollar spent is the evidence base for the cycling capital programme. A single strategic gap closure can jump the reach share by 10-20 percentage points if it merges two large populated islands.
8.4 Island_id = 0 everywhere = broken topology or wrong threshold
If nearly all segments show island_id = 0 (barriers), either:
(a) the LTS threshold is too low (try threshold 3 or 4 to check -- if island_id
still = 0 everywhere, the problem is topology); (b) the network topology is
broken -- segments that visually intersect do not share a node. Run
Prepare Network first and re-classify.
8.5 Cross-references
- Cycling Stress (LTS): the mandatory upstream tool. The LTS field in the network must exist before running Low-Stress Connectivity.
- Service Areas (Isochrones): for an island that contains a destination-rich core, compute the walking catchment of each destination within the island to estimate the "last-mile" walking component of a bike+walk trip.
- Scenario Compare (A/B): present before/after island maps and population-reach KPIs for the current network and the proposed intervention network.
8.6 Pitfalls
- Reachability without routing. The population-reach metric counts origins whose island co-occurs with any destination. It does NOT verify that a path exists from that specific origin to that specific destination within the island (though by definition of a connected component, one does). It also does not check for excessive detour -- an origin and destination in the same large island may be connected by a meandering 8-km route when the straight-line distance is 1 km. The Mekuria/Furth detour criterion (path length $\leq$ 1.25 $\times$ shortest path) is not implemented.
- Population in isolated nodes. An origin snapped to a node that is entirely isolated from the low-stress network (all incident edges are LTS = barrier) forms its own island of size 1. This origin is counted as "not served" unless a destination happens to be snapped to the same node. Check for these cases.
- Threshold sensitivity. The island structure is very sensitive to the threshold choice, especially when many segments are near a boundary (e.g. LTS 2 vs. LTS 3). A speed limit of 31 km/h instead of 30 km/h can flip a segment from LTS 2 to LTS 3, creating or closing a gap. If LTS classification near a boundary is uncertain, run connectivity at both thresholds and report the range.
9. Academic References
Mekuria, M.C., Furth, P.G. & Nixon, H. (2012). Low-Stress Bicycling and Network Connectivity. Mineta Transportation Institute Report 11-19.
Furth, P.G., Mekuria, M.C. & Nixon, H. (2016). "Network Connectivity for Low-Stress Bicycling." Transportation Research Record, 2587(1), 41-49. DOI: 10.3141/2587-06 verified
Dill, J. & McNeil, N. (2013). "Four Types of Cyclists? Examination of Typology for Better Understanding of Bicycling Behavior and Potential." Transportation Research Record, 2387(1), 129-138. DOI: 10.3141/2387-15 verified
Pucher, J. & Buehler, R. (2008). "Making Cycling Irresistible: Lessons from The Netherlands, Denmark and Germany." Transport Reviews, 28(4), 495-528. DOI: 10.1080/01441640701806612 verified
Winters, M., Davidson, G., Kao, D. & Teschke, K. (2011). "Motivators and deterrents of bicycling: comparing influences on decisions to ride." Transportation, 38, 153-168. DOI: 10.1007/s11116-010-9284-y verified
Geller, R. (2006). Four Types of Cyclists. Portland Office of Transportation.
NACTO (2014). Urban Bikeway Design Guide, 2nd ed. National Association of City Transportation Officials.
17. Hazard Screening
The Hazard Screening group provides three hydrologically grounded tools for rapid flood-risk diagnosis without hydrodynamic modelling. Flow Accumulation builds the plumbing: a depression-filled DEM, D8 flow directions, and a topological accumulation grid — the computational backbone for every downstream hydrological analysis. HAND and Inundation normalises the terrain by vertical distance to the nearest drainage, producing a physically meaningful flood-susceptibility index that outperforms raw elevation for screening. Flood Exposure overlays the resulting inundation mask on buildings and population, producing the policy-ready numbers: how many people and buildings sit in harm's way at each depth scenario. All three are screening tools — they rank and locate risk, but do not replace hydraulic modelling for regulatory floodplain certification.
Flow Accumulation
Processing ID: planx:flowaccumulation
· Engine: engine/hydro.py
· Group: Hazard Screening (17)
1. Overview
Produces three foundational hydrological rasters from a digital elevation model (DEM) in a single pass: a depression-filled DEM using the Wang & Liu (2006) priority-flood algorithm, an eight-direction (D8) flow direction grid following Jenson & Domingue (1988), and a topological flow accumulation grid computed via Kahn's algorithm on the directed acyclic graph defined by the D8 directions. Together these three rasters are the computational plumbing for every downstream hydrological tool in PlanX: HAND Index, Flood Exposure, and any future watershed or stream-network analysis.
The algorithm is strictly deterministic: given the same DEM and software version, the output is bit-identical across runs. Ties in D8 direction are broken by a fixed neighbour-visit order (E, SE, S, SW, W, NW, N, NE), which is the standard ESRI convention. The priority-flood depression filler is also deterministic — cells with equal spill elevation drain in the order they enter the priority queue, which is lexicographic by (row, column) after the first tie-break.
2. Theoretical Background
2.1 Evolution of DEM-based flow routing
The problem of extracting drainage networks from gridded elevation data originated in computer vision and quantitative geomorphology. O'Callaghan & Mark (1984) proposed the first operational algorithm: a recursive procedure that routes each cell's flow to its steepest downslope neighbour, accumulating upstream area by summing the contributing cells. Their critical insight was that artificial pits — spurious closed depressions created by interpolation, vegetation, or sensor noise in the DEM — must be filled before routing, because a pit acts as an internal sink that traps flow and breaks the drainage network. They proposed an iterative "flooding" procedure: raise each pit cell to the elevation of its lowest overflow point, repeating until no pits remain.
Jenson & Domingue (1988) systematised this into the now-standard pipeline: (1) fill depressions, (2) assign flow directions on the filled surface using the steepest-descent rule across eight neighbours (the D8 method), and (3) accumulate flow by summing the upstream area of each cell. Their implementation — written for the USGS DEM format — became the template for virtually every commercial and open-source GIS hydrology toolbox, including ArcGIS Spatial Analyst, GRASS r.watershed, TauDEM, and SAGA.
The D8 method's strength is its simplicity: each cell drains to exactly one neighbour, producing a forest of directed trees (a functional graph with no cycles once pits are filled). Its weakness is grid bias: flow is constrained to eight compass directions, which disperses flow unrealistically on planar hillslopes and creates artificial straight-line channel patterns aligned to the grid. Tarboton (1997) proposed the D-infinity (D-inf) method as a remedy: flow direction is a continuous angle computed from the steepest slope across eight triangular facets centred on each cell, and accumulation is apportioned between two downslope neighbours proportionally to angle proximity. D-inf is demonstrably more accurate on hillslopes but doubles the computational bookkeeping. PlanX uses D8 for its screening purpose — the difference between D8 and D-inf matters most at hillslope scale (sub-30 m resolution), and PlanX's hazard tools operate at the city/neighbourhood scale where the eight-direction bias is acceptable given the larger uncertainties in DEM resolution and surface roughness.
2.2 Depression filling: the priority-flood family
The iterative pit-filling algorithm of Jenson & Domingue (1988) requires $O(N^2)$ scans in the worst case (a nested set of depressions). Wang & Liu (2006) introduced the priority-flood algorithm, which processes cells in elevation order using a priority queue — functionally equivalent to running a Dijkstra-like front from the DEM boundaries inward. The time complexity drops to $O(N \log N)$. The algorithm is elegant: push all boundary cells into a min-heap keyed by elevation; pop the lowest cell, and for each unvisited neighbour, set its elevation to $\max(\text{own\_elevation}, \text{spill\_elevation})$ and push it onto the heap. The result is a hydrologically sound surface with no internal sinks, where every cell has a monotonically descending path to a boundary. PlanX implements this algorithm exactly as described in Wang & Liu (2006), with one modification: cells with NaN elevation (outside the valid DEM extent) are permanently excluded rather than pushed from the boundary — this correctly handles non-rectangular study-area masks common in urban analysis.
2.3 Topological accumulation
Once the D8 direction grid is computed on the filled DEM, the flow network forms a directed acyclic graph (DAG) where each cell is a node with at most one outgoing edge. Flow accumulation is the count of upstream cells draining through each cell — equivalent to the size of the subtree rooted at that cell in the drainage forest. The classic recursive algorithm (Jenson & Domingue, 1988) suffers from deep recursion on large DEMs. PlanX uses Kahn's topological sorting algorithm: compute the in-degree of every node (count how many cells drain into it), initialise a queue with all zero-in-degree cells (ridge cells), and process in topological order, adding each cell's accumulation to its single downstream neighbour. The queue-based approach is iterative, avoids recursion-depth limits, and runs in $O(N)$ time after the direction grid is built.
2.4 Assumptions and limitations
- Steepest-descent only. D8 ignores flow divergence — every cell drains entirely to one neighbour. On convex hillslopes this is broadly correct; on planar surfaces (alluvial plains, urban fill) it produces parallel channel artefacts. For city-scale screening, the accumulation pattern at the 1% threshold (the synthetic stream network) is robust to this; cell-by-cell values on flat terrain are not.
- No infiltration or rainfall. Flow accumulation counts upstream area, not discharge. The result is a purely topographic index — it says "water concentrates here if it cannot infiltrate," which is exactly the scenario during an urban cloudburst when impervious surfaces dominate.
- DEM resolution is the effective scale. A 30 m SRTM DEM will not resolve kerb-height flow paths, and accumulation values on a 5 m LiDAR DEM will appear smaller because each cell represents less area. Always state the DEM resolution alongside any accumulation threshold.
- Filled DEM is a model surface, not reality. The filling algorithm raises depressions to their spill elevation. Real karst terrain, underpasses, and closed basins are deliberately erased. The filled-minus-original difference map is therefore a depression inventory — an important diagnostic product in its own right.
3. Mathematical Formulation
D8 slope. For a cell at row $r$, column $c$ with elevation $Z(r,c)$, the slope to neighbour $(r+dr, c+dc)$ is:
$$\text{slope}(dr, dc) = \frac{Z(r,c) - Z(r+dr, c+dc)}{d(dr,dc)} \tag{3}$$where the inter-cell distance $d = 1$ pixel for cardinal neighbours and $d = \sqrt{2}$ for diagonal neighbours. The D8 direction code is the index of the neighbour with the maximum positive slope (steepest descent). If no neighbour is lower, the cell is a flat area or pit (code 0). The direction codes follow the ESRI/ArcGIS convention (powers of 2):
$$D(r,c) = \begin{cases} 1 & \text{East} \\ 2 & \text{Southeast} \\ 4 & \text{South} \\ 8 & \text{Southwest} \\ 16 & \text{West} \\ 32 & \text{Northwest} \\ 64 & \text{North} \\ 128 & \text{Northeast} \\ 0 & \text{Flat / pit (no descent)} \end{cases} \tag{2}$$Depression filling (Wang & Liu, 2006). Let $\Omega$ be the set of valid (finite) DEM cells. Boundary cells $\partial\Omega$ are pushed onto a min-heap $H$ keyed by elevation. While $H$ is not empty, pop the lowest cell $(r,c)$ with elevation $e$. For each unvisited neighbour $(nr, nc)$:
$$F(nr, nc) = \max(Z(nr, nc),\, e) \tag{1}$$The neighbour is marked visited and pushed onto $H$ with key $F(nr,nc)$. The output $F$ is the filled DEM — every cell has a monotonically non-ascending path to a boundary cell.
Kahn accumulation. Let $\text{indeg}[r,c]$ be the number of cells whose D8 direction points to $(r,c)$. Initialise queue $Q$ with all cells where $\text{indeg}[r,c] = 0$ (ridge cells). For each cell $(r,c)$ dequeued, let $(nr,nc)$ be its downstream neighbour (from the D8 code). Then:
$$A(nr, nc) \mathrel{+}= A(r,c) \qquad \text{indeg}[nr,nc] \mathrel{-}= 1$$If $\text{indeg}[nr,nc] = 0$, enqueue $(nr,nc)$. At termination, $A$ holds the number of upstream cells draining through each cell. All cells are initialised with $A = 1$ (each cell contributes its own area).
4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| DEM | Raster | Yes | Single-band digital elevation model in a projected CRS (metres). Resolution 5–30 m for urban analysis; coarser DEMs miss kerb-height flow paths. Must be hydrologically conditioned (no internal NoData islands except at the study-area boundary). |
Where to obtain: SRTM (30 m, global, void-filled versions), ALOS AW3D30 (30 m, better in steep terrain), Copernicus GLO-30, national LiDAR programmes (1–5 m). For urban pluvial flood screening, LiDAR-derived DEMs at 1–5 m resolution are strongly preferred — a 30 m DEM cannot resolve the street/kerb/building microtopography that controls surface flow in cities.
5. Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
DEM | Raster layer | Yes | Input digital elevation model. Must be in a projected CRS with metric units. The tool reads the first band; multi-band rasters are not supported. |
OUTPUT_FILLED | Raster destination | Yes | Depression-filled DEM. Same extent, resolution, and CRS as the input. Cell values are in metres. NaN where the input was NaN (outside the valid mask). |
OUTPUT_DIR | Raster destination | Yes | D8 flow direction raster. Integer codes 1, 2, 4, 8, 16, 32, 64, 128 following the ESRI convention; 0 = flat/pit (no descent); 255 = NoData. Stored as Float32; visualised as a discrete palette. |
OUTPUT_ACCUM | Raster destination | Yes | Flow accumulation raster (upstream cell count). Values span from 1 (ridge cell) to the total cell count of the catchment (basin outlet). Stored as Float32. Always style with a logarithmic scale. |
6. Output Description
| Output | Type | Range | Description |
|---|---|---|---|
| Filled DEM | Float32 raster | Variable (metres) | Hydrologically conditioned DEM with all depressions raised to their spill elevation. Visually near-identical to the original except in pit areas (quarries, karst, underpasses). The difference map (filled minus original) is a pit/depression inventory. |
| D8 Direction | Float32 raster | {0, 1, 2, 4, 8, 16, 32, 64, 128, 255} | Flow direction to the steepest downslope neighbour. Code 0 = flat or pit cell (no valid descent); 255 = NoData. The raster encodes both hydrology (which way water goes) and topology (the drainage forest structure). |
| Flow Accumulation | Float32 raster | [1, N_cells] | Number of upstream cells draining through each cell. A value of 1 means the cell is a ridge (no upstream inflow). Values span orders of magnitude — always use log scale for visualisation. A threshold at the 99th percentile extracts the synthetic stream network. |
7. Symbolic Representation
Style flow accumulation with a pseudocolour renderer using Viridis or Inferno, logarithmic classification with 10–15 classes. The bright branching lines are the flow concentration zones. Overlay the network at 50% opacity on a hillshade of the filled DEM for a combined terrain-and-drainage map. The D8 direction raster should use a discrete palette: assign distinct colours to the eight compass directions (e.g., blues for northward, reds for southward). The filled DEM is typically not mapped on its own; instead, map the difference (filled minus original) with a sequential ramp (Blues) to reveal filled depressions — any cell with a difference above 0.5 m in urban fabric is a candidate pluvial ponding location.
8. Interpretation Guide
8.1 Reading the accumulation raster
Flow accumulation is the primary diagnostic product. The key insight is that urban surface water follows the same topographic paths as natural drainage, regardless of what is built on top. High-accumulation lines that cross streets, parcels, or building footprints are the surface flow paths that activate during a cloudburst — the water finds the historic drainage route whether or not a pipe or channel is present.
- Buildings on high-accumulation lines (top 1% of cells): elevated pluvial flood risk. The building footprint intercepts natural overland flow, and if the building has a basement or ground-floor opening facing upstream, water will enter.
- High-accumulation lines crossing streets: overland flow paths. Culverts and drains at these crossing points are the choke points to inspect first — if they are undersized or blocked, the street becomes a temporary channel.
- Synthetic stream network: threshold accumulation at the top 1% (or a cell-count threshold calibrated to a known stream) to extract a single-pixel-wide drainage network. Compare against mapped blue-line streams — discrepancies reveal either unmapped drainage or DEM artefacts.
- Filled-minus-original DEM: cells with a positive difference are natural or artificial depressions. In urban areas, differences above 0.5 m often correspond to underpasses, basement excavations, detention basins, and quarries — exactly the locations where pluvial water ponds during heavy rain.
8.2 Cross-references to other PlanX tools
- Feed directly into HAND Index: the filled DEM and D8 direction raster are mandatory inputs for the HAND algorithm. Use the same DEM throughout the chain for consistency.
- Overlay with buildings: intersect the synthetic stream network (top 1% accumulation) with building footprints via Building Form Metrics output to flag at-risk structures. A simple spatial join of centroids to a 5 m buffer of the high-accumulation cells is sufficient for screening.
- Combine with Land-Use Allocation Optimizer: use the high-accumulation corridors as a constraint layer — new development should avoid placing buildings on these natural drainage paths. The accumulation raster can be reclassified into a binary "keep free" mask.
- Scenario Pipeline: the filled DEM and accumulation raster are baseline products that do not change between land-use scenarios. Compute them once and reference from each scenario run.
8.3 Pitfalls
- DEM resolution mismatch. A 30 m DEM smoothed by interpolation will underestimate accumulation on narrow urban streets. Use the highest resolution available. If only 30 m data is available, treat accumulation patterns at scales below ~90 m (3 cells) as unreliable.
- Flat terrain. Cities built on alluvial plains or coastal fill have genuinely low relief. The D8 algorithm will produce noisy, grid-aligned flow patterns because elevation differences between neighbours are smaller than the DEM vertical precision (~1 m for SRTM). In these settings, hand-digitised drainage networks from municipal records are more reliable than DEM-derived routing.
- NoData islands. Internal NoData cells (e.g., water bodies masked out of the DEM) create artificial boundaries that the priority-flood algorithm pushes against. Fill internal water bodies with a nominal surface elevation (shoreline level) before running the tool, or they will act as artificial sinks.
9. Academic References
O'Callaghan, J.F. & Mark, D.M. (1984). "The extraction of drainage networks from digital elevation data." Computer Vision, Graphics, and Image Processing, 28(3), 323–344. DOI: 10.1016/S0734-189X(84)80011-0
Jenson, S.K. & Domingue, J.O. (1988). "Extracting topographic structure from digital elevation data for geographic information system analysis." Photogrammetric Engineering and Remote Sensing, 54(11), 1593–1600. journal does not assign DOIs for pre-1990 volumes]
Wang, L. & Liu, H. (2006). "An efficient method for identifying and filling surface depressions in digital elevation models for hydrologic analysis and modelling." International Journal of Geographical Information Science, 20(2), 193–213. DOI: 10.1080/13658810500433453
Tarboton, D.G. (1997). "A new method for the determination of flow directions and upslope areas in grid digital elevation models." Water Resources Research, 33(2), 309–319. DOI: 10.1029/96WR03137
Garbrecht, J. & Martz, L.W. (1997). "The assignment of drainage direction over flat surfaces in raster digital elevation models." Journal of Hydrology, 193(1–4), 204–213. DOI: 10.1016/S0022-1694(96)03138-1
Barnes, R., Lehman, C. & Mulla, D. (2014). "Priority-flood: An optimal depression-filling and watershed-labeling algorithm for digital elevation models." Computers & Geosciences, 62, 117–127. DOI: 10.1016/j.cageo.2013.04.024
===ALGORITHM===HAND and Inundation
Processing ID: planx:handindex
· Engine: engine/hydro.py
· Group: Hazard Screening (17)
1. Overview
Computes the Height Above Nearest Drainage (HAND) index — the vertical distance from each terrain cell to the nearest stream cell along the D8 flow path — and derives a binary bathtub inundation mask for any user-specified water depth. HAND normalises the DEM relative to the drainage network: instead of absolute elevation (which conflates "high mountain" with "flood-safe"), it reports how many metres a cell sits above the stream it drains to. This single number — conceptually the local gravitational potential relative to the drainage — is the most parsimonious topographic predictor of flood exposure available without hydraulic modelling (Renno et al., 2008; Nobre et al., 2011).
The workflow is modular: HAND is computed once from the filled DEM, D8 directions, and a drainage accumulation threshold. The inundation mask is then a trivial raster operation — every cell with HAND at or below the specified depth is flagged as inundated. Run at multiple depths (0.5, 1.0, 2.0, 5.0 m) to produce nested risk bands for exposure analysis without recomputing HAND.
2. Theoretical Background
2.1 Why HAND? The normalisation argument
Raw elevation is a poor flood predictor. A cell at 500 m ASL in a mountain valley may be 2 m above the adjacent river and highly exposed; a cell at 5 m ASL on a coastal plateau 50 m above its nearest stream is flood-safe. HAND solves this by referencing every cell's elevation to its own drainage outlet. The computation is a single downstream trace along the D8 flow path: follow the steepest-descent chain from each cell until a drainage cell is reached (a cell whose upstream accumulation exceeds the user-specified threshold), then subtract elevations:
$$\text{HAND}(c) = Z(c) - Z(d_c)$$where $d_c$ is the first drainage cell encountered downstream from $c$. This is a relative measure — it says "I am X metres above the stream I drain to" — and is therefore comparable across terrain types, geologies, and climates without calibration. HAND naturally captures the hydrological principle that flood risk increases with proximity to the drainage network, but it encodes proximity as a vertical distance (the energy gradient), not a horizontal (Euclidean) one.
2.2 The HAND lineage
HAND emerged from Amazonian hydrology where the challenge was mapping soil-water regimes across vast, ungauged catchments using only SRTM topography (Renno et al., 2008). The authors demonstrated that HAND classes (0–5 m, 5–15 m, etc.) corresponded systematically to water-table depth measured at field sites, validating the method across an 18,000 km² region. Nobre et al. (2011) formalised this into the terrain model used today, demonstrating that HAND class boundaries align with observable soil-moisture transitions and that the classes are transferable across geologies. This validation is the key: HAND is not merely a geometric transform of the DEM — it correlates with measured hydrological variables, giving it physical meaning beyond the elevation data it consumes.
Subsequent work has scaled HAND to continental levels. The National Water Model at NOAA uses CONUS-scale HAND rasters (10 m resolution) for real-time flood inundation mapping (Liu et al., 2018). Zheng et al. (2018) embedded HAND in the GeoFlood workflow, combining it with synthetic rating curves to translate National Water Model discharge forecasts into inundation maps within minutes — a production demonstration that HAND-based screening, while simpler than full 2D hydraulic models, captures the first-order inundation patterns needed for emergency response.
2.3 The bathtub inundation model
The inundation mask produced by PlanX is a bathtub model: every cell with HAND less than or equal to the specified water depth is flagged as wet. This is the simplest possible inundation model — it assumes water rises to a flat surface at the specified depth, with no routing, no volume conservation, no defences, and no dynamic effects. It is not a substitute for a hydraulic model (HEC-RAS, TUFLOW, MIKE FLOOD) and must never be used for regulatory floodplain certification. Its role is screening: rapidly identifying which areas warrant detailed study, ranking candidate development sites by exposure, and producing the exposure curves (population vs. depth) that drive policy conversations about risk tolerance.
The bathtub approach is conservative by design — it will overestimate inundation because real water has volume and cannot fill every disconnected depression simultaneously. This conservatism is appropriate for screening: a site flagged as "potentially exposed" deserves hydraulic investigation; a site flagged as "safe" (HAND well above the scenario depth) is almost certainly so.
2.4 Drainage threshold: the key parameter
The drainage accumulation threshold defines what counts as a "stream" for HAND computation. A threshold of 100 cells means any cell draining an upstream area of at least 100 cells is a drainage cell. The physical analogue is channel initiation: at what upstream area does overland flow concentrate sufficiently to form a recognisable channel? Lower thresholds (10–50 cells) initiate channels in every gully and swale; higher thresholds (500–1000 cells) only mark major streams. The threshold interacts with DEM resolution:
- At 30 m resolution, 100 cells = 9 ha (0.09 km²) — a headwater stream.
- At 5 m resolution, 100 cells = 0.25 ha — a roadside ditch.
- At 1 m resolution, 100 cells = 100 m² — a kerb inlet.
For urban screening at typical resolutions (5–30 m), thresholds of 50–200 cells produce HAND patterns that align with mapped drainage. Always state the threshold, the DEM resolution, and the resulting minimum drainage area in the results — these three numbers define the effective scale of the analysis.
3. Mathematical Formulation
HAND computation. For each terrain cell $c = (r,c)$ on the filled DEM $F$, the algorithm traces the D8 flow path downstream until a drainage cell is reached:
$$d_c = \begin{cases} c & \text{if } \text{accum}(c) \geq \theta \text{ (c is a drainage cell)} \\ d_{c'} & \text{where } c' = \text{downstream}(c) \text{ via D8 direction} \end{cases} \tag{5}$$where $\theta$ is the drainage accumulation threshold. Then:
$$\text{HAND}(r,c) = F(r,c) - F(d_r, d_c) \tag{4}$$The implementation uses path memoisation (dynamic programming): once the drainage cell for a given starting cell is found, every cell on the traced path is assigned the same drainage cell, so each cell is traced at most once. Cycle detection (via a per-path visited set) handles the rare case of D8 direction loops on flat-filled terrain.
Inundation mask. For a given water depth $D$ (metres):
$$I_D(r,c) = \begin{cases} 1 & \text{if } \text{HAND}(r,c) \leq D \text{ and } \text{HAND}(r,c) \geq 0 \\ 0 & \text{otherwise} \end{cases} \tag{3}$$The $\text{HAND} \geq 0$ condition excludes cells where HAND computation failed (coded as −1 in the engine), which occurs when no drainage cell is reachable downstream — typically cells at the DEM boundary that drain outward.
HAND as gravitational potential. Conceptually, HAND is the remaining potential energy of a water parcel at cell $c$ relative to the drainage network. Expressed as a head difference:
$$\Delta h(c) = \text{HAND}(c) = Z(c) - Z_{\text{drainage}}(c) \tag{2}$$Water at $c$ must lose $\Delta h$ metres of elevation to reach the drainage network. This framing connects HAND to the energy-gradient formulation used in hydrological models and explains why HAND correlates with water-table depth: the water table surface is, to first order, a subdued replica of the topography, and HAND measures the local relief above the drainage base level.
Flood depth exceedance curve (post-processing). Given population data $P$ distributed over cells and HAND values $h_c$, the exposed population at depth $D$ is:
$$E_{pop}(D) = \sum_{c:\, h_c \leq D} P_c \tag{1}$$Plotting $D \mapsto E_{pop}(D)$ yields the exposure curve — the single most policy-relevant product of the Hazard Screening group.
4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Filled DEM | Raster | Yes | Output from Flow Accumulation (OUTPUT_FILLED). Must be in the same projected CRS and exactly co-registered (same extent, resolution) as the direction and accumulation rasters. |
| D8 Flow Direction | Raster | Yes | Output from Flow Accumulation (OUTPUT_DIR). D8 codes 1–128; cells with code 0 or 255 are treated as terminal (no downstream neighbour). |
| Flow Accumulation | Raster | Yes | Output from Flow Accumulation (OUTPUT_ACCUM). Used only to threshold drainage cells; the accumulation values are compared to the threshold parameter, not used directly in HAND arithmetic. |
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
DEM | Raster layer | — | Filled DEM (output of Flow Accumulation). Projected CRS required. |
D8_DIR | Raster layer | — | D8 flow direction raster (output of Flow Accumulation). Codes 1–128; 0 = flat, 255 = NoData. Must share extent and resolution with DEM. |
ACCUM | Raster layer | — | Flow accumulation raster (output of Flow Accumulation). Thresholded to define drainage cells. |
THRESHOLD | Double | 100.0 | Drainage accumulation threshold (cell count). Cells with accumulation ≥ threshold are drainage cells. Lower = more drainage channels (finer HAND pattern); higher = only major streams. Scale with DEM resolution: target 0.1–1.0 km² drainage area. |
DEPTH | Double | 1.0 | Inundation depth in metres. Cells with HAND ≤ depth are wet. Run at multiple depths (e.g. 0.5, 1.0, 2.0, 5.0) to build the exposure curve. Depths below the DEM vertical precision (~1 m for SRTM) are indicative only. |
OUTPUT_HAND | Raster destination | — | HAND index raster. Values in metres; 0 = drainage cell itself; NaN = NoData. Computed once, reused for any depth scenario. |
OUTPUT_INUNDATION | Raster destination | — | Binary inundation mask. 1 = wet (HAND ≤ depth); 0 = dry; NaN = NoData. The mask is the input for Flood Exposure. |
6. Output Description
| Output | Type | Range | Description |
|---|---|---|---|
| HAND Index | Float32 raster | 0 to hundreds of metres | Vertical distance (m) from each cell to its nearest downstream drainage cell. 0 = drainage cell (stream bed). Values are always non-negative for valid cells. HAND measures local draining potential — the energy a water parcel must dissipate to reach the channel network. |
| Inundation Mask | Float32 raster | {0, 1} | Binary bathtub inundation at the specified depth. 1 = cell is at or below the water depth above its drainage. The mask is a scenario product, not a return-period flood map — it has no hydrology, no volume constraint, and no defences. |
7. Symbolic Representation
Style HAND with a sequential-diverging pseudocolour ramp (RdYlBu reversed: red for low HAND = high risk, blue for high HAND = safe). Use manual classification at the standard hydrological breaks: 0, 1, 2, 5, 10, 20, 50 m. The 0–1 m band (red) is the active floodplain; the 1–2 m band (orange) is high exposure; above 10 m (blue) is flood-safe for planning purposes. The inundation mask should be a two-class renderer: blue fill at 40% opacity for wet cells, fully transparent for dry cells.
8. Interpretation Guide
8.1 HAND risk bands
| HAND Range | Risk Level | Planning Interpretation |
|---|---|---|
| 0–1 m | Floodplain (by construction) | Cells at or near the drainage elevation. Active channel, bankfull zone, and immediate riparian corridor. Any building here is in the floodplain regardless of mapped flood zones. Action: flag for no-build; if occupied, commission a hydraulic study immediately. |
| 1–2 m | High exposure | Likely inundated in moderate-to-major flood events. Building ground floors may be above the 1-in-100 level, but access routes (streets, underpasses) flood earlier, cutting off egress. Action: require raised finished floor levels; ensure at least one evacuation route stays above 2 m HAND. |
| 2–5 m | Moderate exposure | Inundated only in extreme events. Most development is physically safe, but critical infrastructure (hospitals, emergency centres) here faces residual risk. Action: protect critical facilities with site-specific flood barriers; maintain drainage clearance. |
| 5–10 m | Low exposure | Flood risk is low for riverine flooding. Pluvial (surface-water) flooding from local intense rainfall may still occur in depressions regardless of HAND. Action: check the filled-minus-original depression map for local ponding risk. |
| >10 m | Flood-safe (screening level) | Negligible riverine flood risk. Suitable for any development from a flood-screening perspective. Caveat: coastal, dam-break, and flash-flood hazards are not captured by HAND. |
8.2 Multi-depth inundation analysis
The recommended workflow is to run HAND once, then generate inundation masks at 0.5, 1.0, 2.0, and 5.0 m depths. Feed each mask to Flood Exposure to build the population exposure curve. The shape of this curve is diagnostic:
- Flat then sharp rise: the city sits above the floodplain, but a threshold depth (often 1–2 m) suddenly submerges a large low-lying neighbourhood. The classic "levee-protected" signature — a small increase in flood stage produces a disproportionate jump in exposure.
- Steady, roughly linear rise: development has sprawled uniformly into the floodplain. Every increment of depth claims a roughly constant number of additional buildings. Risk is distributed, not concentrated.
- Explosive at 1–2 m: the city's growth ring sits just above the everyday flood level. Creeping risk — the 1-in-100 event that was once rare may become the 1-in-20 as climate shifts. This is the most dangerous signature because it is invisible in normal conditions.
- Scattered wet cells away from mapped streams: pluvial (runoff) signature, not riverine. The drainage network (under street level, in the stormwater system) is the problem, not the river. Check the filled-minus-original DEM for depressions that coincide with these cells — these are surface ponding locations.
8.3 Cross-references to other PlanX tools
- Feed to Flood Exposure: the inundation mask is the direct input to Flood Exposure for building and population impact assessment.
- Developable Land screening: reclassify HAND into binary (buildable if HAND > 2 m) and use as a constraint layer in Land-Use Allocation Optimizer or Residential Capacity.
- Scenario testing: the HAND raster is valid for all depth scenarios — compute once per study area. The Scenario Pipeline can reference the same HAND raster for multiple land-use scenarios, changing only the population allocation, not the hazard surface.
- Accessibility equity: overlay HAND risk bands with Accessibility Equity outputs — low-income neighbourhoods in the 0–2 m HAND band is a classic environmental-justice finding.
8.4 Pitfalls
- Drainage threshold dominates the result. A threshold that is too high misses the headwater streams that cause flooding at the neighbourhood scale. A threshold that is too low makes every swale a drainage line, producing HAND values near zero everywhere and a meaningless inundation mask. Always calibrate the threshold against a known mapped stream network and state it with the results.
- HAND has no return period. The inundation depth is a bathtub level, not a 1-in-100-year flood. There is no hydrology — no discharge, no rainfall, no routing. HAND cannot tell you the probability of a given depth; it can only tell you what floods if that depth occurs.
- Coastal and tidal flooding. HAND measures vertical distance to the nearest fluvial drainage. It does not capture coastal storm surge, tidal inundation, or sea-level rise — these require a separate coastal model. In coastal cities, HAND is a fluvial-only screening layer.
- DEM artefacts propagate. A DEM with building footprints "burned in" (common in LiDAR DSMs) will route flow around buildings, creating false drainage lines along street centrelines. Use a bare-earth DEM (DTM), not a surface model (DSM), for HAND computation.
9. Academic References
Renno, C.D., Nobre, A.D., Cuartas, L.A., Soares, J.V., Hodnett, M., Tomasella, J. & Waterloo, M.J. (2008). "HAND, a new terrain descriptor using SRTM-DEM: Mapping terra-firme rainforest environments in Amazonia." Remote Sensing of Environment, 112(9), 3469–3481. DOI: 10.1016/j.rse.2008.03.018
Nobre, A.D., Cuartas, L.A., Hodnett, M., Renno, C.D., Rodrigues, G., Silveira, A., Waterloo, M. & Saleska, S. (2011). "Height Above the Nearest Drainage — a hydrologically relevant new terrain model." Journal of Hydrology, 404(1–2), 13–29. DOI: 10.1016/j.jhydrol.2011.03.051
Zheng, X., Maidment, D.R., Tarboton, D.G., Liu, Y.Y. & Passalacqua, P. (2018). "GeoFlood: Large-Scale Flood Inundation Mapping Based on High-Resolution Terrain Analysis." Water Resources Research, 54(12), 10013–10033. DOI: 10.1029/2018WR023457
Liu, Y.Y., Maidment, D.R., Tarboton, D.G., Zheng, X. & Wang, S. (2018). "A CyberGIS Integration and Computation Framework for High-Resolution Continental-Scale Flood Inundation Mapping." Journal of the American Water Resources Association, 54(4), 770–784. DOI: 10.1111/1752-1688.12660
Speckhann, G.A., Borges Chaffe, P.L., Fabris Goerl, R., Miranda de Abreu, J.J. & Altamirano Flores, J.A. (2018). "Flood hazard mapping in Southern Brazil: a combination of flow frequency analysis and the HAND model." International Journal of River Basin Management, 16(1), 87–98. DOI: 10.1080/15715124.2017.1372444
Bates, P.D. & De Roo, A.P.J. (2000). "A simple raster-based model for flood inundation simulation." Journal of Hydrology, 236(1–2), 54–77. DOI: 10.1016/S0022-1694(00)00278-X
===ALGORITHM===Flood Exposure
Processing ID: planx:floodexposure
· Engine: engine/hydro.py
· Group: Hazard Screening (17)
1. Overview
Translates a binary inundation mask raster into policy-ready exposure numbers. Given an inundation mask (from the HAND and Inundation tool or any external source), a building footprint layer, and an optional population-weighted demand point layer, the tool computes: how many buildings are in the flood zone, what percentage of the total building stock that represents, how many people are exposed, and what share of the total population is affected. The output is a single-row summary table — designed to be run once per depth scenario (0.5, 1.0, 2.0, 5.0 m), with the results assembled into an exposure curve outside the tool.
Optionally, the tool annotates demand points with a wet_dry
status field, enabling spatial analysis of which neighbourhoods
and demographic groups bear the exposure, not just how many.
2. Theoretical Background
2.1 Exposure as a distinct concept from hazard
In the standard risk taxonomy (UNISDR, 2015), hazard is the physical phenomenon (the flood water, its depth and extent); exposure is the people and assets located in the hazard zone; and vulnerability is the susceptibility of those assets to damage. PlanX's Flood Exposure tool operates at the exposure layer — it answers the question "what is in the water?" but not "how badly will it be damaged?" The latter requires depth-damage curves (e.g., FEMA HAZUS, JRC global flood depth-damage functions), which are not implemented in PlanX. The output is a count of exposed elements, not a monetary loss estimate.
2.2 The exposure curve as a planning instrument
Running Flood Exposure at multiple depths and plotting the results produces an exposure curve — the cumulative count (or share) of exposed buildings and population as a function of water depth. This curve is a standard tool in flood risk management (Jongman et al., 2012; Apel et al., 2009). Its shape encodes the spatial relationship between development and the floodplain: a convex curve (steep at low depths) means most exposure is in the shallow fringe — relatively easy to protect with low walls, raised floors, or zoning. A concave curve (steep at high depths) means exposure is concentrated in deep-flood zones — the development is genuinely at risk, and retreat or structural protection are the only options.
2.3 Building vs. population exposure
The tool reports both because they carry different policy meanings. Building exposure is a capital stock indicator — it tells the insurance/asset-management story: "310 buildings, representing 14% of the building stock, would be in floodwater at this depth." Population exposure is a human safety indicator — it tells the emergency-management story: "1,240 residents would need evacuation, shelter, and post-event support." A neighbourhood with high building exposure but low population (warehouse district) requires a different policy response than one with high population exposure (dense residential area), even if the flood depth is identical.
2.4 Screening caveats
All caveats that apply to the inundation mask carry forward to the exposure analysis. No flood defences (levees, flood walls, pumps) are modelled. No depth-damage functions are applied (the tool counts exposure, not damage). No temporal dimension is present (a flash flood and a slow-rise river flood with the same depth produce identical results, even though evacuation outcomes are radically different). The tool operates in the same projected CRS as the inundation raster — building centroids and demand points in a different CRS are reprojected automatically by QGIS processing, but coordinate transformation between datums can introduce sub-pixel shifts at the inundation mask boundary.
3. Mathematical Formulation
Building exposure. Given building centroids $\{(x_i, y_i)\}_{i=1}^{N_b}$ and an inundation grid $I$ with geotransform $gt = (x_0, dx, 0, y_0, 0, dy)$ where $dy < 0$:
$$col_i = \left\lfloor \frac{x_i - gt_0}{gt_1} \right\rfloor \qquad row_i = \left\lfloor \frac{y_i - gt_3}{gt_5} \right\rfloor \tag{3}$$ $$N_{\text{exposed}} = \sum_{i=1}^{N_b} \mathbf{1}[0 \leq row_i < R \land 0 \leq col_i < C \land I[row_i, col_i] > 0.5] \tag{2}$$Buildings whose centroid falls outside the raster extent are counted as not exposed (they are in the total but not in the exposed count, so the percentage is conservative).
Population exposure. Given demand points with coordinates $(x_j, y_j)$ and population values $P_j$:
$$P_{\text{exposed}} = \sum_{j=1}^{N_p} P_j \cdot \mathbf{1}[I(row_j, col_j) > 0.5] \tag{1}$$where $(row_j, col_j)$ is computed from the coordinates as above. If no population field is specified, each demand point is counted as 1 person.
The output percentages are:
$$\text{pct\_bld} = 100 \cdot \frac{N_{\text{exposed}}}{N_b} \qquad \text{pct\_pop} = 100 \cdot \frac{P_{\text{exposed}}}{P_{\text{total}}}$$4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Inundation mask | Raster | Yes | Binary raster where values > 0.5 indicate wet cells. From HAND and Inundation output, or any external binary flood mask. Must be in a projected CRS (metric units). |
| Buildings | Vector polygons | No | Building footprints. Centroids are computed internally. At least one of Buildings or Demand Points must be provided. |
| Demand points | Vector (any geometry) | No | Points with optional population attribute. Geometries are converted to centroids. Population field is optional; if omitted, each point counts as 1. |
| Population field | Numeric field (on demand points) | No | If specified, weighted exposure uses this field's values. NULL or non-numeric values are treated as 0. Typically a dasymetrically distributed population estimate. |
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
INUNDATION | Raster layer | — | Binary inundation mask. Any cell value above 0.5 is treated as wet. The raster's CRS is the analysis CRS — other layers are reprojected to match. |
BUILDINGS | Vector layer (Polygon) | (optional) | Building footprints. Exposure is assessed at the centroid. Provide at least one of Buildings or Demand Points. |
DEMAND | Vector layer (Any) | (optional) | Demand/population points. Each feature's centroid is tested against the inundation mask. Without a population field, each point counts as 1 person. |
POP_FIELD | Field (Numeric) | (optional) | Population attribute on the demand layer. NULL and non-numeric values are treated as 0. Negative values are clamped to 0. |
OUTPUT | Table (FeatureSink) | — | One-row summary table with exposure statistics. No geometry. Designed for assembly into multi-depth exposure curves. |
OUT_DEMAND | Vector layer (Point) | (optional) | Copy of the demand points with an appended wet_dry field ("wet" or "dry"). Enables spatial/demographic cross-tabulation of exposure. |
6. Output Description
| Field | Type | Description |
|---|---|---|
exposed_bld | Double | Absolute count of buildings whose centroid falls in a wet cell. Integer-valued but stored as Double for consistency. |
total_bld | Double | Total number of buildings in the input layer. Denominator for pct_bld. |
pct_bld | Double | Percent of building stock exposed: 100 × exposed_bld / total_bld. 0.0 if no buildings layer was provided. |
exposed_pop | Double | Sum of population values for demand points in wet cells. If no population field, equals the count of wet demand points. |
total_pop | Double | Total population sum over all demand points. Denominator for pct_pop. |
pct_pop | Double | Percent of population exposed: 100 × exposed_pop / total_pop. 0.0 if no demand layer was provided. |
Annotated demand points (optional output): appends a single field wet_dry (String) to the demand layer attributes. Values: "wet" if the point's centroid falls in a cell where the inundation mask > 0.5; "dry" otherwise. Points outside the raster extent are "dry".
7. Symbolic Representation
The summary table is a numeric product — visualise it as a bar chart or
exposure curve outside PlanX. In QGIS, the annotated demand points are the
primary map product: style wet_dry as a two-class renderer (blue
circles for "wet", grey for "dry") overlaid on the inundation mask at 30%
opacity. For a multi-depth series, create four copies of the annotated points
(one per depth), style each at a different blue intensity (light blue for
shallow, dark blue for deep), and display side by side in the map layout.
8. Interpretation Guide
8.1 The exposure curve
Run the tool at 0.5, 1.0, 2.0, and 5.0 m depths. Tabulate pct_pop
(and pct_bld) against depth. The resulting curve is the single
most policy-relevant output of the Hazard Screening group:
- Flat-then-sharp rise: the city sits above the floodplain until a threshold depth is crossed. This is common in cities with defined river terraces or levees. The threshold depth is the key number — it tells you at what flood stage your exposure explodes.
- Steady, roughly linear rise: development has sprawled uniformly into the floodplain. Every increment of depth claims additional buildings at a roughly constant rate. Exposure is distributed, not concentrated — structural protection (a levee) would need to be very long.
- Explosive at 1–2 m: the most dangerous signature. Development has occurred just above the normal flood level — the city's growth ring sits at the 1–2 m HAND band. Climate shifts that raise flood frequency will expose this entire ring simultaneously. This is the "creeping risk" pattern that is invisible without the exposure curve.
8.2 Building exposure vs. population exposure
Disagreement between the two percentages is informative:
- pct_bld high, pct_pop low: the flood zone contains non-residential buildings — warehouses, industrial sheds, commercial big-box. The capital-at-risk is high but evacuation demand is low. Focus on property protection (flood-proofing, insurance).
- pct_pop high, pct_bld low: the flood zone contains dense residential buildings (apartment blocks) or the population is concentrated in few structures. Evacuation and shelter planning are the priority.
- Both high: the flood zone is a dense urban neighbourhood. The classic "river runs through town" scenario. Requires the full spectrum of flood-risk management: structural defences, land-use control, early warning, evacuation planning, and insurance.
8.3 Cross-references to other PlanX tools
- Compare existing vs. proposed development: run Flood Exposure on the current building stock, then on the proposed land-use allocation (converted to building centroids). If the proposed scenario has higher pct_bld or pct_pop, the plan is placing more assets in harm's way. This is a single-number test of whether a plan is "risk-informed" as claimed.
- Equity analysis: feed the annotated demand points
(
wet_dryfield) into Demographic Equity Cross-Tabs to test whether low-income or minority populations are disproportionately exposed to flood hazard. The combination of Flood Exposure + Equity Cross-Tabs is the standard environmental-justice screening workflow. - Infrastructure exposure: use the building exposure logic on any point layer — schools, hospitals, fire stations, power substations. Copy the facility layer to the demand input, set the population field to a capacity or occupancy field, and the output tells you how much critical service capacity is exposed. A hospital with 300 beds in the flood zone is a different order of problem than 300 dispersed residents.
- Scenario Pipeline: the exposure summary at each depth is a compact KPI. Include it in the Scenario Compare dashboard to show how different land-use scenarios change exposure at each depth.
8.4 Pitfalls
- Centroid exposure is binary. A large building whose centroid falls just outside the wet zone is counted as "not exposed" even if 80% of its footprint is inundated. Conversely, a building whose centroid is wet by one pixel is fully counted. For refined analysis with large-footprint buildings (warehouses, shopping centres), replace the buildings layer with a regular grid of points (e.g., 5 × 5 m spacing) weighted by building presence.
- Population data quality dominates the result. The inundation mask may be accurate to 5 m LiDAR precision, but if the population data is a 1 km grid disaggregated to points by area-weighting, the exposure count is only as good as the disaggregation. Always report the population data source and resolution alongside the exposure percentages.
- A single row is not a distribution. The summary reports aggregate exposure — it tells you 14% of the population is exposed, not which 14%. Use the annotated demand points output to map the spatial distribution of exposure. Two cities with identical 14% exposure can have radically different spatial patterns (concentrated vs. dispersed), requiring radically different emergency plans.
9. Academic References
Jongman, B., Ward, P.J. & Aerts, J.C.J.H. (2012). "Global exposure to river and coastal flooding: Long term trends and changes." Global Environmental Change, 22(4), 823–835. DOI: 10.1016/j.gloenvcha.2012.07.004
Apel, H., Aronica, G.T., Kreibich, H. & Thieken, A.H. (2009). "Flood risk analyses — how detailed do we need to be?" Natural Hazards, 49(1), 79–98. DOI: 10.1007/s11069-008-9277-8
Merz, B., Kreibich, H., Schwarze, R. & Thieken, A. (2010). "Review article: Assessment of economic flood damage." Natural Hazards and Earth System Sciences, 10(8), 1697–1724. DOI: 10.5194/nhess-10-1697-2010
Bates, P.D. & De Roo, A.P.J. (2000). "A simple raster-based model for flood inundation simulation." Journal of Hydrology, 236(1–2), 54–77. DOI: 10.1016/S0022-1694(00)00278-X
UNISDR (2015). "Sendai Framework for Disaster Risk Reduction 2015–2030." United Nations Office for Disaster Risk Reduction, Geneva. Available at: undrr.org
===ALGORITHM===18. Travel Demand
The Travel Demand group implements the classic four-step transportation model — trip generation, trip distribution (gravity), mode split, and assignment — as three PlanX tools. Trip Generation estimates productions (home-end trips) and attractions (work-end trips) per traffic analysis zone from population and employment using linear rates. Gravity Distribution balances these productions and attractions against network travel costs via a doubly constrained Furness/IPF procedure, producing an OD flow matrix. Mode Split applies a multinomial logit choice model to each OD pair, splitting the total flow into mode-specific shares based on travel time differences and alternative-specific constants.
These are aggregate, zone-based models — they predict trips between zones, not individual traveller choices. They are "screening-quality" in the PlanX sense: correct order of magnitude, structurally sound, and policy-responsive (you can change inputs and see the direction of change correctly), but not calibrated to local surveys unless you supply locally-estimated rates and coefficients. For a calibrated four-step model, use the PlanX outputs as the initial run and calibrate rates, beta, and ASCs against a household travel survey or traffic count using external estimation software.
Trip Generation
Processing ID: planx:tripgeneration
· Engine: engine/demand.py
· Group: Travel Demand (18)
1. Overview
Computes trip productions (trips generated by households) and trip attractions (trips drawn to workplaces) for each traffic analysis zone using simple linear rates on population and employment. This is Step 1 of the four-step travel demand model (Ortuzar & Willumsen, 2011), and in PlanX it is the mandatory input to the Gravity Distribution tool.
The computation is straightforward: for each zone $i$, productions $P_i = \text{pop}_i \times r_P$ and attractions $A_i = \text{jobs}_i \times r_A$, where $r_P$ (trips per capita per day) and $r_A$ (trips per job per day) are user-specified rates. The output is a table retaining all original zone attributes plus the two new numeric columns — ready to chain into Gravity Distribution.
2. Theoretical Background
2.1 The four-step model and trip generation's place in it
The four-step travel demand model was formalised in the 1950s–1960s by transportation planning agencies in the United States (the Chicago Area Transportation Study, 1955–1962, being the canonical first application) and codified in the textbook by Ortuzar & Willumsen (2011). The four steps are: (1) Trip generation — how many trips start and end in each zone; (2) Trip distribution — where those trips go (the OD matrix); (3) Mode split — which transport mode each trip uses; and (4) Assignment — which specific route through the network each trip takes.
Trip generation is the demographic/economic foundation of the model. It asserts that the volume of travel is driven by two fundamental quantities: people (who need to travel from home to activities) and jobs (which draw people to workplaces). Additional trip purposes (education, shopping, leisure) can be modelled by adding more production-attraction pairs, but PlanX provides the simplest population-and-jobs formulation as the screening baseline. For a five-purpose model (home-based work, home-based education, home-based shopping, home-based other, non-home-based), run Trip Generation multiple times with different population/job subsets and rates, then sum across purposes before the gravity step.
2.2 Productions vs. attractions
The distinction between productions and attractions is not merely semantic — it encodes asymmetry in the travel system. Productions are home-end trips: each resident generates a certain number of trips per day (typically 1.5–2.5, including all purposes). Attractions are activity-end trips: each job attracts a certain number of trip-ends (typically 1.5–3.0, reflecting that a workplace receives both employees and visitors/customers). A zone's P/A ratio (productions divided by attractions) is a single-number land-use diagnosis:
- P/A ≫ 1: dormitory zone — many residents, few jobs. The zone exports trips in the morning and imports them in the evening. Commuting flows are outward-heavy in the AM peak.
- P/A ≪ 1: employment core — many jobs, few residents. The zone imports trips in the morning. Classic downtown or business-park signature.
- P/A ≈ 1: balanced zone — jobs and residents in rough equilibrium. Trips may still cross the zone boundary, but net commuting is balanced. The planning ideal for a "complete neighbourhood."
The P/A imbalance across all zones also diagnoses the study area boundary: if total productions exceed total attractions (zones sum to more outbound than inbound trips), the study area exports commuters to zones outside it. This is correct behaviour — you must either expand the study area boundary or add external zones representing the destinations outside. The gravity model's doubly constrained balancing (Step 2) rescales attractions to match productions internally, so the absolute totals are consistent, but the zone-level P/A pattern remains informative.
2.3 Rate calibration
The default rates ($r_P = 1.5$ trips/capita/day, $r_A = 2.0$ trips/job/day) are order-of-magnitude screening values, not calibrated parameters. They produce approximately correct totals for a typical mid-sized city, but the zonal distribution (which zones contribute most trips) is driven entirely by the population and employment data — the rate is a scalar multiplier that does not affect the relative ranking. For consequential analysis:
- Calibrate $r_P$ against a household travel survey: divide total daily trips reported by the survey population.
- Calibrate $r_A$ against employment density and observed trip attractions from the same survey.
- For trip-purpose-specific rates, the ITE Trip Generation Manual provides rates per land-use category (dwelling units, square metres of retail, etc.) — but these require detailed land-use data that PlanX's screening-level tools do not consume.
- Cross-validate: the ratio of total productions to total population across all zones should be in the range 1.2–2.5 for most cities. Values outside this range suggest either a data problem (population undercount) or a rate problem.
2.4 Assumptions and limitations
- Linear rates assume constant trip rates per capita. In reality, trip rates vary with income, household size, car ownership, and age structure. PlanX does not model these socio-demographic dimensions — it uses a single scalar rate per zone. For equity-sensitive trip generation, stratify zones by income or car-ownership categories and apply different rates.
- No trip purpose differentiation. Productions and attractions are total daily trips, not peak-hour, not purpose-specific. For peak-hour analysis (congestion modelling), apply peak-to-daily ratios (typically 0.08–0.12 for the AM peak hour) to the daily totals.
- No internal capture. Trips that both start and end within the same zone (intrazonal trips) are not distinguished. The gravity model excludes the diagonal (i = j) entries, which is correct for interzonal flows but undercounts total trips in zones that are internally walkable.
3. Mathematical Formulation
Trip productions. For zone $i$ with population $\text{pop}_i$ and production rate $r_P$ (trips/capita/day):
$$P_i = \text{pop}_i \cdot r_P \tag{3}$$Trip attractions. For zone $i$ with employment $\text{jobs}_i$ and attraction rate $r_A$ (trips/job/day):
$$A_i = \text{jobs}_i \cdot r_A \tag{2}$$P/A balance ratio (diagnostic):
$$\text{balance}_i = \frac{P_i}{A_i} \quad (\text{undefined if } A_i = 0) \tag{1}$$The $\text{balance}_i$ value is not output as a separate field — it is the ratio of the two output columns — but it is the single most informative diagnostic for land-use planning. Zone maps of balance are standard master-plan exhibits.
4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Zone layer | Vector (Polygon or Point) | Yes | Traffic analysis zones (TAZs). Population and jobs must be attributes. Zones should be mutually exclusive and collectively exhaustive of the study area. |
| Population field | Numeric | Yes | Total population per zone. From census, WorldPop, or a population allocation tool. |
| Jobs field | Numeric | Yes | Total employment per zone. From business registers, census workplace data, or economic models. |
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
ZONES | Vector layer (Polygon/Point) | — | Traffic analysis zone layer with population and employment attributes. |
POP_FIELD | Field (Numeric) | — | Attribute field containing zone population. NULL or non-numeric values are treated as 0. |
JOBS_FIELD | Field (Numeric) | — | Attribute field containing zone employment. NULL or non-numeric values are treated as 0. |
P_RATE | Double | 1.5 | Production rate (trips per capita per day). Typical range: 1.2–2.5. Use 1.5 for screening; calibrate from surveys for operational models. |
A_RATE | Double | 2.0 | Attraction rate (trips per job per day). Typical range: 1.5–3.0. Generally higher than the production rate because jobs attract both workers and visitors. |
OUTPUT | Table (FeatureSink) | — | Zone table with appended production and attraction columns. No geometry is written — the table is designed for direct input to Gravity Distribution. |
6. Output Description
| Field | Type | Description |
|---|---|---|
production | Double | Total daily trip productions for the zone (trips/day). Rounded to 2 decimal places. This column is the Productions input for Gravity Distribution. |
attraction | Double | Total daily trip attractions for the zone (trips/day). Rounded to 2 decimal places. This column is the Attractions input for Gravity Distribution. |
All original zone attributes are preserved. The output table has no geometry — it is an attribute-only table. For mapping, join back to the zone polygon layer using the zone ID.
7. Symbolic Representation
Map the P/A balance ratio (production / attraction) with a diverging colour ramp (RdYlGn or PuOr reversed). A value of 1.0 = balanced (white or grey); above 1.0 = dormitory (blue tones); below 1.0 = employment core (red/orange tones). Use a logarithmic scale centred at 1.0: breakpoints at 0.25, 0.5, 1.0, 2.0, 4.0. The P/A map alone — without any routing — is often the single most powerful exhibit in a land-use plan: it visualises exactly where the imbalance between housing and jobs will generate traffic.
8. Interpretation Guide
8.1 Reading the P/A map
The P/A ratio is a structural diagnosis of the city's spatial economy. A map of P/A by zone tells you:
- Which zones force long commutes. Zones with extreme P/A ratios (above 3 or below 0.3) are fundamentally unbalanced. Their residents or workers must travel to other zones for their daily pattern to complete. The distance between high-P and high-A clusters determines the city's average commute length.
- Where mixed-use development would reduce trip lengths. A zone with P/A = 3.0 (three times as many home-end trips as job-end trips) is a candidate for employment infill. Adding jobs to this zone would absorb some productions locally, shortening commutes.
- Whether the study area boundary is adequate. If total productions substantially exceed total attractions (aggregate P/A > 1.2), the study area is exporting trips — there are jobs outside the boundary absorbing the surplus. Either expand the boundary or add external zones. The gravity model will rescale attractions to match internally, which distorts the spatial pattern if the boundary is too tight.
8.2 Cross-references to other PlanX tools
- Feed directly to Gravity Distribution: the output table
(with
productionandattractioncolumns) is the mandatory input to the next step in the four-step chain. - Scenario comparison: run Trip Generation on the current population/jobs and on a proposed land-use scenario (e.g., a new housing development or a relocated employment centre). The difference in P/A ratios shows how the scenario changes the commuting balance — a housing development in a high-A zone (moving P/A toward 1.0) is functionally mixed-use even if the buildings are single-purpose.
- Long-term planning: feed Population Projection and Allocate Population Growth outputs into Trip Generation to forecast future trip demand. The production column in year 2040 vs. 2025 quantifies the travel growth the transport system must accommodate.
- Land-Use Balance: Trip Generation's P/A ratio is the mobility-side counterpart to Land-Use Balance's per-capita standards. A zone can meet its per-capita open-space standard but still have a P/A ratio of 4.0 — it's a good place to live but a bad place for the transport system.
8.3 Pitfalls
- Rates are scalars — the zonal pattern is in the data. Changing the production rate from 1.5 to 2.0 multiplies every zone's productions by the same factor. The ranking of zones is unchanged. The relative pattern (which zones dominate) is driven entirely by the population and employment spatial distributions. If those data are wrong (e.g., census population assigned to workplace zones), no rate adjustment can fix the pattern.
- Zero-population or zero-jobs zones. A zone with zero population produces zero trips — it will never receive trips in the gravity model (productions are the row totals). A zone with zero jobs attracts zero trips — it will never send trips out after balancing. Zones with both zero pop and zero jobs are inert. Check for data gaps before running.
- The output is daily totals, not peak hour. Transport infrastructure (road capacity, transit frequency) is designed for peak demand. Multiply the daily production by a peak-hour factor (0.08–0.12) before feeding into capacity analysis. PlanX does not apply this factor automatically — do it in post-processing or adjust the rates.
9. Academic References
Ortuzar, J. de D. & Willumsen, L.G. (2011). Modelling Transport. 4th edition. John Wiley & Sons, Chichester. DOI: 10.1002/9781119993308
Ewing, R. & Cervero, R. (2010). "Travel and the Built Environment: A Meta-Analysis." Journal of the American Planning Association, 76(3), 265–294. DOI: 10.1080/01944361003766766
Cervero, R. & Kockelman, K. (1997). "Travel demand and the 3Ds: Density, diversity, and design." Transportation Research Part D: Transport and Environment, 2(3), 199–219. DOI: 10.1016/S1361-9209(97)00009-6
Institute of Transportation Engineers (2017). Trip Generation Manual, 10th edition. ITE, Washington, DC. ISBN: 978-1-933452-90-2 industry manual, no DOI]
Litman, T. (2017). "Evaluating Transportation Land Use Impacts: Considering the Impacts, Benefits and Costs of Different Land Use Development Patterns." Victoria Transport Policy Institute. Available at: vtpi.org/landuse.pdf
===ALGORITHM===Gravity Distribution
Processing ID: planx:gravitymodel
· Engine: engine/demand.py
· Group: Travel Demand (18)
1. Overview
Distributes zonal trip productions and attractions into a full origin–destination flow matrix using a doubly constrained gravity model — the classic spatial interaction model (Wilson, 1967) that forms Step 2 of the four-step travel demand framework. Given trip productions $P_i$, attractions $A_j$, and a travel cost matrix $c_{ij}$ computed over the street network, the algorithm iteratively balances rows and columns via the Furness/IPF (Iterative Proportional Fitting) procedure until convergence or a maximum iteration limit. The deterrence (impedance) function can be exponential $\exp(-\beta c_{ij})$ or power $c_{ij}^{-\beta}$, where the coefficient $\beta$ controls the sensitivity of trip-making to distance.
The output is an OD flow table — a complete matrix of estimated trips between every zone pair — plus optional desire lines for visualisation. The table feeds directly into Mode Split (Step 3).
2. Theoretical Background
2.1 Wilson's entropy-maximising derivation
Alan Wilson's (1967) seminal paper derived the gravity model not as an analogy to Newtonian physics — as earlier formulations had done — but as the most probable spatial distribution of trips consistent with known constraints. Using the method of Lagrange multipliers to maximise the entropy of the trip matrix subject to fixed row totals (productions), fixed column totals (attractions), and a fixed total travel cost (the budget constraint), Wilson showed that the most likely flow $T_{ij}$ from zone $i$ to zone $j$ takes the form:
$$T_{ij} = A_i \cdot O_i \cdot B_j \cdot D_j \cdot \exp(-\beta c_{ij})$$where $A_i$ and $B_j$ are balancing factors (the $r_i$ and $s_j$ in PlanX's notation), $O_i$ are origin totals ($P_i$), $D_j$ are destination totals ($A_j$ in PlanX's convention), and $\beta$ is the Lagrange multiplier associated with the cost constraint — the parameter that controls the distance-decay behaviour. This derivation transformed the gravity model from an empirical analogue into a statistically principled method: the model is the maximum-entropy estimate of the trip matrix, which means it makes the fewest assumptions beyond the constraints you impose.
The doubly constrained model (the one PlanX implements) satisfies both $\sum_j T_{ij} = P_i$ (row totals match productions) and $\sum_i T_{ij} = A_j$ (column totals match attractions). This is the standard model when both productions and attractions are known from trip generation. The singly constrained variant (production-constrained or attraction-constrained) is appropriate when only one set of marginals is known — PlanX does not implement this, but if you set all attractions equal (or scale them to the production total), the doubly constrained algorithm reduces to production-constrained in practice because the column-balancing step has no bite.
2.2 The Furness / IPF balancing algorithm
The doubly constrained model has no closed-form solution — the balancing factors $r_i$ and $s_j$ are interdependent. The Furness (or IPF) algorithm solves this by alternating between row and column scaling:
- Initialise all $s_j = 1$.
- Row balancing: For each row $i$, scale so $\sum_j T_{ij} = P_i$. Set $r_i = P_i / \sum_j (F_{ij} \cdot s_j)$.
- Column balancing: For each column $j$, scale so $\sum_i T_{ij} = A_j$. Set $s_j = A_j / \sum_i (F_{ij} \cdot r_i)$.
- Repeat steps 2–3 until the maximum absolute difference between modelled and target marginals falls below the convergence tolerance.
The algorithm is guaranteed to converge when the deterrence matrix $F_{ij}$ has no zero rows or columns — a condition PlanX enforces by replacing zero deterrence values with a small epsilon and by clamping denominator sums to a minimum value to prevent division by zero.
A practical refinement: before balancing, PlanX rescales the attraction totals to match the production totals (multiplying by $P_{\text{sum}} / A_{\text{sum}}$). This ensures the row and column totals are consistent — the model distributes trips, it does not create or destroy them — and prevents the Furness algorithm from diverging when production and attraction totals differ substantially.
2.3 The deterrence function: exponential vs. power
The choice of deterrence function encodes an assumption about how distance deters travel:
- Exponential: $F(c) = \exp(-\beta c)$. Dominant in person-trip models. The exponential form means each additional unit of cost multiplies the flow by a constant factor $\exp(-\beta)$ — the "memoryless" property. At $\beta = 0.1$, a 10-minute increase in travel time reduces the flow by a factor of $\exp(-1) \approx 0.37$. The exponential function has a thin tail: very long trips are heavily penalised, which matches the empirical observation that most urban trips are short.
- Power: $F(c) = c^{-\beta}$. Common in freight and migration models. The power form has a heavier tail — long-distance flows decay more gradually — consistent with the observation that freight shipments and migration flows span wider distance ranges than person trips. At the same $\beta$, the power function penalises short distances less and long distances more than the exponential — the shapes are fundamentally different, not just scaled versions of each other.
The calibration of $\beta$ is the empirical core of gravity modelling. A $\beta$ that is too low produces a uniform flow matrix where distance barely matters. A $\beta$ that is too high produces a diagonal-dominated matrix where only adjacent zones interact. The standard calibration target is the mean trip length (or mean trip cost): the modelled mean, $\bar{c}_{\text{model}} = \sum_{ij} T_{ij} c_{ij} / \sum_{ij} T_{ij}$, should match the observed mean from a travel survey. PlanX does not calibrate automatically — it applies the $\beta$ you specify — so the practitioner must iterate: run the model, compute $\bar{c}_{\text{model}}$, compare to $\bar{c}_{\text{observed}}$, adjust $\beta$, repeat.
2.4 Assumptions and limitations
- Zonal aggregation bias. The gravity model operates on zone-to-zone flows. The cost between zones is the network distance between their centroids, which assumes every trip in the zone starts and ends at the centroid. For large zones (above ~1 km² in urban areas), this introduces aggregation error — the intra-zonal cost (which is not modelled, since the diagonal is excluded) can be larger than some inter-zonal costs.
- No competition effects. The gravity model allocates trips to destinations based on attraction mass and cost only. It does not account for intervening opportunities — the principle that a traveller heading toward a distant destination may stop at a nearer one. The intervening-opportunities model (Stouffer, 1940; Schneider, 1959) addresses this but is not implemented in PlanX.
- Cost matrix is static. The network cost matrix is computed once for all zone pairs. The model does not account for congestion (travel time increases with flow), which is the domain of equilibrium assignment (Step 4, not implemented in PlanX). For uncongested networks (most non-motorway urban streets at daily, not peak-hour, resolution), this is acceptable.
3. Mathematical Formulation
Deterrence matrix. Given the cost $c_{ij}$ between zone $i$ and zone $j$, computed as the shortest-path network distance (or a user-specified cost field) between zone centroids:
$$F_{ij} = \begin{cases} \exp(-\beta \cdot c_{ij}) & \text{(exponential deterrence)} \\ c_{ij}^{-\beta} & \text{(power deterrence, with } c_{ij} \text{ clamped to } \geq 10^{-6}) \end{cases} \tag{5}$$Doubly constrained gravity model. The balanced flow matrix $T$ satisfies two sets of marginal constraints:
$$\sum_{j} T_{ij} = P_i \quad \forall i \qquad \sum_{i} T_{ij} = A'_j \quad \forall j \tag{4}$$where $A'_j = A_j \cdot (P_{\text{sum}} / A_{\text{sum}})$ is the rescaled attraction vector ensuring $\sum P = \sum A'$. The flow from $i$ to $j$ at iteration $k$ is:
$$T_{ij}^{(k)} = r_i^{(k)} \cdot F_{ij} \cdot s_j^{(k)} \tag{3}$$where the balancing factors are updated alternately:
$$r_i^{(k)} = \frac{P_i}{\sum_{j} F_{ij} \cdot s_j^{(k-1)}} \qquad s_j^{(k)} = \frac{A'_j}{\sum_{i} F_{ij} \cdot r_i^{(k)}} \tag{2}$$with initialisation $s_j^{(0)} = 1$ for all $j$. The algorithm terminates when:
$$\max\left( \max_i \left|\sum_j T_{ij} - P_i\right|,\; \max_j \left|\sum_i T_{ij} - A'_j\right| \right) < \tau \tag{1}$$where $\tau$ is the convergence tolerance (default $10^{-4}$), or when the
iteration count exceeds MAX_ITER.
4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Zone layer | Vector (Polygon/Point) | Yes | Traffic analysis zones with ID, production, and attraction fields. Typically the output of Trip Generation, or any polygon/point layer with these attributes. |
| Street network | Vector lines | Yes | Road centreline network. Must be in a projected CRS (metres). Prepared network from Prepare Network is recommended for correct intersection topology. |
| Cost field | Numeric field | No | If empty, cost is geometric length. Use for time-based impedance — the same cost field used in OD Cost Matrix should be used here for consistency. |
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
ZONES | Vector layer (Polygon/Point) | — | Zone layer with production, attraction, and ID fields. Centroid coordinates are used for cost computation. |
ZONE_ID | Field | — | Field uniquely identifying each zone. Used in the output as origin_id and dest_id. |
PRODUCTION_FIELD | Field (Numeric) | — | Field containing trip productions (from Trip Generation). Row totals are matched to these values. |
ATTRACTION_FIELD | Field (Numeric) | — | Field containing trip attractions (from Trip Generation). Column totals are balanced to these values after rescaling to match the production total. |
NETWORK | Vector layer (Line) | — | Street network. Centroids snap to nearest nodes. Must be in a projected CRS. |
COST_FIELD | Field (Numeric) | (optional) | Per-segment cost attribute. If empty, geometric length is used. Use travel time (minutes) for time-based impedance. |
BETA | Double | 0.1 | Deterrence (impedance) coefficient. Higher beta = shorter trips dominate. Calibrate by matching modelled mean trip cost to observed. Typical range: 0.02–0.30 for exponential with distance in metres; 0.05–0.20 for minutes. Run with 2–3 beta values to assess sensitivity. |
KIND | Enum | Exponential | Deterrence function: Exponential ($\exp(-\beta c)$) or Power ($c^{-\beta}$). Exponential is standard for person trips; power is common for freight and migration. |
MAX_ITER | Integer | 100 | Maximum Furness/IPF balancing iterations. 100 is adequate for most problems; convergence is typically reached in 10–50 iterations. |
TOL | Double | $10^{-4}$ | Convergence tolerance: the maximum absolute difference between modelled and target marginals. Reducing below $10^{-6}$ rarely changes flows meaningfully but increases iterations. |
OUTPUT | Table (FeatureSink) | — | OD flow table. One row per non-zero zone pair (excluding the diagonal). No geometry. |
LINES | Vector layer (Line) | (optional) | Straight desire lines between zone centroids, styled by flow magnitude. |
6. Output Description
| Field | Type | Description |
|---|---|---|
origin_id | String | Zone identifier for the trip origin (from the zone ID field). |
dest_id | String | Zone identifier for the trip destination. |
cost | Double | Shortest-path network cost between the two zone centroids (metres or cost-field units). The impedance that the travel demand responds to. |
flow | Double | Estimated daily trips from origin to destination after doubly constrained balancing. The core output of the model. Flows below the convergence tolerance are clipped to 0. |
The tool also logs the top 10 flows by magnitude to the QGIS Processing feedback panel, enabling immediate inspection of the dominant corridors. The Furness balancing statistics (iterations run, final maximum error) are also logged.
7. Symbolic Representation
Map the desire lines (LINES output) by flow
with a sequential ramp (Viridis or Plasma) and natural-breaks classification
(5–7 classes). Line width proportional to the square root of flow (to
de-emphasise the extreme top flows). Set opacity to 30–40% so overlapping
bundles create visually denser corridors. Alternatively, filter to the top
20 flows by magnitude — these are the structural corridors that the land-use
pattern imposes on the transport system. Show these with a thicker stroke
(0.8 mm) in a warm colour (red/orange) against a thin grey network background.
8. Interpretation Guide
8.1 Reading the flow table
- Top 10 flows: the dominant corridors in the study area. These are the OD pairs where land-use mass and proximity combine to produce the highest trip volumes. They are the structural demand corridors — even modest changes to land-use or transport will not alter the fact that most trips flow along these axes. This is where transport capacity is least negotiable.
- Flow asymmetry: compare $T_{ij}$ to $T_{ji}$ for each pair. Large asymmetry (e.g., $T_{AB} \gg T_{BA}$) means zone A sends many more trips to B than B sends to A — a net commuting flow. The direction of asymmetry reverses between AM and PM peaks, but the magnitude of asymmetry is stable across the day. Zones with large net outflows are dormitory; zones with large net inflows are employment centres.
- Beta sensitivity: run the model at $\beta = 0.05, 0.10, 0.20$ and compare the flow patterns. At low beta, long-distance flows are inflated — the model predicts more cross-city commuting than the network would sustain. At high beta, most flows are short — the model predicts a city of isolated neighbourhoods. The range of $\beta$ values that produce physically plausible mean trip costs defines the model's "credible region."
8.2 Scenario differencing
The gravity model's primary policy use is scenario comparison: run it once on the base land-use (current population and jobs), once on a proposed plan (new housing here, new employment there). Then difference the two flow tables:
$$\Delta T_{ij} = T_{ij}^{\text{plan}} - T_{ij}^{\text{base}}$$OD pairs with large positive $\Delta T$ are corridors under growth pressure — the plan adds trips to these routes. Pairs with large negative $\Delta T$ are corridors where the plan relieves pressure (e.g., by adding jobs near housing). The top 10 positive $\Delta T$ pairs are the corridors where the plan implicitly orders increased transport capacity — if no capacity increase is planned for those corridors, the plan and the transport system are in conflict.
8.3 Cross-references to other PlanX tools
- Feed to Mode Split: the OD flow table is the mandatory input for Step 3. Join it with mode-specific travel time matrices to split the flow into mode shares.
- OD Cost Matrix validation: check whether the gravity model's top corridors align with the observed desire lines from the OD Cost Matrix. Disagreement between modelled (gravity) and observed (survey/mobile data) flows at the top corridors is a calibration signal — adjust $\beta$.
- Transit Access overlay: overlay the gravity model's top 10 corridors on the Transit Travel-Time Access output. A corridor with high modelled flow but poor transit access is the strongest case for a new transit route. The gravity model says "demand is here"; transit access says "supply is poor"; the gap is the opportunity.
- Link Criticality calibration: use the gravity model's OD demand as the input demand set for Link Criticality, replacing simple population-to-facility demand. The criticality ranking then reflects the modelled travel demand pattern, not just proximity.
8.4 Pitfalls
- Intrazonal trips are excluded. The diagonal ($i = j$) is skipped. Trips that both start and end within the same zone are not modelled. For large zones, this can omit a significant share of total trips. Subdivide zones until the intrazonal share is below 15% of total productions.
- Centroid-to-centroid cost. The cost between two zones is the shortest-path distance between their centroids, which snaps to the nearest network node. For irregularly shaped zones, the centroid may be far from the population-weighted centre. Where possible, use population-weighted centroids rather than geometric centroids.
- Non-convergence. If the Furness algorithm reaches MAX_ITER without converging, it means the deterrence matrix has structural zeros — some zone pairs are unreachable within the network (e.g., zones separated by a river with no bridge). The algorithm cannot balance because no amount of scaling can route flow through a zero-deterrence pair. Check the cost matrix for infinite values and add network connections or consolidate zones.
9. Academic References
Wilson, A.G. (1967). "A statistical theory of spatial distribution models." Transportation Research, 1(3), 253–269. DOI: 10.1016/0041-1647(67)90035-4
Fotheringham, A.S. & O'Kelly, M.E. (1989). Spatial Interaction Models: Formulations and Applications. Kluwer Academic Publishers, Dordrecht. ISBN: 0-7923-0021-1 book, no DOI assigned]
Ortuzar, J. de D. & Willumsen, L.G. (2011). Modelling Transport. 4th edition. John Wiley & Sons, Chichester. DOI: 10.1002/9781119993308
Evans, A.W. (1971). "The calibration of trip distribution models with exponential or similar cost functions." Transportation Research, 5(1), 15–38. DOI: 10.1016/0041-1647(71)90027-X
Sen, A. & Smith, T.E. (1995). Gravity Models of Spatial Interaction Behavior. Springer-Verlag, Berlin. DOI: 10.1007/978-3-642-79880-1
Erlander, S. & Stewart, N.F. (1990). The Gravity Model in Transportation Analysis: Theory and Extensions. VSP, Utrecht. ISBN: 90-6764-125-6 book, no DOI assigned]
Stouffer, S.A. (1940). "Intervening Opportunities: A Theory Relating Mobility and Distance." American Sociological Review, 5(6), 845–867. DOI: 10.2307/2084520
===ALGORITHM===Mode Split
Processing ID: planx:modesplit
· Engine: engine/demand.py
· Group: Travel Demand (18)
1. Overview
Applies a multinomial logit (MNL) mode choice model (McFadden, 1974) to each origin–destination pair, splitting the total OD flow into mode-specific shares and flows based on per-mode travel times, utility coefficients (betas), and alternative-specific constants (ASCs). This is Step 3 of the four-step travel demand model.
For each OD pair, the model computes the systematic utility $V_{k} = \text{ASC}_k + \beta_k \cdot t_{k}$ for each mode $k$ (where $t_k$ is the travel time for mode $k$ on that OD pair), exponentiates to obtain $\exp(V_k)$, and normalises by the sum of exponentials across modes to obtain the choice probability. The probabilities are then multiplied by the total OD flow to get mode-specific flows. Log-sum-exp stabilisation (subtracting the maximum utility before exponentiation) prevents floating-point overflow on pairs with large time differences.
2. Theoretical Background
2.1 Random utility theory and the logit model
Discrete choice models rest on random utility theory (Manski, 1977; Ben-Akiva & Lerman, 1985): a decision-maker $n$ facing a set of alternatives $\mathcal{C}$ chooses alternative $k$ if and only if $U_{nk} > U_{nj}$ for all $j \neq k$, where the utility of each alternative is decomposed into a systematic (observable) component $V_{nk}$ and a random (unobservable) component $\varepsilon_{nk}$:
$$U_{nk} = V_{nk} + \varepsilon_{nk}$$In PlanX's implementation, the systematic utility is a simple linear-in-parameters function of travel time:
$$V_{nk} = \text{ASC}_k + \beta_k \cdot t_{nk}$$where $\text{ASC}_k$ is the alternative-specific constant — the average effect of all factors not captured by travel time (comfort, reliability, cost, prestige, habit) — and $\beta_k$ is the marginal utility of travel time for mode $k$ (typically negative: more time = less utility = lower choice probability).
When the random terms $\varepsilon$ are independently and identically distributed following the Type I Extreme Value (Gumbel) distribution, the probability that alternative $k$ is chosen takes the closed-form multinomial logit expression (McFadden, 1974):
$$P_k = \frac{\exp(V_k)}{\sum_{m} \exp(V_m)}$$The Gumbel assumption implies the independence of irrelevant alternatives (IIA) property: the ratio of choice probabilities between any two alternatives is independent of the presence or characteristics of other alternatives. This is the logit model's most famous limitation — the classic "red bus / blue bus" paradox (adding a blue bus identical to an existing red bus should halve the red bus's share, not the car's; but logit predicts proportional draw-down from all modes). For screening applications with clearly distinct modes (car, transit, walk, cycle), IIA is acceptable; for operational models with correlated alternatives, a nested logit or mixed logit specification is needed.
2.2 The three parameters per mode
Each mode requires three parameters, and their interpretation is critical to correct use:
- Travel time ($t_k$, per OD pair): the cost (in minutes) of travelling from origin to destination by mode $k$. This is the only policy-sensitive variable in the screening model — you change the times, the model changes the shares. Times come from the street network (for car, walk, cycle) or from an external transit model (for bus, rail). PlanX's Mode Split tool accepts time fields from any source — the OD flows layer must contain one time column per mode.
- Time coefficient ($\beta_k$, per mode): the marginal disutility of one additional minute of travel time. Typically in the range $-0.05$ to $-0.15$ for commuting trips (Train, 2009). A $\beta$ of $-0.10$ means each additional 10 minutes of travel time reduces the odds of choosing that mode by a factor of $\exp(-0.10 \times 10) = \exp(-1) = 0.37$. The coefficient can vary by mode (e.g., time spent walking is generally perceived as more onerous than time spent in a vehicle), but for screening with identical betas across modes, the time differences between modes drive the result.
- Alternative-specific constant ($\text{ASC}_k$, per mode): the baseline preference for mode $k$ when all measured attributes are zero. The ASC is conventionally normalised to zero for one mode (the reference alternative), and the other ASCs are interpreted relative to it. An ASC of 2.0 for car relative to transit (set at 0) means that, at equal travel times, the car is $\exp(2.0) \approx 7.4$ times more likely to be chosen — capturing the value of comfort, flexibility, and loading/unloading time. ASCs are identified relative to a reference alternative; adding a constant to all ASCs does not change the model. Without survey-based estimation, ASCs should be adjusted until the aggregate mode shares match observed city-wide shares.
2.3 Log-sum-exp stabilisation
A numerical detail with important practical consequences: computing $\exp(V_k)$ directly can overflow double-precision floating-point when utility values differ by more than ~700 (since $\exp(710) \approx 10^{308}$, the maximum double value). PlanX stabilises the computation by subtracting the maximum utility value before exponentiating:
$$P_k = \frac{\exp(V_k - V_{\max})}{\sum_m \exp(V_m - V_{\max})}$$This is mathematically identical to the original expression (adding a constant to all utilities does not change the logit probabilities) but ensures all exponentiated values are between 0 and 1, eliminating overflow. The maximum utility $V_{\max} = \max_m V_m$ is computed per OD pair.
2.4 Assumptions and limitations
- IIA property. Proportional substitution between all modes. Adding a new mode draws from all existing modes in proportion to their current shares. If you add a bus rapid transit mode, it will draw equally from car and walking (proportional to their shares), which may overstate the draw from transit-like modes and understate the draw from car.
- Time-only utility. The model includes only travel time and ASCs. Cost, reliability, comfort, frequency (for transit), and multimodality are all absorbed into the ASC. This is adequate for screening where time differences drive the scenario (a new bus lane changes $t_{\text{transit}}$; it does not change cost). For operational models, at minimum add cost ÷ value-of-time as a second variable.
- No trip-purpose segmentation. The same model parameters apply to all OD pairs regardless of trip purpose. In reality, mode choice for work trips differs substantially from shopping or leisure. For purpose-specific shares, run Mode Split separately on purpose-segmented flow tables.
- Observational equivalence of ASC and $\beta$. Without variation in travel times across OD pairs, ASC and $\beta$ are not separately identifiable — many combinations produce the same probabilities. For screening, fix $\beta$ at literature values (e.g., $-0.10$) and adjust ASCs to match aggregate shares.
3. Mathematical Formulation
Systematic utility. For each OD pair (indexed by $n$) and each mode $k \in \{1, \ldots, K\}$:
$$V_{nk} = \text{ASC}_k + \beta_k \cdot t_{nk} \tag{4}$$Choice probability (multinomial logit with log-sum-exp stabilisation). Let $V_n^{\max} = \max_k V_{nk}$:
$$P_{nk} = \frac{\exp(V_{nk} - V_n^{\max})}{\sum_{m=1}^{K} \exp(V_{nm} - V_n^{\max})} \tag{3}$$Mode-specific flows. Given the total OD flow $F_n$ for the pair:
$$F_{nk} = P_{nk} \cdot F_n \tag{2}$$By construction, $\sum_k P_{nk} = 1$ and $\sum_k F_{nk} = F_n$ for every OD pair.
Aggregate mode share (post-processing). The city-wide share of mode $k$:
$$\text{share}_k = \frac{\sum_n F_{nk}}{\sum_n F_n} = \frac{\sum_n P_{nk} \cdot F_n}{\sum_n F_n} \tag{1}$$This is a flow-weighted average — OD pairs with more trips contribute more to the aggregate share. The aggregate share is the calibration target: adjust ASCs until $\text{share}_k$ matches observed city-wide mode shares.
4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| OD flows layer | Vector (Line or Point) | Yes | Output of Gravity Distribution, or any layer with OD pairs and a total flow field. Must contain one time column per mode. |
| Mode time fields | Numeric fields | Yes | One field per mode, containing the travel time (minutes or consistent units) for that mode on each OD pair. Times must be in the same units for all modes. |
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
FLOWS | Vector layer (Line/Point) | — | OD flow layer, typically from Gravity Distribution. Must contain a total flow field and one time field per mode. |
FLOW_FIELD | Field (Numeric) | — | Field containing total trips per OD pair (the gravity model's flow column). |
MODE_TIMES | String | "time_car,time_transit" | Comma-separated field names for per-mode travel times. Each field must exist in the flows layer. Times are assumed to be in consistent units (minutes recommended). Order must match MODE_BETAS, MODE_ASCS, and MODE_NAMES. |
MODE_BETAS | String | "-0.1,-0.1" | Comma-separated time coefficients (typically negative). A value of −0.1 means each additional minute reduces utility by 0.1. Can differ by mode (e.g., walking-time coefficient often more negative than in-vehicle-time). |
MODE_ASCS | String | "0.0,0.0" | Comma-separated alternative-specific constants. ASCs capture unmeasured utility (comfort, flexibility). Normalise one mode to 0 and adjust others. Without calibration, use 0 for transit, 1–2 for car (in the absence of congestion pricing). |
MODE_NAMES | String | "car,transit" | Comma-separated mode names. Used to name output fields: share_{name} and flow_{name}. Must be valid field-name characters. |
OUTPUT | Vector layer | — | Annotated OD flows with appended share_{mode} and flow_{mode} columns. Original geometry and attributes are preserved. |
6. Output Description
| Field | Type | Description |
|---|---|---|
share_{name} | Double | Choice probability for mode name on this OD pair. Ranges [0, 1]; sum across modes = 1. Rounded to 4 decimal places. |
flow_{name} | Double | Estimated trips by mode name on this OD pair: share × total flow. Rounded to 2 decimal places. Sum across modes equals the total flow. |
For example, with MODE_NAMES="car,transit,walk", the output appends six columns: share_car, flow_car, share_transit, flow_transit, share_walk, flow_walk.
7. Symbolic Representation
For visualisation, aggregate flow_{mode} to zones (sum by origin
for productions, by destination for attractions) and map with a pie chart
overlay (QGIS "Diagrams" renderer) showing mode shares per zone.
Alternatively, compute the difference in flow_transit between two
scenarios and map as a graduated line layer with a diverging ramp (RdYlGn):
green where transit flow increases, red where it decreases. The transit-gain
corridors are the evidence for a transit investment's benefit.
8. Interpretation Guide
8.1 Scenario differencing is the robust analysis
With uncalibrated ASCs, the absolute mode shares are indicative, not operational. The statement "transit share = 23%" is not defensible without calibration against observed shares. The statement "the proposed bus lane shifts 340 daily trips from car to transit on this corridor" is defensible, because the ASC — which captures all unmeasured factors — is constant across scenarios and cancels in the difference. The robust policy use of PlanX's Mode Split is therefore:
- Run Mode Split on the base scenario (current travel times).
- Change the transit time field to reflect the proposed improvement
(e.g., reduce
time_transitby the expected travel-time saving from a bus lane). - Run Mode Split again with the same parameters.
- Report: $\Delta \text{flow}_{\text{transit}}$ (the net transit gain) and $\Delta \text{flow}_{\text{car}}$ (the net car reduction).
This "difference-in-shares" approach is standard practice for screening-level mode-choice analysis (Train, 2009, Chapter 2). The key assumption is that the unmeasured factors (the ASCs) do not change between scenarios — the bus lane makes transit faster but does not make it more comfortable or prestigious. For investments that do change comfort (e.g., new rolling stock, station upgrades), adjust the ASCs by judgement as well as the times.
8.2 Reading the time sensitivity
With $\beta = -0.10$, each 10-minute reduction in transit time multiplies the odds of choosing transit by $\exp(1) \approx 2.72$, relative to other modes (all else equal). The relationship is multiplicative, not additive:
- A 5-minute saving: odds multiplier = $\exp(0.5) \approx 1.65$ (65% increase).
- A 10-minute saving: odds multiplier = $\exp(1.0) \approx 2.72$ (172% increase).
- A 20-minute saving: odds multiplier = $\exp(2.0) \approx 7.39$ (639% increase).
This non-linearity means that the largest mode-shift returns come from the corridors with the largest current time penalty — the "low-hanging fruit." A bus lane that saves 5 minutes on a corridor where transit is already competitive may produce a modest shift; the same 5-minute saving where transit is 30 minutes slower than driving may produce very little shift because the time penalty, even reduced, remains large. The Mode Split output makes this visible: sort OD pairs by the absolute change in transit share and focus on the top decile — these are the corridors where time savings translate into mode shift most efficiently.
8.3 Cross-references to other PlanX tools
- Transit Travel-Time Access: the Transit
Access tool's output table contains travel times to destinations by
transit. Join this to the Gravity Distribution output to supply the
time_transitfield for Mode Split. This closes the loop: land-use produces trips, gravity distributes them, transit times come from the transit network, and Mode Split allocates the result. - Scenario Pipeline: the Scenario Pipeline can chain Trip Generation → Gravity Distribution → Mode Split as a single workflow. Define two scenarios (base and plan) with different population, employment, and transport networks, and the pipeline diff produces the mode-shift delta per corridor — a compact policy KPI.
- Emissions estimation: multiply $\text{flow}_{\text{car}}$ by the trip length (from the OD Cost Matrix) to estimate vehicle-kilometres travelled (VKT). Apply an emissions factor (g CO₂ per VKT) for a first-order transport emissions estimate. The change in VKT between scenarios quantifies the emissions impact of transport and land-use decisions.
8.4 Pitfalls
- Time units must be consistent. If one time field is in minutes and another in seconds, the model will produce nonsense — the betas apply to the numeric values as entered. Always use the same time unit (minutes recommended) for all mode time fields.
- Zero or missing times. An OD pair where
time_transitis 0 buttime_caris 15 will assign 100% probability to transit. Zero times are physically meaningless for motorised modes — they usually indicate data gaps. Check for zero or NULL time values before running; replace with a large value (e.g., 999 minutes) for mode-OD combinations where the mode is not available. - ASCs are not free parameters. Arbitrarily setting all ASCs to zero and all betas to −0.1 is the "uninformed prior" — the resulting shares reflect only time differences, not real-world preference for car over transit at equal times. This is appropriate for screening but the absolute shares will overstate transit use. For defensible absolute shares, calibrate ASCs against observed mode shares at the city level.
- Multiplying by gravity model flow compounds errors. The gravity model's flow magnitudes are themselves uncertain (beta sensitivity, zone aggregation). Mode-split shares applied to uncertain total flows produce uncertain mode flows — the uncertainty compounds, not cancels. Always report a sensitivity range (at minimum: low-beta and high-beta gravity model runs, each through the same Mode Split) rather than a single point estimate.
9. Academic References
McFadden, D. (1974). "Conditional logit analysis of qualitative choice behavior." In: Zarembka, P. (ed.), Frontiers in Econometrics, pp. 105–142. Academic Press, New York. book chapter, no DOI assigned]
Train, K.E. (2009). Discrete Choice Methods with Simulation. 2nd edition. Cambridge University Press, Cambridge. DOI: 10.1017/CBO9780511805271
Ben-Akiva, M. & Lerman, S.R. (1985). Discrete Choice Analysis: Theory and Application to Travel Demand. The MIT Press, Cambridge, MA. ISBN: 978-0-262-02217-0 book, no DOI assigned]
Domencich, T.A. & McFadden, D. (1975). Urban Travel Demand: A Behavioral Analysis. North-Holland, Amsterdam. ISBN: 0-7204-3170-5 book, no DOI assigned] Available at: UC Berkeley
Hensher, D.A., Rose, J.M. & Greene, W.H. (2015). Applied Choice Analysis: A Primer. 2nd edition. Cambridge University Press, Cambridge. DOI: 10.1017/CBO9781316136232
Manski, C.F. (1977). "The structure of random utility models." Theory and Decision, 8(3), 229–254. DOI: 10.1007/BF00133443
Ortuzar, J. de D. & Willumsen, L.G. (2011). Modelling Transport. 4th edition. John Wiley & Sons, Chichester. DOI: 10.1002/9781119993308
===ALGORITHM===19. Seismic Risk
The Seismic Risk group contains a single tool — Seismic Collapse and Debris Spread — that models the chain from earthquake shaking to building collapse to street-blocking debris to surviving evacuation corridors. It is a screening-quality Monte Carlo model: deterministic in the sense that a given seed always produces the same outcome, but stochastic in the sense that the seed samples one realisation from the probability distribution defined by the construction-year vulnerability tiers and the scenario magnitude. The tool implements the full pipeline recommended by Goretti & Sarli (2006) for post-earthquake road-network assessment and extends it with four alternative methods for defining the street/open-space network against which debris spread is measured.
Seismic Collapse and Debris Spread (Monte Carlo)
Processing ID: planx:seismicdebris
· Engine: engine/seismic.py
· Group: Seismic Risk (19)
1. Overview
Models the full chain from earthquake scenario magnitude to building collapse to debris spread to road blockage to surviving evacuation corridors. For each building, a collapse probability is derived from the construction year (proxy for seismic design code vintage) scaled by the scenario's moment magnitude $M_w$. A single deterministic Monte Carlo draw (seeded for reproducibility) determines whether the building collapses. Collapsed buildings spread debris outward to a radius proportional to their height (Goretti & Sarli, 2006) — the debris envelope is the union of all individual debris buffers, intersected with the road network to identify blocked segments, and subtracted from the network to reveal the open evacuation corridors.
The road network can be defined in four ways: (A) existing street/open-space polygons used as-is; (B) OSM highway centreline classes buffered by standard urban widths; (C) centreline with a per-feature width attribute; (D) the difference between a region-of-interest polygon and dissolved urban blocks. This flexibility lets the same tool work with diverse data availability: a detailed municipal GIS, a QuickOSM download, or cadastral parcels.
2. Theoretical Background
2.1 Seismic vulnerability as a construction-year proxy
Building collapse probability under seismic loading depends on structural system, material, ductility detailing, soil conditions, and ground-motion characteristics — a multi-dimensional fragility surface. For screening at the city scale without a building-by-building structural survey, the single most informative proxy is construction year (Coburn & Spence, 2002; FEMA, 2020). The logic is:
- Pre-1985: Buildings constructed before modern seismic codes. Unreinforced masonry, non-ductile concrete frames, soft-storey configurations. High baseline vulnerability ($p_{\text{base}} = 0.85$ at $M_w = 7.0$).
- 1985–2000: First-generation seismic codes introduced in many countries following major earthquakes (Mexico City 1985, Loma Prieta 1989, Northridge 1994). Moderate vulnerability ($p_{\text{base}} = 0.60$).
- 2000–2018: Modern seismic codes with capacity design principles. Low vulnerability ($p_{\text{base}} = 0.25$).
- Post-2018: Current-generation codes with performance-based design. Very low baseline vulnerability ($p_{\text{base}} = 0.05$).
These tier values are screening defaults, not calibrated fragility parameters. They are approximately centred on $M_w = 7.0$ — the reference magnitude at which the baseline probabilities apply. The exponential scaling factor $\exp(0.8(M_w - 7.0))$ adjusts the baseline for the scenario magnitude, with the coefficient 0.8 calibrated so that a unit increase in $M_w$ roughly doubles the collapse probability at the reference construction tier — consistent with the empirical observation that damage scales roughly exponentially with magnitude within the 5.5–8.0 range (Coburn & Spence, 2002).
For operational use, the tier probabilities and breakpoints must be calibrated to the local building stock. The defaults are conservative — they assume no retrofitting and the worst structural type common in each era. A city with an active seismic retrofit programme should reduce the probabilities for older tiers. A city on soft soils should increase them.
2.2 Debris spread mechanics
When a building collapses, the debris does not occupy only the building's footprint — it spreads outward into the surrounding street space. Goretti & Sarli (2006) analysed post-earthquake road blockage patterns from Italian earthquakes and proposed a simple geometric model: the debris spread is approximated as a buffer around the building footprint with radius proportional to the building height:
$$r_{\text{debris}} = k \cdot H$$where $H$ is the building height (floor count $\times$ floor height) and $k$ is the debris spread coefficient — the fraction of building height thrown horizontally. Goretti & Sarli found that $k \approx 0.4$ fits observed blockage patterns for mid-rise unreinforced masonry buildings. Taller buildings with larger plan aspect ratios can produce larger $k$ (up to 0.6), while low-rise ductile frames produce smaller $k$ (0.2–0.3). PlanX defaults to $k = 0.4$ for screening.
The debris volume (for clearance resource estimation) follows FEMA (2020) guidance: the gross building volume (footprint area $\times$ height) is multiplied by a solid volume ratio $\eta$ that accounts for void spaces within the collapsed debris. Typical $\eta$ values: 0.10–0.20 for steel/glass-frame buildings, 0.25–0.35 for reinforced concrete, 0.35–0.45 for unreinforced masonry. PlanX defaults to $\eta = 0.3$ (generic mid-range value).
2.3 Monte Carlo approach and reproducibility
The collapse decision is a single Bernoulli trial per building: draw $u_i \sim \text{Uniform}(0,1)$ from a seeded generator, compare to $p_{\text{collapse},i}$, and set $\text{collapsed}_i = 1$ if $u_i < p_i$. The seed is user-specified — the same seed, inputs, and software version always produce the identical collapse pattern. Changing the seed samples a different stochastic realisation of the same scenario.
This design reflects a deliberate modelling choice: one run = one realisation. The probability field ($p_{\text{collapse}}$) is the stable, seed-independent diagnostic; the collapsed flag is one dice roll consistent with it. For robust statements about evacuation corridor reliability, run the tool with 10–20 different seeds and count in how many runs each corridor survives. Corridors that survive all seeds are the dependable evacuation skeleton; corridors that flicker are not to be relied upon for emergency planning.
2.4 The four road network definitions
The network definition fundamentally shapes the result — a narrow street interpretation (centreline + small buffer) will show more blockage than a wide one (street-space polygons including setbacks). The four sources (A–D) let the practitioner match the available data:
- Source A (polygons as-is): The most faithful option when street-space polygons exist (from a zoning plan, cadastre-derived street space, or a previous analysis). Real widths, squares, and setbacks are preserved. This is the recommended source when data quality permits.
- Source B (OSM highway classes): Road centreline downloaded with QuickOSM, buffered by standard urban widths for each highway class. The default widths (motorway/trunk 25 m, primary 18 m, secondary 14 m, tertiary 10 m, residential 8 m, service/living_street 5 m, pedestrian/footway/cycleway 3 m, steps 2 m) are typical full carriageway widths for European cities. This is the fastest path to a screening result when only OSM data is available.
- Source C (width attribute): Any centreline network with a per-feature width field. Values like "6.5", "6,5", or "6.5 m" are all parsed. This is the option when municipal data includes measured street widths.
- Source D (ROI minus blocks): Street space computed as the set difference between a region-of-interest polygon and dissolved urban blocks (parcels or building blocks). This is the only option that requires no street data at all — cadastral parcels or building-block polygons define the non-street space, and everything else is assumed to be street. Parcels are dissolved internally, so shared boundaries vanish. If no ROI is given, the convex hull of the blocks expanded by the fallback width is used.
2.5 Assumptions and limitations
- Collapse is independent across buildings. The Monte Carlo draw treats each building's collapse as an independent Bernoulli trial. In reality, adjacent buildings of similar construction share vulnerability factors (ground motion, soil conditions, construction quality) that induce correlation. PlanX does not model this spatial correlation — the collapse pattern is less clustered than reality, which is conservative for corridor analysis (fragmented debris is easier to clear than large contiguous debris fields).
- Debris spread is isotropic. The buffer model assumes debris spreads equally in all directions. In reality, the debris field has a preferred direction aligned with the building's structural collapse mechanism (pancake, overturning, etc.), which depends on the ground-motion direction and the building's orientation and structural system. Schweier & Markus (2006) provide a classification of collapse types and their geometric footprints — PlanX's isotropic buffer is a simplification for screening.
- No secondary hazards. Fires following earthquakes, soil liquefaction, and landslides are not modelled. The debris field represents direct structural collapse only.
- Construction year is the only vulnerability predictor. Building height, structural system, plan irregularity, soft-storey presence, and soil class are not used. A pre-1985 steel moment frame and a pre-1985 unreinforced masonry building get the same baseline probability. For building-specific vulnerability, supply a pre-computed collapse probability field (e.g., from HAZUS or a detailed structural survey) and bypass the construction-year tier lookup.
3. Mathematical Formulation
Collapse probability. Given construction year $y_i$ and scenario moment magnitude $M_w$:
$$p_{\text{base}}(y_i) = \begin{cases} 0.85 & y_i \leq 1985 \\ 0.60 & 1985 < y_i \leq 2000 \\ 0.25 & 2000 < y_i \leq 2018 \\ 0.05 & y_i > 2018 \end{cases} \tag{7}$$ $$p_i = \min\left(1.0,\; \max\left(0.0,\; p_{\text{base}}(y_i) \cdot \exp(0.8 (M_w - 7.0))\right)\right) \tag{6}$$Collapse realisation. Given seed $s$, draw $u_i \sim \text{Uniform}(0,1)$ from the generator seeded with $s$:
$$\text{collapsed}_i = \mathbf{1}[u_i < p_i] \tag{5}$$Building height. From floor count $n_i$ and floor height $h_{\text{floor}}$:
$$H_i = n_i \cdot h_{\text{floor}} \tag{4}$$Debris spread radius. For collapsed buildings only:
$$r_i = \begin{cases} k \cdot H_i & \text{if collapsed}_i = 1 \\ 0 & \text{otherwise} \end{cases} \tag{3}$$where $k$ is the debris spread coefficient (fraction of height, default 0.4).
Debris volume. From footprint area $A_i$:
$$V_i = \begin{cases} A_i \cdot H_i \cdot \eta & \text{if collapsed}_i = 1 \\ 0 & \text{otherwise} \end{cases} \tag{2}$$where $\eta$ is the solid volume ratio (default 0.3).
Evacuation corridors. The debris envelope $D$ is the union of all individual debris buffers (building footprint buffered by $r_i$, square end-cap, mitre join). The blocked network is the intersection of the road/open-space network $N$ with the debris envelope:
$$B = N \cap D \qquad C = N \setminus B \tag{1}$$The open corridors $C$ are the planning product — the streets that remain passable after debris falls. Only corridors with non-zero area survive; narrow streets where the debris buffer spans the full width vanish entirely.
4. Input Data Requirements
| Input | Type | Required | Notes |
|---|---|---|---|
| Buildings | Vector polygons | Yes | Building footprints in a projected CRS (metres). Must have floor count and/or construction year fields; defaults are used when fields are missing. |
| Floor count field | Numeric | No | If omitted, defaults to 1 floor for all buildings. NULL values also default to 1. |
| Construction year field | Numeric | No | If omitted, defaults to 2000 for all buildings (the most populous tier). NULL values default to 2000. |
| Network inputs | Varies by source | Yes | One of: street/open-space polygons (A), road centreline (B/C), or blocks/parcels + ROI (D). See the Network Source parameter for details. |
5. Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
BUILDINGS | Vector layer (Polygon) | — | Building footprints. Projected CRS required. Missing floor count = 1; missing construction year = 2000. |
FLOOR_FIELD | Field (Numeric) | (optional) | Number of storeys per building. NULL => 1. Used to compute height (= floors × floor_height) and debris parameters. |
YEAR_FIELD | Field (Numeric) | (optional) | Construction year. NULL => 2000. Determines the vulnerability tier. Years before 1900 are capped to the oldest tier (0.85). |
NETWORK_MODE | Enum | A (0) | Network source: A = street/open-space polygons used as-is; B = OSM highway centreline buffered by class widths; C = centreline with width attribute; D = ROI minus dissolved blocks/parcels. |
NETWORK | Vector layer (Polygon) | (A only) | Street/open-space polygons. Used directly as the road network geometry. |
NETWORK_LINES | Vector layer (Line) | (B, C) | Road centreline. For source B, attributes are used for highway class lookup and/or width override. For source C, must have a width field (metres). |
HIGHWAY_FIELD | Field | (B) | Highway class field on centreline (e.g., "highway" from OSM). If blank, auto-detects a field named "highway". |
WIDTH_FIELD | Field (Numeric) | (B, C) | Road width in metres (full carriageway, not half). In source B, overrides the class-based width when present and valid. |
DEFAULT_WIDTH | Double | 8.0 | Fallback width (m) for B/C when no class/width is available; also the expansion distance for the auto-generated ROI hull in source D. |
ROI | Vector layer (Polygon) | (D only) | Region of interest polygon. If omitted, the convex hull of the blocks expanded by DEFAULT_WIDTH is used — provide an explicit ROI for concave study areas. |
BLOCKS | Vector layer (Polygon) | (D only) | Urban blocks or cadastral parcels. Dissolved internally — shared boundaries vanish. Street space = ROI minus dissolved blocks. |
MAGNITUDE | Double | 7.0 | Scenario moment magnitude ($M_w$). Range 4.0–9.0. The exponential scaling factor is $\exp(0.8(M_w - 7.0))$. Sweep 6.5 → 7.5 in 0.5 increments to find the resilience cliff. |
FLOOR_HEIGHT | Double | 3.0 | Average inter-storey height in metres. Total building height = floors × floor_height. Affects debris radius and volume. |
DEBRIS_FACTOR | Double | 0.4 | Debris spread coefficient $k$: fraction of building height thrown horizontally (Goretti & Sarli, 2006). Lower (0.2) for ductile frames; higher (0.6) for unreinforced masonry. |
SOLID_VOLUME_RATIO | Double | 0.3 | Solid volume ratio $\eta$: fraction of gross building volume that becomes solid debris. 0.10–0.20 steel/glass; 0.25–0.35 RC; 0.35–0.45 URM (FEMA, 2020). |
SEED | Integer | 42 | Random seed for the Monte Carlo draw. Same seed + same inputs = identical collapse pattern. Change to sample another realisation. Run 10–20 seeds for robust corridor reliability analysis. |
OUT_BUILDINGS | Vector layer (Point) | — | Annotated building centroids with collapse probability, collapsed flag, debris radius, and debris volume. |
OUT_ENVELOPE | Vector layer (MultiPolygon) | — | Dissolved debris spread envelope — the union of all individual collapsed-building buffers. |
OUT_BLOCKED | Vector layer (MultiPolygon) | — | Blocked portion of the road/open-space network (network ∩ debris envelope). Identifies which street sections are impassable. |
OUT_CORRIDORS | Vector layer (MultiPolygon) | — | Open evacuation corridors (network minus blocked). The planning product — streets that remain passable after debris falls. |
6. Output Description
| Output | Fields | Description |
|---|---|---|
| Annotated Buildings | height_m, collapse_prob, collapsed, debris_radius_m, debris_vol_m3 | Building centroid points with all intermediate and final risk metrics. collapse_prob is the seed-independent diagnostic (0–1); collapsed is the binary realisation (0/1) for this seed; debris_radius_m and debris_vol_m3 are 0 for non-collapsed buildings. |
| Debris Envelope | (none — geometry only) | Single MultiPolygon geometry: the union of all individual building debris buffers. The extent of debris on the ground. Visualised as a semi-transparent red overlay. |
| Network Blockage | (none — geometry only) | Single MultiPolygon geometry: the intersection of the road network with the debris envelope. These are the street sections that are impassable. Visualised as solid red. |
| Open Corridors | (none — geometry only) | Single MultiPolygon geometry: the road network minus the blocked sections. Streets that remain passable. Visualised as solid green. This is the evacuation and emergency-access map. |
7. Symbolic Representation
Style the four outputs as a three-layer map:
- Base layer: annotated buildings as graduated point symbols
(size 1.5–4.0 mm) styled by
collapse_probwith a sequential ramp (YlOrRd): yellow (low prob) to dark red (high prob). Buildings withcollapsed = 1in this seed can be shown with a thick black outline or a star symbol. - Middle layer: debris envelope at 30% opacity in red — the physical extent of rubble.
- Top layer: open evacuation corridors in semi-transparent green (30–40% opacity) — the planning product. The blocked streets are the gaps in the green network.
For multi-seed analysis, create a composite corridor-reliability map: run 20 seeds, rasterise each seed's corridor output (1 = open, 0 = blocked), sum the rasters, and style with a sequential green ramp (1–20). Cells with value 20 survived all seeds — the dependable skeleton. Cells with value 2–5 flicker — not reliable for evacuation planning.
8. Interpretation Guide
8.1 One run vs. many runs
A single run (one seed) produces one realisation of the earthquake scenario. This is useful for:
- Visualising a plausible worst case: show decision-makers what one earthquake could look like. The collapsed buildings are specific, named structures — this is more compelling than a probability map.
- Testing network preparation: does the network definition (mode A/B/C/D) produce a plausible street-space geometry? Check before committing to a multi-seed run.
- Identifying the seed-sensitivity of specific corridors: run twice with different seeds. If a critical corridor (hospital access) is open in one seed and blocked in another, it is not reliable.
For robust planning statements, run 10–20 seeds and analyse the distribution of outcomes. The key metrics across seeds:
- Corridor survival probability: for each corridor segment, the fraction of seeds in which it remained open. Segments with survival > 0.9 are the dependable skeleton.
- Mean and range of collapsed building count: the expected damage and its seed-to-seed variability. A narrow range (e.g., 340–360 collapsed buildings across 20 seeds at Mw 7.0) means the scenario is well-constrained; a wide range (200–500) means the city has many buildings with intermediate collapse probabilities (~0.5), and the outcome is genuinely uncertain.
- Mean and range of debris volume: sizes the clearance problem. Multiply by clearance cost per cubic metre (local rates) for a first-order resource estimate.
8.2 Reading the collapse probability field
The collapse_prob field is the stable, seed-independent
diagnostic. It tells you:
- Where the risk is concentrated: sort buildings by
descending
collapse_prob. The top 5% of buildings (by this probability) are the priority retrofit candidates, regardless of which buildings happen to collapse in any single seed. - How magnitude changes the picture: run at Mw 6.5, 7.0, 7.5. At 6.5, only the oldest tier (pre-1985) has elevated probability (0.85 × exp(−0.4) ≈ 0.57). At 7.5, even the newest tier has non-negligible probability (0.05 × exp(0.4) ≈ 0.07). The magnitude at which a significant number of post-2000 buildings exceed 0.3 probability is the "resilience cliff" — the seismic design level beyond which the building stock ceases to provide reliable protection.
- Interaction with urban form: tall pre-1985 buildings on
narrow streets are the highest-risk category — high collapse probability,
large debris radius, small street width to absorb it. Rank buildings by
collapse_prob × height_mand overlay on street width — the intersection identifies the worst-case structures.
8.3 Evacuation corridor analysis
The open corridors output is the primary planning product. The analysis sequence:
- Identify critical facilities: hospitals, fire stations, assembly areas, evacuation centres. Buffer each by a 50 m access zone.
- Check corridor connectivity: is each critical facility connected to the surviving corridor network in this seed? A facility whose access zone has zero intersection with the open corridors is isolated.
- Multi-seed reliability: count in how many seeds each facility retains corridor access. A hospital that is cut off in 15 out of 20 seeds is not operationally accessible after the modelled earthquake — it needs a second access route, a widened approach street, or pre-positioned supplies.
- Neighbourhood isolation: identify residential blocks that are entirely surrounded by blocked streets (zero corridor access). These are the neighbourhoods that would need helicopter or foot access — a different order of emergency-response challenge.
8.4 Cross-references to other PlanX tools
- Link Criticality: run Link Criticality on the same street network and compare the critical links to the corridors that survive the seismic debris model. A link that is both critical (high NRI) and likely to be blocked (low survival probability across seeds) is a dual vulnerability — it is structurally important and seismically fragile. These are the highest-priority resilience investments.
- Nearest Facility: run Nearest Facility with demand = population points and facilities = hospitals, using the open corridors as the network. Compare the allocation to the baseline (intact network). The population whose nearest hospital distance increases by more than 50% is the population that loses effective emergency access in this scenario.
- Scenario Compare: a seismic scenario is a specific type of "planning scenario." Feed the corridor survival summary (count of open corridors, number of isolated facilities) into Scenario Compare alongside growth and infrastructure scenarios to evaluate seismic resilience alongside other planning priorities.
8.5 Pitfalls
- Year tiers are global defaults, not local calibrations. The three tier breakpoints (1985, 2000, 2018) reflect the approximate trajectory of seismic code development internationally, but individual countries introduced codes at different times (Turkey: 1975, 1998, 2007, 2018; Japan: 1924, 1950, 1981, 2000; Chile: 1972, 1996, 2010). Replace the tier breakpoints and probabilities with locally appropriate values before using the tool for operational risk assessment.
- The collapse flag is one roll of the dice. Do not present a single seed's collapse pattern as "the" earthquake damage — it is one realisation from a probability distribution. The question "will this building collapse in a Mw 7.0 earthquake?" has a probabilistic answer (the collapse_prob field), not a deterministic one. The collapsed flag exists to make the debris spread geometrically concrete, not to certify individual building safety.
- Street width matters critically. A 2 m difference in default street width can change a corridor from "survives" to "blocked." Source B (OSM highway classes) uses standard widths that may not match local conditions — a "residential" street in a historic centre may be 4 m wide between facades, not the assumed 8 m. Whenever possible, use Source A (measured street-space polygons) or Source C (measured widths) for consequential analysis.
- The model has no time dimension. All buildings collapse simultaneously. There is no aftershock sequence, no progressive collapse, and no cascading failures (e.g., a collapsed building damaging a neighbouring one). The debris envelope is a static snapshot of the immediate post-event condition, not a time-evolving debris field.
9. Academic References
Goretti, A. & Sarli, V. (2006). "Road network and damaged buildings in urban areas: short and long-term interaction." Bulletin of Earthquake Engineering, 4(2), 159–175. DOI: 10.1007/s10518-006-9004-3
Coburn, A. & Spence, R. (2002). Earthquake Protection. 2nd edition. John Wiley & Sons, Chichester. DOI: 10.1002/0470855185
Schweier, C. & Markus, M. (2006). "Classification of Collapsed Buildings for Fast Damage and Loss Assessment." Bulletin of Earthquake Engineering, 4(2), 177–192. DOI: 10.1007/s10518-006-9005-2
FEMA (2020). Hazus Earthquake Model Technical Manual — Hazus 5.1. Federal Emergency Management Agency, Washington, DC. Available at: fema.gov/hazus
Ansal, A., Akinci, A., Cultrera, G., Erdik, M., Pessina, V., Tonuk, G. & Zulfikar, C. (2011). "Loss scenarios for the city of Istanbul and its vulnerability to earthquakes." Soil Dynamics and Earthquake Engineering, 31(3), 534–546. DOI: 10.1016/j.soildyn.2010.10.008
Argyroudis, S., Selva, J., Gehl, P. & Pitilakis, K. (2015). "Systemic Seismic Risk Assessment of Road Networks Considering Interactions with the Built Environment." Computer-Aided Civil and Infrastructure Engineering, 30(7), 524–540. DOI: 10.1111/mice.12136
Zanini, M.A., Faleschini, F., Zampieri, P., Pellegrino, C., Gecchele, G., Gastaldi, M. & Rossi, R. (2017). "Post-quake urban road network assessment: A combined seismic damage and traffic flow approach." Structure and Infrastructure Engineering, 13(3), 355–368. DOI: 10.1080/15732479.2016.1170780
Appendix A: Data Sources Directory
| Data Type | Global Source | Resolution | Notes |
|---|---|---|---|
| Street network | OpenStreetMap (QuickOSM, Overpass Turbo) | — | Filter highway=* tags; remove motorways for pedestrian analyses |
| Building footprints | Microsoft Building Footprints, OpenStreetMap | — | National cadastral databases where available; OSM coverage varies |
| DEM (30 m) | SRTM, ALOS AW3D30, Copernicus GLO-30 | 30 m | SRTM: void-filled versions preferred; ALOS: better in steep terrain |
| DEM (high-res) | National LIDAR programmes | 1–5 m | Essential for urban pluvial flood screening and microclimate |
| DSM (surface) | National LIDAR; EU-DSM (Copernicus) | 1–30 m | Must include building heights for solar/shadow/visibility analysis |
| Population | WorldPop, GHS-POP, LandScan, national censuses | 100 m–1 km | WorldPop and GHS-POP are open; LandScan requires license |
| Employment | National business registries, census workplace data | Zone-level | Often available as TAZ-level summaries from MPOs |
| Land use / land cover | Copernicus Urban Atlas, ESA WorldCover, OSM landuse | 10–100 m | Urban Atlas: 17 urban classes, ~200 European cities only |
| Green spaces | OSM leisure=park, landuse=grass, natural=wood | — | Contains private gardens; filter by access=* tags where needed |
| GTFS transit feeds | Transit.land, OpenMobilityData, agency websites | — | Coverage strongest in North America, Europe, and major Asian cities |
| Traffic counts (AADT) | National/state DOT traffic count programmes | Point data | Often sparse outside major roads; use travel-demand models as fallback |
| Cycling infrastructure | OSM cycleway=*, local bike-network inventories | — | OSM coverage improving; always verify against official maps |
| Seismic vulnerability | National building censuses, post-earthquake surveys | Building-level | Construction year often the best available fragility proxy |
Appendix B: Symbolization Quick Reference
| Output Type | Recommended Renderer | Color Ramp | Classes | Classification |
|---|---|---|---|---|
| Network centrality (betweenness) | Graduated (point) | Viridis / Inferno | 5–7 | Natural breaks |
| Space syntax NACH | Graduated (line) | Viridis / Plasma | 7–10 | Quantile |
| Space syntax NAIN | Graduated (line) | OrRd / YlOrRd | 7–10 | Quantile |
| Walkability score | Graduated (line) | RdYlGn | 5 | Equal interval |
| Access score (15-min) | Graduated (point) | RdYlGn | 5 | Manual (40,60,80,100) |
| Building form metrics | Graduated (polygon) | Sequential (Blues/Oranges/Reds) | 5 | Natural breaks |
| Spacematrix class | Categorized (polygon) | 10-class green-orange-red palette | 10 | Fixed categories |
| SVF | Pseudocolor (raster) | RdBu reversed | 7–10 | 0.1 intervals |
| Shadow / Sun hours | Pseudocolor (raster) | YlOrRd / Plasma | 5–8 | Manual based on daylight |
| Solar irradiation | Pseudocolor (raster) | Viridis / Inferno | 5–8 | Manual (% of reference) |
| Heat risk grid | Graduated (polygon) | YlOrRd | 4 | Fixed (25,50,75) |
| Noise grid | Pseudocolor (raster) | Green→Yellow→Orange→Red | Continuous | Manual (45,55,65,75 dB) |
| HAND index | Pseudocolor (raster) | RdYlBu reversed | 7 | Manual (0,1,2,5,10,20,50 m) |
| Inundation mask | Two-class (raster) | Blue / transparent | 2 | Binary |
| LTS / Cycling stress | Categorized (line) | Teal/Orange/Purple/Magenta | 4 | Fixed categories |
| Flow accumulation | Pseudocolor (raster) | Viridis | 10 | Log-spaced manual |
| Equity (Gini/Theil) | Graduated (point) | Diverging (RdYlGn) | 5–7 | Equal interval |
| Equity crosstabs | Categorized (point) | Sequential by v_class | 5 | Quantile (by population) |
| Gravity desire lines | Graduated (line) | Single hue + opacity | 5–7 | Natural breaks |
| Debris / evacuation | Two-class (polygon) | Red (debris) / Green (open) | 2 | Binary |
| Service areas (pedshed) | Hollow circles over solid areas | Blue circles, warm areas | 2 layers | Overlay |
| Land-use allocation | Categorized (polygon) | Distinct per use + grey unassigned | N uses + 1 | Fixed categories |
Appendix C: Glossary
- AADT
- Annual Average Daily Traffic — vehicles per day on a road segment.
- Angular cost
- Turn angle in degrees divided by 90. Straight = 0; right angle = 1.
- ASC
- Alternative-Specific Constant — in mode choice models, captures average unmeasured utility of a mode.
- ASHRAE
- American Society of Heating, Refrigerating and Air-Conditioning Engineers — clear-sky irradiance model.
- Atkinson index
- Inequality measure with explicit normative parameter ε (inequality aversion).
- CA (Cellular Automaton)
- Grid-based simulation where cell state changes according to neighbourhood rules.
- CSR
- Compressed Sparse Row — sparse matrix format used for graph adjacency.
- D8
- Eight-direction single flow direction model for hydrological routing on gridded DEMs.
- Dasymetric mapping
- Redistribution of areal data using ancillary information (e.g., buildings to refine population distribution).
- DEM
- Digital Elevation Model — raster of bare-earth terrain heights.
- DSM
- Digital Surface Model — raster of terrain + building + vegetation heights.
- Dijkstra
- Shortest-path algorithm for non-negative edge weights; runs in $O((V+E)\log V)$.
- dPC
- Delta Probability of Connectivity — share of connectivity index lost when a patch is removed.
- FAR / FSI
- Floor Area Ratio / Floor Space Index — gross floor area divided by site area.
- Furness / IPF
- Iterative Proportional Fitting — balances matrix rows and columns to match target marginals.
- Gini coefficient
- Inequality measure: 0 = perfect equality, 1 = maximal inequality. Twice the area between the Lorenz curve and equality line.
- GSI
- Ground Space Index — building footprint area divided by site area (coverage).
- GTFS
- General Transit Feed Specification — standard open format for public transit schedules.
- HAND
- Height Above Nearest Drainage — vertical distance from a cell to the nearest stream cell along the D8 flow path.
- Hare-Niemeyer
- Largest-remainder apportionment method — guarantees exact integer allocation summing to the target.
- Isovist
- The set of all points visible from a given vantage point (Benedikt, 1979).
- LCRPGR
- Land Consumption Rate to Population Growth Rate ratio — SDG Indicator 11.3.1.
- Leslie matrix
- Age-structured population projection matrix: fertility on first row, survival on sub-diagonal.
- Lorenz curve
- Plot of cumulative population share vs. cumulative value share — graphical inequality measure.
- LTS
- Level of Traffic Stress — 1 (children) to 4 (strong and fearless only), for cycling.
- MCLP
- Maximal Covering Location Problem — maximise population served within a distance given p facilities.
- MNL
- Multinomial Logit — discrete choice model with Gumbel-distributed errors (McFadden, 1974).
- NAIN
- Normalised Angular INtegration — size-independent to-movement potential (Hillier, Yang & Turner, 2012).
- NACH
- Normalised Angular CHoice — size-independent through-movement potential.
- OSR
- Open Space Ratio — (1 − GSI) / FSI; spaciousness.
- PC (connectivity)
- Probability of Connectivity — sum of squared component areas divided by total area squared.
- Pedshed ratio
- Network catchment area divided by straight-line circle area — measures street-layout efficiency.
- P-median
- Facility location problem: minimise population-weighted total travel distance with p facilities.
- RAPTOR
- Round-based Public Transit Routing — earliest-arrival algorithm using timetable rounds.
- SVF
- Sky View Factor — fraction of visible sky hemisphere from a point (0–1).
- Tobler function
- Walking speed as a function of slope: $v = 6 \cdot e^{-3.5|m+0.05|}$ km/h.
- Theil index
- Inequality measure from information theory; additively decomposable into between/within groups.
- UTM
- Universal Transverse Mercator — projected CRS family in metres, suitable for all PlanX tools.
- λf / λp
- Frontal Area Index ($\lambda_f$) and Plan Area Index ($\lambda_p$) — urban roughness parameters.
— End of PlanX Comprehensive Academic Reference Manual —
Covering PlanX v4.10.1 · 69 Algorithms · 19 Tool Groups · August 2026