Morphology Module¶
The morphology module provides functions for creating morphological graphs from urban form data, capturing spatial relationships between place spaces (e.g., tessellation cells) and movement spaces (e.g., street segments).
Module for creating morphological graphs from urban data.
This module provides comprehensive functionality for analyzing urban morphology through graph representations, focusing on the relationships between place spaces (buildings and their tessellations) and movement spaces (street segments). It creates heterogeneous graphs that capture the complex spatial relationships inherent in urban environments. Both GeoDataFrame and NetworkX objects can be converted to PyTorch Geometric Data or HeteroData by functions from graph.py.
The module specializes in three types of spatial relationships: 1. Place-to-place: Adjacency relationships between building tessellations 2. Movement-to-movement: Topological connectivity between street segments 3. Place-to-movement: Interface relationships between place and movement spaces
Functions:
| Name | Description |
|---|---|
morphological_graph | Create a morphological graph from buildings and street segments. |
place_to_place_graph | Create edges between contiguous place polygons based on spatial adjacency. |
place_to_movement_graph | Create edges between place polygons and nearby movement geometries. |
movement_to_movement_graph | Create edges between connected movement segments based on topological connectivity. |
segments_to_graph | Convert a GeoDataFrame of LineString segments into a graph structure. |
morphological_graph ¶
morphological_graph(
buildings_gdf,
segments_gdf,
center_point=None,
distance=None,
clipping_buffer=inf,
extent_buffer=100.0,
limit=None,
primary_barrier_col="barrier_geometry",
contiguity="queen",
keep_buildings=False,
keep_segments=True,
tolerance=1e-06,
include_unenclosed_buildings=False,
as_nx=False,
duplicate_edges=False,
non_movement_barrier_col=None,
tessellation_fallback=False,
tessellation_n_jobs=-1,
)
Create a morphological graph from buildings and street segments.
This function creates a comprehensive morphological graph that captures relationships between place spaces (building tessellations) and movement spaces (street segments). The graph includes three types of relationships: place-to-place adjacency, movement-to-movement connectivity, and place-to-movement interfaces.
The 'place_id' for tessellation cells is derived from 'tess_id' (generated by create_tessellation) or assigned sequentially if 'tess_id' doesn't directly map. The 'movement_id' for street segments is taken directly from the index of segments_gdf.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
buildings_gdf | GeoDataFrame | GeoDataFrame containing building polygons. Should contain Polygon or MultiPolygon geometries. | required |
segments_gdf | GeoDataFrame | GeoDataFrame containing street segments. Should contain LineString geometries. | required |
center_point | GeoSeries or GeoDataFrame | Center point(s) for spatial filtering. If provided with distance parameter, only segments within the specified distance will be included. | None |
distance | float | Maximum distance from | None |
clipping_buffer | float | Buffer distance to ensure adequate context for generating tessellation. Must be non-negative and not smaller than | math.inf |
extent_buffer | float | Maximum perpendicular access distance (a bounded catchment cap) from a street to a building/cell for it to be retained, and the maximum length of a | 100.0 |
limit | geopandas.GeoDataFrame, geopandas.GeoSeries, shapely geometry, or None | Boundary passed to | None |
primary_barrier_col | str | Column name containing alternative geometry for movement spaces. If specified and exists, this geometry will be used instead of the main geometry column for tessellation barriers. This only substitutes the geometry of a segment; it never removes a row from the movement layer, so every segment it applies to still becomes a movement node. To make individual rows act as barriers only (excluded from the movement layer), use | 'barrier_geometry' |
contiguity | str | Type of spatial contiguity for place-to-place connections. Must be either "queen" or "rook". | "queen" |
keep_buildings | bool | If True, preserves building information in the tessellation output. | False |
keep_segments | bool | If True, preserves the original segment LineString geometry in a column named 'segment_geometry' in the movement nodes GeoDataFrame. | True |
tolerance | float | Buffer distance for movement geometries when creating place-to-movement connections. This parameter controls how close place spaces need to be to movement spaces to establish a connection. | 1e-6 |
include_unenclosed_buildings | bool | If True, buildings excluded by enclosed tessellation are added using barrier-free tessellation before distance filters are applied. | False |
as_nx | bool | If True, convert the output to a NetworkX graph. | False |
duplicate_edges | bool | If True, the undirected same-type edge GeoDataFrames — ("place", "touched_to", "place") and ("movement", "connected_to", "movement") — contain both (u, v) and (v, u) rows (roughly doubling their row count), so neighbourhood queries on the MultiIndex are complete. The heterogeneous ("place", "faced_to", "movement") edges are left unchanged because a reverse row would mix movement ids into the place index level. Incompatible with | False |
non_movement_barrier_col | str | Name of a boolean column in | None |
tessellation_fallback | bool | If True and the enclosed tessellation encloses no area ( | False |
tessellation_n_jobs | int | Number of parallel jobs forwarded to the enclosed tessellation. Use | -1 |
Returns:
| Type | Description |
|---|---|
tuple[dict[str, GeoDataFrame], dict[tuple[str, str, str], GeoDataFrame]] | Graph | If as_nx is False (default), returns a tuple (nodes, edges) where:
If as_nx is True, returns a NetworkX graph. |
Raises:
| Type | Description |
|---|---|
TypeError | If buildings_gdf or segments_gdf are not GeoDataFrames. |
ValueError | If contiguity parameter is not "queen" or "rook". If clipping_buffer is negative. If |
See Also
morphological_graphs : Build graphs for several distances in one shared pass. place_to_place_graph : Create adjacency between place spaces. place_to_movement_graph : Create connections between place and movement spaces. movement_to_movement_graph : Create connectivity between movement spaces.
Notes
The function first filters the street network by distance (resulting in segs). A segs_buffer GeoDataFrame is also created for tessellation context, potentially filtered by distance + clipping_buffer or distance if center_point and distance are provided. This segs_buffer is used to create enclosures and tessellations. It then establishes three types of relationships: 1. Place-to-place: Adjacency between tessellation cells (handled by place_to_place_graph) 2. Movement-to-movement: Topological connectivity between street segments 3. Place-to-movement: Spatial interfaces between tessellations and streets
The output follows a heterogeneous graph structure suitable for network analysis of urban morphology.
Examples:
place_to_place_graph ¶
place_to_place_graph(
place_gdf,
group_col=None,
contiguity="queen",
as_nx=False,
duplicate_edges=False,
)
Create edges between contiguous place polygons based on spatial adjacency.
This function identifies spatial adjacency relationships between place polygons (e.g., tessellation cells) using either Queen or Rook contiguity criteria. Optionally groups connections within specified groups (e.g., enclosures). The input place_gdf is expected to have a 'place_id' column.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
place_gdf | GeoDataFrame | GeoDataFrame containing place space polygons. Must contain a 'place_id' column. | required |
group_col | str | Column name for grouping connections. Only polygons within the same group will be connected. If None, all polygons are considered as one group. | None |
contiguity | str | Type of spatial contiguity to use. Must be either "queen" or "rook". Queen contiguity includes vertex neighbors, Rook includes only edge neighbors. | "queen" |
as_nx | bool | If True, convert the output to a NetworkX graph. | False |
duplicate_edges | bool | If True, the edges GeoDataFrame contains both (u, v) and (v, u) rows for every undirected edge (roughly doubling the row count), with the 'from_place_id' and 'to_place_id' values swapped on reverse rows. Incompatible with | False |
Returns:
| Type | Description |
|---|---|
tuple[GeoDataFrame, GeoDataFrame] or Graph | If as_nx is False (default), returns a tuple (nodes, edges) where:
If as_nx is True, returns a networkx.Graph representing the place adjacency. |
Raises:
| Type | Description |
|---|---|
TypeError | If place_gdf is not a GeoDataFrame. |
ValueError | If contiguity not in {"queen", "rook"}, or if group_col doesn't exist. If |
See Also
morphological_graph : Main function that creates comprehensive morphological graphs. place_to_movement_graph : Create connections between place and movement spaces. movement_to_movement_graph : Create connectivity between movement spaces.
Notes
The function uses libpysal's spatial weights to determine adjacency relationships. Edge geometries are created as LineStrings connecting polygon centroids. Self-connections and duplicate edges are automatically filtered out. The input place_gdf is expected to have a 'place_id' column.
Examples:
place_to_movement_graph ¶
place_to_movement_graph(
place_gdf,
movement_gdf,
primary_barrier_col=None,
tolerance=1e-06,
as_nx=False,
max_connection_distance=inf,
duplicate_edges=False,
)
Create edges between place polygons and nearby movement geometries.
This function identifies spatial relationships between place spaces (tessellations) and movement spaces (street segments) by finding intersections between buffered movement geometries and place polygons. Input GDFs are expected to have 'place_id' and 'movement_id' columns respectively.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
place_gdf | GeoDataFrame | GeoDataFrame containing place space polygons. Expected to have a 'place_id' column. | required |
movement_gdf | GeoDataFrame | GeoDataFrame containing movement space geometries (typically LineStrings). Expected to have a 'movement_id' column. | required |
primary_barrier_col | str | Column name for alternative movement geometry. If specified and exists, this geometry will be used instead of the main geometry column. | None |
tolerance | float | Buffer distance for movement geometries to detect proximity to place spaces. | 1e-6 |
as_nx | bool | If True, convert the output to a NetworkX graph. | False |
max_connection_distance | float | Maximum distance for the nearest-movement fallback connection. Place cells matched by the | ``math.inf`` |
duplicate_edges | bool | If True, the edges GeoDataFrame contains both (u, v) and (v, u) rows for every edge (roughly doubling the row count). Note that on reverse rows the 'place_id' column holds a movement id and vice versa, because the endpoints are swapped. Incompatible with | False |
Returns:
| Type | Description |
|---|---|
tuple[GeoDataFrame, GeoDataFrame] or Graph | If as_nx is False (default), returns a tuple (nodes, edges) where:
If as_nx is True, returns a networkx.Graph representing the place-to-movement connections. |
Raises:
| Type | Description |
|---|---|
TypeError | If place_gdf or movement_gdf are not GeoDataFrames. |
ValueError | If 'place_id' or 'movement_id' columns are missing from input GDFs. If |
See Also
morphological_graph : Main function that creates comprehensive morphological graphs. place_to_place_graph : Create adjacency between place spaces. movement_to_movement_graph : Create connectivity between movement spaces.
Notes
Edge geometries are created as LineStrings connecting the centroids of place polygons and movement geometries. The function uses spatial joins to identify overlapping areas within the specified tolerance. Input GDFs are expected to have 'place_id' and 'movement_id' columns respectively.
Examples:
movement_to_movement_graph ¶
Create edges between connected movement segments based on topological connectivity.
This function identifies topological connections between movement space geometries (typically street segments) using the dual graph approach to find segments that share endpoints or connection points. The function automatically creates a unique identifier for each row if needed.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
movement_gdf | GeoDataFrame | GeoDataFrame containing movement space geometries (typically LineString). | required |
as_nx | bool | If True, convert the output to a NetworkX graph. | False |
duplicate_edges | bool | If True, the edges GeoDataFrame contains both (u, v) and (v, u) rows for every undirected edge (roughly doubling the row count), with the 'from_movement_id' and 'to_movement_id' values swapped on reverse rows. Incompatible with | False |
Returns:
| Type | Description |
|---|---|
tuple[GeoDataFrame, GeoDataFrame] or Graph | If as_nx is False (default), returns a tuple (nodes, edges) where:
If as_nx is True, returns a networkx.Graph representing the movement connectivity. |
Raises:
| Type | Description |
|---|---|
TypeError | If movement_gdf is not a GeoDataFrame. |
ValueError | If |
See Also
morphological_graph : Main function that creates comprehensive morphological graphs. place_to_place_graph : Create adjacency between place spaces. place_to_movement_graph : Create connections between place and movement spaces.
Notes
The function uses the dual graph approach where each LineString becomes a node, and edges represent topological connections between segments. Edge geometries are created as LineStrings connecting the centroids of connected segments.
Examples:
segments_to_graph ¶
Convert a GeoDataFrame of LineString segments into a graph structure.
This function takes a GeoDataFrame of LineStrings and processes it into a topologically explicit graph representation, consisting of a GeoDataFrame of unique nodes (the endpoints of the lines) and a GeoDataFrame of edges.
The resulting nodes GeoDataFrame contains unique points representing the start and end points of the input line segments. The edges GeoDataFrame is a copy of the input, but with a new MultiIndex (from_node_id, to_node_id) that references the IDs in the new nodes GeoDataFrame. If multigraph is True (the default), an additional index level (edge_key) distinguishes multiple edges between the same pair of nodes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
segments_gdf | GeoDataFrame | A GeoDataFrame where each row represents a line segment, and the 'geometry' column contains LineString objects. | required |
multigraph | bool | If True, supports multiple edges between the same pair of nodes by adding an .. versionchanged:: 0.4 The default changed from | True |
directed | bool | If True, edge orientation follows the LineString draw order: the first coordinate becomes | True |
as_nx | bool | If True, returns a NetworkX graph instead of a tuple of GeoDataFrames. | False |
Returns:
| Type | Description |
|---|---|
tuple[GeoDataFrame, GeoDataFrame] | A tuple containing two GeoDataFrames:
|
Raises:
| Type | Description |
|---|---|
ValueError | If |
See Also
city2graph.canonicalize_edges : Collapse reciprocal/parallel edge rows.
Examples:
>>> import geopandas as gpd
>>> from shapely.geometry import LineString
>>> # Create a GeoDataFrame of line segments
>>> segments = gpd.GeoDataFrame(
... {"road_name": ["A", "B"]},
... geometry=[LineString([(0, 0), (1, 1)]), LineString([(1, 1), (1, 0)])],
... crs="EPSG:32633"
... )
>>> # Convert to graph representation
>>> nodes_gdf, edges_gdf = segments_to_graph(segments)
>>> print(nodes_gdf)
>>> print(edges_gdf)
node_id geometry
0 POINT (0 0)
1 POINT (1 1)
2 POINT (1 0)
road_name geometry
from_node_id to_node_id edge_key
0 1 0 A LINESTRING (0 0, 1 1)
1 2 0 B LINESTRING (1 1, 1 0)
>>> # Duplicate connections become parallel edges with distinct keys
>>> segments_with_duplicates = gpd.GeoDataFrame(
... {"road_name": ["A", "B", "C"]},
... geometry=[LineString([(0, 0), (1, 1)]),
... LineString([(0, 0), (1, 1)]),
... LineString([(1, 1), (1, 0)])],
... crs="EPSG:32633"
... )
>>> nodes_gdf, edges_gdf = segments_to_graph(segments_with_duplicates)
>>> print(edges_gdf.index.names)
['from_node_id', 'to_node_id', 'edge_key']
Deprecated¶
The following aliases emit a DeprecationWarning and delegate to the renamed functions above:
private_to_private_graph→place_to_place_graphprivate_to_public_graph→place_to_movement_graphpublic_to_public_graph→movement_to_movement_graph