Skip to content

Commit 2b1bf15

Browse files
authored
Merge pull request #170 from benchmark-urbanism/dev
# v4.24.0 Release Notes ## New Features ### Z-aware networks (elevation and slope) Network nodes now support an optional `z` attribute for elevation. When both endpoints of an edge have z coordinates, a slope-based walking impedance using Tobler's hiking function is automatically applied during shortest-path and simplest-path computations. Uphill segments incur a penalty proportional to grade; steep downhill segments are also penalised; gentle downhill slopes receive a slight bonus. The penalty is directional (A→B differs from B→A) and composes with the configured walking speed. Z coordinates are preserved through the full processing chain: graph construction, decomposition, consolidation, merging, dual graph conversion, CRS reprojection, and round-trip serialisation. When z is absent, behaviour is identical to previous versions. Supported in all IO methods: `nx_from_osm_nx`, `nx_from_open_roads`, `nx_from_generic_geopandas`, `nx_from_cityseer_geopandas`, `network_structure_from_nx`, and `network_structure_from_gpd`. ### Adaptive sampling (experimental) `node_centrality_shortest` and `node_centrality_simplest` accept `sample=True` to use distance-based Hoeffding/Eppstein-Wang sampling for approximate centrality, achieving 2-3x speedup while maintaining ρ ≥ 0.95. Sampling probability is derived deterministically from each distance threshold using a canonical grid network model. This work remains experimental. ### QGIS plugin updates New accessibility and statistics processing algorithms. Expanded centrality algorithm with sampling support. ## Breaking Changes ### Angular (simplest-path) analysis now requires a dual graph `node_centrality_simplest` (and the convenience wrappers `closeness_simplest`, `betweenness_simplest`) now raises `ValueError` if the input `NetworkStructure` was not ingested from a dual graph. Angular routing uses endpoint-aware dual-graph traversal instead of the previous bearing-based angular costs. Convert primal graphs with `graphs.nx_to_dual()` before calling `network_structure_from_nx()`. ### `tolerance` parameter semantics changed The `tolerance` parameter on `node_centrality_shortest`, `node_centrality_simplest`, `betweenness_shortest`, `betweenness_simplest`, and `betweenness_od` now uses **relative percentage** semantics (e.g. `1.0` = 1%) instead of the previous absolute fraction. The default changed from `0.0` to `None`. A tiny internal epsilon is always enforced for floating-point stability. To migrate: multiply old values by 100 (e.g. old `0.05` → new `5.0`). ### `tolerance` parameter reordered in `node_centrality_simplest` `tolerance` now appears before `angular_scaling_unit` and `farness_scaling_offset`. Code using positional arguments for these parameters will need updating. ### `cycles` metric changed The `cycles` output from `node_centrality_shortest` now measures the **circuit rank** of the locally reachable subgraph (m − n + c), providing a more stable measure of network meshedness than the older tree-cycle heuristic. ### Sampling functions moved from `config` to `sampling` module `compute_distance_p`, `compute_hoeffding_p`, `HOEFFDING_EPSILON`, `HOEFFDING_DELTA`, and `GRID_SPACING` have moved from `cityseer.config` to `cityseer.sampling`. The `config` module is still importable via lazy-loading but no longer contains sampling functions. Update imports accordingly. ## Other Changes - All result arrays (`CentralityShortestResult`, `CentralitySimplestResult`, `CentralitySegmentResult`, `Stats`, etc.) now return `np.float64` instead of `np.float32`. - `betweenness_od` now accepts an optional `tolerance` parameter. - `closeness_shortest` and `closeness_simplest` now accept an optional `tolerance` parameter. - Bug fix: `is_dual` graph attribute was incorrectly cast via `CRS()` instead of `bool()` in `nx_remove_dangling_nodes` and `nx_merge_parallel_edges`. - `NetworkStructure` now tracks `is_dual` explicitly and exposes `node_zs`, `node_xyzs`, and `coord_z` properties. - Dual graph edges now pass `shared_primal_node_key` for endpoint-aware angular transitions. - `measure_bearing` in `tools.util` now unpacks `x, y` in the correct order (was previously reversed but functionally equivalent due to symmetric usage).
2 parents 99454e3 + 337c119 commit 2b1bf15

File tree

30 files changed

+2436
-1102
lines changed

30 files changed

+2436
-1102
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ Cite as: [The cityseer Python package for pedestrian-scale network-based urban a
3636
The `cityseer-api` `Python` package addresses a range of issues specific to computational workflows for urban analytics from an urbanist's point of view and contributes a combination of techniques to support developments in this field:
3737

3838
- High-resolution workflows including localised moving-window analysis with strict network-based distance thresholds; spatially precise assignment of land-use or other data points to adjacent street-fronts for improved contextual sensitivity; dynamic aggregation workflows which aggregate and compute distances on-the-fly from any selected point on the network to any accessible land-use or data point within a selected distance threshold; facilitation of workflows eschewing intervening steps of aggregation and associated issues such as ecological correlations; and the optional use of network decomposition to increase the resolution of the analysis.
39-
- Localised computation of network centralities using either shortest or simplest path heuristics on either primal or dual graphs, including tailored methods such as harmonic closeness centrality, and segmented versions of centrality (which convert centrality methods from a discretised to an explicitly continuous form). For more information, see [_"Network centrality measures and their correlation to mixed-uses at the pedestrian-scale"_](https://arxiv.org/abs/2106.14040).
40-
- Land-use accessibilities and mixed-use calculations incorporate dynamic and directional aggregation workflows with the optional use of spatial-impedance-weighted forms. These can likewise be applied with either shortest or simplest path heuristics and on either primal or dual graphs. For more information, see [_"The application of mixed-use measures at the pedestrian-scale"_](https://arxiv.org/abs/2106.14048).
39+
- Localised computation of network centralities using shortest paths on primal or dual graphs, and simplest-path heuristics on dual graphs, including tailored methods such as harmonic closeness centrality, and segmented versions of centrality (which convert centrality methods from a discretised to an explicitly continuous form). For more information, see [_"Network centrality measures and their correlation to mixed-uses at the pedestrian-scale"_](https://arxiv.org/abs/2106.14040).
40+
- Land-use accessibilities and mixed-use calculations incorporate dynamic and directional aggregation workflows with the optional use of spatial-impedance-weighted forms. Shortest-path workflows operate on primal or dual graphs, while simplest-path workflows require dual graphs. For more information, see [_"The application of mixed-use measures at the pedestrian-scale"_](https://arxiv.org/abs/2106.14048).
4141
- Network centralities dovetailed with land-use accessibilities, mixed-uses, and general statistical aggregations from the same points of analysis to generate multi-scalar and multi-variable datasets facilitating downstream data science and machine learning workflows. For examples, see [_"Untangling urban data signatures: unsupervised machine learning methods for the detection of urban archetypes at the pedestrian scale"_](https://arxiv.org/abs/2106.15363) and [_"Prediction of 'artificial' urban archetypes at the pedestrian-scale through a synthesis of domain expertise with machine learning methods"_](https://arxiv.org/abs/2106.15364).
4242
- The inclusion of graph cleaning methods reduce topological distortions for higher quality network analysis and aggregation workflows while accommodating workflows bridging the wider `NumPy` ecosystem of scientific and geospatial packages.
4343
- Underlying loop-intensive algorithms are implemented in `rust`, allowing these methods to be applied to large and, optionally, decomposed graphs, which have substantial computational demands.

RELEASE_NOTES.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# v4.24.0 Release Notes
2+
3+
## New Features
4+
5+
### Z-aware networks (elevation and slope)
6+
7+
Network nodes now support an optional `z` attribute for elevation. When both endpoints of an edge have z coordinates, a slope-based walking impedance using Tobler's hiking function is automatically applied during shortest-path and simplest-path computations. Uphill segments incur a penalty proportional to grade; steep downhill segments are also penalised; gentle downhill slopes receive a slight bonus. The penalty is directional (A→B differs from B→A) and composes with the configured walking speed.
8+
9+
Z coordinates are preserved through the full processing chain: graph construction, decomposition, consolidation, merging, dual graph conversion, CRS reprojection, and round-trip serialisation. When z is absent, behaviour is identical to previous versions.
10+
11+
Supported in all IO methods: `nx_from_osm_nx`, `nx_from_open_roads`, `nx_from_generic_geopandas`, `nx_from_cityseer_geopandas`, `network_structure_from_nx`, and `network_structure_from_gpd`.
12+
13+
### Adaptive sampling (experimental)
14+
15+
`node_centrality_shortest` and `node_centrality_simplest` accept `sample=True` to use distance-based Hoeffding/Eppstein-Wang sampling for approximate centrality, achieving 2-3x speedup while maintaining ρ ≥ 0.95. Sampling probability is derived deterministically from each distance threshold using a canonical grid network model.
16+
17+
### QGIS plugin updates
18+
19+
New accessibility and statistics processing algorithms. Expanded centrality algorithm with sampling support.
20+
21+
## Breaking Changes
22+
23+
### Angular (simplest-path) analysis now requires a dual graph
24+
25+
`node_centrality_simplest` (and the convenience wrappers `closeness_simplest`, `betweenness_simplest`) now raises `ValueError` if the input `NetworkStructure` was not ingested from a dual graph. Angular routing uses endpoint-aware dual-graph traversal instead of the previous bearing-based angular costs. Convert primal graphs with `graphs.nx_to_dual()` before calling `network_structure_from_nx()`.
26+
27+
### `tolerance` parameter semantics changed
28+
29+
The `tolerance` parameter on `node_centrality_shortest`, `node_centrality_simplest`, `betweenness_shortest`, `betweenness_simplest`, and `betweenness_od` now uses **relative percentage** semantics (e.g. `1.0` = 1%) instead of the previous absolute fraction. The default changed from `0.0` to `None`. A tiny internal epsilon is always enforced for floating-point stability. To migrate: multiply old values by 100 (e.g. old `0.05` → new `5.0`).
30+
31+
### `tolerance` parameter reordered in `node_centrality_simplest`
32+
33+
`tolerance` now appears before `angular_scaling_unit` and `farness_scaling_offset`. Code using positional arguments for these parameters will need updating.
34+
35+
### `betweenness_beta` removed from angular (simplest) results
36+
37+
`CentralitySimplestResult` no longer exposes `node_betweenness_beta`. The `node_centrality_simplest` function no longer writes `cc_betweenness_beta_*` columns. Only `cc_betweenness_*` columns are produced.
38+
39+
### `cycles` metric changed
40+
41+
The `cycles` output from `node_centrality_shortest` now measures the **circuit rank** of the locally reachable subgraph (m − n + c), providing a more stable measure of network meshedness than the older tree-cycle heuristic.
42+
43+
### Sampling functions moved from `config` to `sampling` module
44+
45+
`compute_distance_p`, `compute_hoeffding_p`, `HOEFFDING_EPSILON`, `HOEFFDING_DELTA`, and `GRID_SPACING` have moved from `cityseer.config` to `cityseer.sampling`. The `config` module is still importable via lazy-loading but no longer contains sampling functions. Update imports accordingly.
46+
47+
## Other Changes
48+
49+
- All result arrays (`CentralityShortestResult`, `CentralitySimplestResult`, `CentralitySegmentResult`, `Stats`, etc.) now return `np.float64` instead of `np.float32`.
50+
- `betweenness_od` now accepts an optional `tolerance` parameter.
51+
- `closeness_shortest` and `closeness_simplest` now accept an optional `tolerance` parameter.
52+
- Bug fix: `is_dual` graph attribute was incorrectly cast via `CRS()` instead of `bool()` in `nx_remove_dangling_nodes` and `nx_merge_parallel_edges`.
53+
- `NetworkStructure` now tracks `is_dual` explicitly and exposes `node_zs`, `node_xyzs`, and `coord_z` properties.
54+
- Dual graph edges now pass `shared_primal_node_key` for endpoint-aware angular transitions.
55+
- `measure_bearing` in `tools.util` now unpacks `x, y` in the correct order (was previously reversed but functionally equivalent due to symmetric usage).

docs/src/pages/intro.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,30 @@ A growing collection of recipes and examples is available via the [`Cityseer Exa
1919
`cityseer` is developed from the ground-up for pedestrian-scale urban analysis. It builds-on and further best-practices for urban analytics:
2020

2121
- It uses localised network analysis (as opposed to global forms of analysis) using a 'moving-window' methodology. A node is selected, the graph is then isolated at a selected distance threshold around the node, metrics are then computed, and then the process subsequently repeats for every other node in the network. `cityseer` exclusively uses localised methods for network analysis because they do not suffer from the same issues as global methods, which are inherently problematic because of edge roll-off effects. Localised methods have the distinct advantage of being comparable across different locations and cities, while also being capable of targeting both smaller and larger distance thresholds to reveal patterns at different scales of analysis.
22-
- It is common to use either shortest-distance (metric) or simplest-path (shortest angular or geometric distance) heuristics for network analysis. When using simplest-path (angular) distances, it is necessary to modify the underlying shortest-path algorithms to prevent side-stepping of sharp angular turns; otherwise, two smaller side-steps can be combined to 'short-cut' sharp corners.
23-
- `cityseer` supports analysis for both primal and dual graph representations, and contains methods for converting from primal (intersection-based) to dual (street-segment-based) representations. The dual representation retains accurate street lengths and geometry (angles) while affording the opportunity to measure and visualise metrics relative to streets instead of intersections.
22+
- It is common to use either shortest-distance (metric) or simplest-path (shortest angular or geometric distance) heuristics for network analysis. In `cityseer`, simplest-path (angular) analysis is performed on dual graphs so that each segment forms an explicit routing state.
23+
- `cityseer` supports analysis for both primal and dual graph representations, and contains methods for converting from primal (intersection-based) to dual (street-segment-based) representations. Shortest-path workflows support either topology. Angular workflows require the dual representation, which retains accurate street lengths and geometry (angles) while affording the opportunity to measure and visualise metrics relative to streets instead of intersections.
2424
- `cityseer` supports both unweighted and weighted (spatial impedance) forms of centrality, accessibility, and mixed-use methods.
2525
- To support the evaluation of measures at finely-spaced intervals along street fronts, `cityseer` includes support for network decomposition.
2626
- Granular evaluation of land-use accessibilities and mixed-uses requires that land uses be assigned to the street network in a contextually precise manner. `cityseer` assigns data-points to the nearest adjacent street segment and then allows access over the network from both sides, thereby allowing precise distances to be calculated dynamically based on the direction of approach.
2727
- Centrality methods are susceptible to topological distortions arising from 'messy' graph representations as well as due to the conflation of topological and geometrical properties of street networks. `cityseer` addresses these through the inclusion of graph cleaning functions and procedures for splitting geometrical properties from topological representations.
2828

29+
## Elevation and Slope
30+
31+
`cityseer` supports optional z (elevation) coordinates on network nodes. When elevation data is available, it is preserved throughout the full processing chain: graph construction, decomposition, consolidation, merging, dual graph conversion, CRS reprojection, and round-trip serialisation between `networkX`, `GeoDataFrames`, and the Rust `NetworkStructure`.
32+
33+
When both endpoint nodes of an edge have z coordinates, `cityseer` automatically applies a slope-based walking impedance during shortest-path and simplest-path computations, using [Tobler's hiking function](https://en.wikipedia.org/wiki/Tobler%27s_hiking_function) (Tobler, 1993). This adjusts the effective traversal cost of each edge based on the gradient:
34+
35+
- **Uphill** segments incur a penalty proportional to the grade (e.g. a 20% slope approximately doubles the effective distance).
36+
- **Steep downhill** segments are also penalised, reflecting the reduced walking speed on steep descents.
37+
- **Gentle downhill** slopes (~3%) receive a slight bonus, matching the empirically observed optimal walking gradient.
38+
- **Flat terrain** incurs no penalty (multiplier of 1.0).
39+
40+
The slope penalty is computed dynamically and directionally during graph traversal, so the cost of walking uphill from A to B differs from the cost of walking downhill from B to A. This operates independently of the configured walking speed: the penalty is a dimensionless multiplier on effective distance, meaning it composes correctly regardless of whether the walking speed is set to 1.4 m/s or any other value.
41+
42+
For simplest-path (angular) analysis, the slope penalty affects only the time budget (reachability cutoff), not the angular routing metric itself. This means the cognitively simplest path is still selected, but steep terrain reduces the distance a pedestrian can cover within the analysis threshold.
43+
44+
When z coordinates are not present, all slope penalties default to 1.0 (no effect), ensuring full backward compatibility with existing 2D workflows.
45+
2946
The broader emphasis on localised methods and how `cityseer` addresses these is broached in the [associated paper](https://journals.sagepub.com/doi/full/10.1177/23998083221133827). `cityseer` includes a variety of convenience methods for the general preparation of networks and their conversion into (and out of) the lower-level data structures used by the underlying algorithms. These graph utility methods are designed to work with `NetworkX` to facilitate ease of use. A complement of code tests has been developed to maintain the codebase's integrity through general package maintenance and upgrade cycles. Shortest-path algorithms, harmonic closeness, and betweenness algorithms are tested against `NetworkX`. Mock data and test plots have been used to visually confirm the intended behaviour for divergent simplest and shortest-path heuristics and for testing data assignment to network nodes given various scenarios.
3047

3148
The best way to get started is to see the [`Cityseer Examples`](https://benchmark-urbanism.github.io/cityseer-examples/) site, which contains a number of recipes for a variety of use-cases.

0 commit comments

Comments
 (0)