Open In Colab

Setting live or non-live nodes

Set a node’s status to live=True or live=False based on whether it intersects the original boundary.

This is used for demarcating nodes that fall within the original unbuffered boundary when calculating measures. This allows for the original boundary to be delineated from the buffered surrounding extents, which is normally included for purposes of avoiding edge rolloff. The algorithms will continue to consider parts of the network where nodes are not live (therefore preventing edge rolloff), but will not compute metrics for these nodes (reducing unnecessary computation).

import matplotlib.pyplot as plt
from cityseer.metrics import networks
from cityseer.tools import graphs, io
from shapely import geometry

When using this approach it is best to work in a projector coordinate reference system. In this example we will cast the buffered point polygon to projected CRS by using the projected=True parameter.

lng, lat = -0.13396079424572427, 51.51371088849723
buffer = 500
poly_utm, epsg_code = io.buffered_point_poly(lng, lat, buffer, projected=True)
poly_utm

Since the Polygon is in a projected CRS, the buffering step can proceed with a distance defined in metres. Here the Polygon is buffered by 400m since this is the maximum distance considered for the centrality analysis in the next step.

pol_buff = poly_utm.buffer(400)
pol_buff

The buffer polygon can then be used as an argument for retrieving the OSM network. The poly_crs_code and to_crs_code parameters need to be set so that the function knows which CRS the input geometry is in, and which CRS to convert the network to.

G = io.osm_graph_from_poly(pol_buff, poly_crs_code=epsg_code, to_crs_code=epsg_code)
INFO:cityseer.tools.graphs:Generating interpolated edge geometries.
WARNING:cityseer.tools.util:The to_crs_code parameter 4326 is not a projected CRS
INFO:cityseer.tools.io:Converting networkX graph to CRS code 32630.
WARNING:cityseer.tools.util:The to_crs_code parameter 4326 is not a projected CRS
INFO:cityseer.tools.io:Processing node x, y coordinates.
INFO:cityseer.tools.io:Processing edge geom coordinates, if present.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.graphs:Removing dangling nodes.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Splitting opposing edges.
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Splitting opposing edges.
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Splitting opposing edges.
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Splitting opposing edges.
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.util:Creating nodes STR tree
INFO:cityseer.tools.graphs:Consolidating nodes.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.util:Creating nodes STR tree
INFO:cityseer.tools.graphs:Consolidating nodes.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.util:Creating nodes STR tree
INFO:cityseer.tools.graphs:Consolidating nodes.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.util:Creating nodes STR tree
INFO:cityseer.tools.graphs:Consolidating nodes.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.util:Creating nodes STR tree
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Snapping gapped endings.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Splitting opposing edges.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.graphs:Removing dangling nodes.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Splitting opposing edges.
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.util:Creating nodes STR tree
INFO:cityseer.tools.graphs:Consolidating nodes.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.util:Creating edges STR tree.
INFO:cityseer.tools.graphs:Splitting opposing edges.
INFO:cityseer.tools.graphs:Squashing opposing nodes
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.util:Creating nodes STR tree
INFO:cityseer.tools.graphs:Consolidating nodes.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 25.
INFO:cityseer.tools.graphs:Removing filler nodes.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 50.
INFO:cityseer.tools.graphs:Ironing edges.
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 1.
INFO:cityseer.tools.graphs:Removing dangling nodes.
INFO:cityseer.tools.graphs:Removing filler nodes.

Since the network and the source geometry are in the same CRS, it is possible to demarcate each node as either live=True or live=False based on whether it intersects the original geometry.

This can be done by iterating through the nodes and checking if they intersect the original geometry. If they do, the node is set to live=True, otherwise it is set to live=False.

for node_idx, node_data in G.nodes(data=True):
    node_pnt = geometry.Point(node_data["x"], node_data["y"])
    if node_pnt.intersects(poly_utm):
        G.nodes[node_idx]["live"] = True
    else:
        G.nodes[node_idx]["live"] = False

Metrics can then be computed based on the target distance without encountering edge roll-off.

G_dual = graphs.nx_to_dual(G)
nodes_gdf, _edges_gdf, network_structure = io.network_structure_from_nx(
    G_dual,
)
distances = [400]
nodes_gdf = networks.node_centrality_shortest(
    network_structure=network_structure,
    nodes_gdf=nodes_gdf,
    distances=distances,
)
nodes_gdf.head()
INFO:cityseer.tools.graphs:Converting graph to dual.
INFO:cityseer.tools.graphs:Preparing dual nodes
INFO:cityseer.tools.graphs:Preparing dual edges (splitting and welding geoms)
INFO:cityseer.tools.io:Preparing node and edge arrays from networkX graph.
INFO:cityseer.graph:Edge R-tree built successfully with 3198 items.
INFO:cityseer.metrics.networks:Computing node centrality (shortest).
INFO:cityseer.metrics.networks:  Full: 400m
ns_node_idx x y z live weight primal_edge primal_edge_node_a primal_edge_node_b primal_edge_idx dual_node cc_beta_400 cc_cycles_400 cc_density_400 cc_farness_400 cc_harmonic_400 cc_hillier_400 cc_betweenness_400 cc_betweenness_beta_400
25257319_25257320_k0 0 698204.726812 5.710187e+06 None False 1 LINESTRING (698235.492 5710213.589, 698232.233... 25257320 25257319 0 POINT (698204.726812 5710187.371082) 0.000000 0.0 0.0 0.000000 0.000000 NaN 0.0 0.000000
108252_25257054_k0 1 698153.737591 5.710642e+06 None False 1 LINESTRING (698138.426 5710664.248, 698144.086... 108252 25257054 0 POINT (698153.737591 5710641.557264) 0.240003 1363.0 8.0 2832.212830 0.022721 0.022597 1.0 0.020966
108252_452229727_k0 2 698123.239970 5.710685e+06 None False 1 LINESTRING (698138.426 5710664.248, 698133.018... 108252 452229727 0 POINT (698123.23997 5710685.118712) 0.262115 1514.0 9.0 3219.641663 0.025323 0.025158 9.0 0.202300
108252_57552|08253±12391|03078_k0 3 698120.890901 5.710655e+06 None False 1 LINESTRING (698103.385 5710645.919, 698131.137... 108252 57552|08253±12391|03078 0 POINT (698120.890901 5710655.116857) 0.297685 1690.0 10.0 3560.291626 0.028296 0.028088 9.0 0.217308
108252_30694|56840±12373|16592±10825|56840_k0 4 698183.290484 5.710684e+06 None False 1 LINESTRING (698228.148 5710703.651, 698222.24 ... 108252 30694|56840±12373|16592±10825|56840 0 POINT (698183.290484 5710683.927691) 0.864444 3412.0 20.0 6498.006531 0.062889 0.061557 46.0 1.240377

Measures will only have been computed for live nodes.

fig, ax = plt.subplots(1, 1, figsize=(8, 6), facecolor="#1d1d1d")
nodes_gdf.plot(
    column="cc_harmonic_400",
    cmap="magma",
    legend=False,
    ax=ax,
)
ax.axis(False)
(np.float64(697663.4586927991),
 np.float64(699980.0625239151),
 np.float64(5709670.722888798),
 np.float64(5711930.195587498))

To print or save only live nodes, filter the data frame accordingly.

fig, ax = plt.subplots(1, 1, figsize=(8, 6), facecolor="#1d1d1d")
nodes_filtered = nodes_gdf[nodes_gdf.live]
nodes_filtered.plot(
    column="cc_harmonic_400",
    cmap="magma",
    legend=False,
    ax=ax,
)
ax.axis(False)
(np.float64(698266.6364452019),
 np.float64(699469.3803111856),
 np.float64(5710223.021892861),
 np.float64(5711471.024025262))

Summary

This notebook demonstrated how to set live=True or live=False on network nodes based on whether they fall within the original (unbuffered) study area boundary. This prevents edge rolloff effects: the algorithms can route through the buffer zone, but metrics are only computed for live nodes within the study area.

Next steps: