Skip to content

Commit f7a9da7

Browse files
songololoclaude
andcommitted
Remove segment_centrality, add segment_weighted param, rename centrality functions
Replace the separate segment_centrality code path (edge-based continuous integrals, dedicated Dijkstra, CentralitySegmentResult) with a segment_weighted boolean on the existing centrality functions. On dual graphs, this sets node weights to primal edge lengths so that closeness measures reflect total reachable street length and betweenness weights pairs by both endpoint segment lengths. - Rename node_centrality_shortest → centrality_shortest - Rename node_centrality_simplest → centrality_simplest - Add segment_weighted param (Rust + Python) with _SegmentWeightContext - Add set_node_weight method on NetworkStructure - Replace pair_distances_betas_time with pair_distances_and_time - Clean up betas machinery from Python callers and log_thresholds - Remove dead code: EdgeVisit, dijkstra_tree_segment, origin_seg/last_seg, unchecked edge helpers, CentralitySegmentResult - Update all docs, tests, type stubs, and references Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 77c8a41 commit f7a9da7

File tree

30 files changed

+424
-1646
lines changed

30 files changed

+424
-1646
lines changed

RELEASE_NOTES.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Supported in all IO methods: `nx_from_osm_nx`, `nx_from_open_roads`, `nx_from_ge
1212

1313
### Adaptive sampling (experimental)
1414

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.
15+
`centrality_shortest` and `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.
1616

1717
### QGIS plugin updates
1818

@@ -22,31 +22,31 @@ New accessibility and statistics processing algorithms. Expanded centrality algo
2222

2323
### Angular (simplest-path) analysis now requires a dual graph
2424

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()`.
25+
`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()`.
2626

2727
### `tolerance` parameter semantics changed
2828

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`).
29+
The `tolerance` parameter on `centrality_shortest`, `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`).
3030

31-
### `tolerance` parameter reordered in `node_centrality_simplest`
31+
### `tolerance` parameter reordered in `centrality_simplest`
3232

3333
`tolerance` now appears before `angular_scaling_unit` and `farness_scaling_offset`. Code using positional arguments for these parameters will need updating.
3434

3535
### `betweenness_beta` removed from angular (simplest) results
3636

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.
37+
`CentralitySimplestResult` no longer exposes `node_betweenness_beta`. The `centrality_simplest` function no longer writes `cc_betweenness_beta_*` columns. Only `cc_betweenness_*` columns are produced.
3838

3939
### `cycles` metric changed
4040

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.
41+
The `cycles` output from `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.
4242

4343
### Sampling functions moved from `config` to `sampling` module
4444

4545
`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.
4646

4747
## Other Changes
4848

49-
- All result arrays (`CentralityShortestResult`, `CentralitySimplestResult`, `CentralitySegmentResult`, `Stats`, etc.) now return `np.float64` instead of `np.float32`.
49+
- All result arrays (`CentralityShortestResult`, `CentralitySimplestResult`, `Stats`, etc.) now return `np.float64` instead of `np.float32`.
5050
- `betweenness_od` now accepts an optional `tolerance` parameter.
5151
- `closeness_shortest` and `closeness_simplest` now accept an optional `tolerance` parameter.
5252
- Bug fix: `is_dual` graph attribute was incorrectly cast via `CRS()` instead of `bool()` in `nx_remove_dangling_nodes` and `nx_merge_parallel_edges`.

analysis/od/prototype_od_weighted.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696

9797
# %% Run standard centrality
9898

99-
nodes_std = networks.node_centrality_shortest(
99+
nodes_std = networks.centrality_shortest(
100100
net,
101101
nodes_gdf.copy(),
102102
distances=DISTANCES,

analysis/sampling/paper/main.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ \section{Technical Details}
429429
\begin{verbatim}
430430
from cityseer.metrics import networks
431431
432-
gdf = networks.node_centrality_shortest(
432+
gdf = networks.centrality_shortest(
433433
network_structure,
434434
nodes_gdf,
435435
distances=[500,1000,2000,5000,10000,20000],

docs/plots/plots.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
G = graphs.nx_simple_geoms(G)
2525
G = graphs.nx_decompose(G, 20)
2626
nodes_gdf, _edges_gdf, network_structure = io.network_structure_from_nx(G)
27-
nodes_gdf = networks.segment_centrality(network_structure=network_structure, nodes_gdf=nodes_gdf, distances=[400, 800])
27+
nodes_gdf = networks.centrality_shortest(network_structure=network_structure, nodes_gdf=nodes_gdf, distances=[400, 800])
2828
data_gdf = mock.mock_landuse_categorical_data(G, random_seed=25)
2929
nodes_gdf, data_gdf = layers.compute_mixed_uses(
3030
data_gdf,
@@ -34,7 +34,7 @@
3434
distances=[400, 800],
3535
)
3636
# custom colourmap
37-
segment_harmonic_vals = nodes_gdf["cc_seg_harmonic_800"]
37+
segment_harmonic_vals = nodes_gdf["cc_harmonic_800"]
3838
mixed_uses_vals = nodes_gdf["cc_hill_q0_800"]
3939
cmap = colors.LinearSegmentedColormap.from_list("cityseer", ["#64c1ff", "#d32f2f"])
4040
segment_harmonic_vals = colors.Normalize()(segment_harmonic_vals)
@@ -157,7 +157,7 @@ def simple_plot(_G, _path, plot_geoms=True):
157157
G = graphs.nx_simple_geoms(G)
158158
G = graphs.nx_decompose(G, 50)
159159
nodes_gdf, edges_gdf, network_structure = io.network_structure_from_nx(G)
160-
networks.node_centrality_shortest(network_structure=network_structure, nodes_gdf=nodes_gdf, distances=[800])
160+
networks.centrality_shortest(network_structure=network_structure, nodes_gdf=nodes_gdf, distances=[800])
161161
G_after = io.nx_from_cityseer_geopandas(nodes_gdf, edges_gdf)
162162
# let's extract and normalise the values
163163
vals = []

docs/src/pages/api/network.md

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ print(cn_restored.nodes_gdf["cc_harmonic_800"])
10731073
</div>
10741074

10751075

1076-
Compute shortest-path (metric) node centrality. Wraps [`node_centrality_shortest`](/metrics/networks#node-centrality-shortest). All keyword arguments are forwarded; see that function for the full parameter list including ``distances``, ``minutes``, ``compute_closeness``, ``compute_betweenness``, ``decay_fn``, ``sample``, and ``epsilon``.
1076+
Compute shortest-path (metric) centrality. Wraps [`centrality_shortest`](/metrics/networks#centrality-shortest). All keyword arguments are forwarded; see that function for the full parameter list including ``distances``, ``minutes``, ``compute_closeness``, ``compute_betweenness``, ``decay_fn``, ``sample``, and ``epsilon``.
10771077
### Returns
10781078
<div class="param-set">
10791079
<div class="def">
@@ -1146,7 +1146,7 @@ cn.centrality_shortest(minutes=[5, 10, 20])
11461146
</div>
11471147

11481148

1149-
Compute simplest-path (angular) node centrality. Wraps [`node_centrality_simplest`](/metrics/networks#node-centrality-simplest). All keyword arguments are forwarded; see that function for the full parameter list.
1149+
Compute simplest-path (angular) centrality. Wraps [`centrality_simplest`](/metrics/networks#centrality-simplest). All keyword arguments are forwarded; see that function for the full parameter list.
11501150

11511151
This method does not accept a ``decay_fn`` parameter; angular centralities use angular cost rather than distance-based decay.
11521152
### Returns
@@ -1180,44 +1180,6 @@ cn.centrality_simplest(distances=[400, 800, 1600])
11801180

11811181

11821182

1183-
<div class="function">
1184-
1185-
## segment_centrality
1186-
1187-
1188-
<div class="content">
1189-
<span class="name">segment_centrality</span><div class="signature multiline">
1190-
<span class="pt">(</span>
1191-
<div class="param">
1192-
<span class="pn">self</span>
1193-
</div>
1194-
<div class="param">
1195-
<span class="pn">**kwargs</span>
1196-
</div>
1197-
<span class="pt">)-&gt;[</span>
1198-
<span class="pr">CityNetwork</span>
1199-
<span class="pt">]</span>
1200-
</div>
1201-
</div>
1202-
1203-
1204-
Compute segment-based centrality. Wraps [`segment_centrality`](/metrics/networks#segment-centrality). All keyword arguments are forwarded; see that function for the full parameter list.
1205-
### Returns
1206-
<div class="param-set">
1207-
<div class="def">
1208-
<div class="name">self</div>
1209-
<div class="type">CityNetwork</div>
1210-
</div>
1211-
<div class="desc">
1212-
1213-
Returns self for method chaining. Results are written to ``nodes_gdf``.</div>
1214-
</div>
1215-
1216-
1217-
</div>
1218-
1219-
1220-
12211183
<div class="function">
12221184

12231185
## build_od_matrix

docs/src/pages/guide.md

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ Centrality metrics quantify the structural importance of each location in the st
154154

155155
### Shortest-path centrality
156156

157-
[`centrality_shortest`](/api/network#centrality-shortest) (or [`node_centrality_shortest`](/metrics/networks#node-centrality-shortest) in the lower-level API) computes the following metrics for each distance threshold `d`:
157+
[`centrality_shortest`](/api/network#centrality-shortest) (or [`centrality_shortest`](/metrics/networks#centrality-shortest) in the lower-level API) computes the following metrics for each distance threshold `d`:
158158

159159
| Column | Description |
160160
| --- | --- |
@@ -169,7 +169,7 @@ Centrality metrics quantify the structural importance of each location in the st
169169

170170
### Simplest-path centrality
171171

172-
[`centrality_simplest`](/api/network#centrality-simplest) (or [`node_centrality_simplest`](/metrics/networks#node-centrality-simplest)) computes angular centrality metrics. Note the `_ang` suffix:
172+
[`centrality_simplest`](/api/network#centrality-simplest) (or [`centrality_simplest`](/metrics/networks#centrality-simplest) in the lower-level API) computes angular centrality metrics. Note the `_ang` suffix:
173173

174174
| Column | Description |
175175
| --- | --- |
@@ -372,13 +372,7 @@ The [`add_gtfs`](/api/network#add-gtfs) method integrates public transport stops
372372

373373
## Performance and Scale
374374

375-
The underlying algorithms are parallelised in Rust and scale to large networks. Typical performance on a modern laptop (8 cores):
376-
377-
- **10,000 edges** at 3 distance thresholds: seconds
378-
- **50,000 edges** at 5 distance thresholds: under a minute
379-
- **200,000+ edges** at long distances: minutes; consider [adaptive sampling](#adaptive-sampling) for 5 km+ thresholds
380-
381-
Computation time scales with the number of edges, the number of distance thresholds, and the reachability at each threshold. Simplest-path (angular) centrality is typically faster than shortest-path because angular routing produces sparser traversal trees.
375+
The underlying algorithms are parallelised in Rust and scale to large networks. Computation scales with the number of edges, the number of distance thresholds, and the reachability at each threshold. Simplest-path (angular) centrality is typically faster than shortest-path because angular routing produces sparser traversal trees. For large networks at long distance thresholds, consider [adaptive sampling](#adaptive-sampling).
382376

383377
## Adaptive Sampling
384378

0 commit comments

Comments
 (0)