Skip to content

Morphology Module

The morphology module provides functions for creating morphological graphs from urban fabric data, capturing spatial relationships between buildings, streets, and public spaces.

Composite Graphs

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 private spaces (buildings and their tessellations) and public 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. Private-to-private: Adjacency relationships between building tessellations 2. Public-to-public: Topological connectivity between street segments 3. Private-to-public: Interface relationships between private and public spaces

Functions:

Name Description
morphological_graph

Create a morphological graph from buildings and street segments.

morphological_graph

morphological_graph(
    buildings_gdf,
    segments_gdf,
    center_point=None,
    distance=None,
    clipping_buffer=inf,
    primary_barrier_col="barrier_geometry",
    contiguity="queen",
    keep_buildings=False,
    keep_segments=True,
    tolerance=1e-06,
    as_nx=False,
)

Create a morphological graph from buildings and street segments.

This function creates a comprehensive morphological graph that captures relationships between private spaces (building tessellations) and public spaces (street segments). The graph includes three types of relationships: private-to-private adjacency, public-to-public connectivity, and private-to-public interfaces.

The 'private_id' for tessellation cells is derived from 'tess_id' (generated by create_tessellation) or assigned sequentially if 'tess_id' doesn't directly map. The 'public_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 center_point for spatial filtering. When specified, street segments beyond this shortest-path distance are removed and tessellation cells are kept only if their own distance via these segments does not exceed this value.

None
clipping_buffer float

Buffer distance to ensure adequate context for generating tessellation. Must be non-negative.

math.inf
primary_barrier_col str

Column name containing alternative geometry for public spaces. If specified and exists, this geometry will be used instead of the main geometry column for tessellation barriers.

'barrier_geometry'
contiguity str

Type of spatial contiguity for private-to-private 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 public nodes GeoDataFrame.

True
tolerance float

Buffer distance for public geometries when creating private-to-public connections. This parameter controls how close private spaces need to be to public spaces to establish a connection.

1e-6
as_nx bool

If True, convert the output to a NetworkX graph.

False

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:

  • nodes: Dictionary containing node GeoDataFrames with keys:

    • "private": Tessellation cells (private spaces)
    • "public": Street segments (public spaces)
  • edges: Dictionary containing edge GeoDataFrames with keys:

    • ("private", "touched_to", "private"): Adjacency between tessellation cells
    • ("public", "connected_to", "public"): Connectivity between street segments
    • ("private", "faced_to", "public"): Interface between tessellation cells and street segments

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.

See Also

private_to_private_graph : Create adjacency between private spaces. private_to_public_graph : Create connections between private and public spaces. public_to_public_graph : Create connectivity between public 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. Private-to-private: Adjacency between tessellation cells (handled by private_to_private_graph) 2. Public-to-public: Topological connectivity between street segments 3. Private-to-public: Spatial interfaces between tessellations and streets

The output follows a heterogeneous graph structure suitable for network analysis of urban morphology.

Examples:

>>> # Create morphological graph from buildings and segments
>>> nodes, edges = morphological_graph(buildings_gdf, segments_gdf)
>>> private_nodes = nodes['private']
>>> public_nodes = nodes['public']

Component Graphs

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 private spaces (buildings and their tessellations) and public 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. Private-to-private: Adjacency relationships between building tessellations 2. Public-to-public: Topological connectivity between street segments 3. Private-to-public: Interface relationships between private and public spaces

Functions:

Name Description
private_to_private_graph

Create edges between contiguous private polygons based on spatial adjacency.

private_to_public_graph

Create edges between private polygons and nearby public geometries.

public_to_public_graph

Create edges between connected public segments based on topological connectivity.

segments_to_graph

Convert a GeoDataFrame of LineString segments into a graph structure.

private_to_private_graph

private_to_private_graph(
    private_gdf, group_col=None, contiguity="queen", as_nx=False
)

Create edges between contiguous private polygons based on spatial adjacency.

This function identifies spatial adjacency relationships between private polygons (e.g., tessellation cells) using either Queen or Rook contiguity criteria. Optionally groups connections within specified groups (e.g., enclosures). The input private_gdf is expected to have a 'private_id' column.

Parameters:

Name Type Description Default
private_gdf GeoDataFrame

GeoDataFrame containing private space polygons. Must contain a 'private_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

Returns:

Type Description
tuple[GeoDataFrame, GeoDataFrame] or Graph

If as_nx is False (default), returns a tuple (nodes, edges) where:

  • nodes is a geopandas.GeoDataFrame containing the private nodes.
  • edges is a geopandas.GeoDataFrame containing the adjacency connections.

If as_nx is True, returns a networkx.Graph representing the private adjacency.

Raises:

Type Description
TypeError

If private_gdf is not a GeoDataFrame.

ValueError

If contiguity not in {"queen", "rook"}, or if group_col doesn't exist.

See Also

morphological_graph : Main function that creates comprehensive morphological graphs. private_to_public_graph : Create connections between private and public spaces. public_to_public_graph : Create connectivity between public 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 private_gdf is expected to have a 'private_id' column.

Examples:

>>> # Create private-to-private adjacency graph
>>> nodes, edges = private_to_private_graph(tessellation_gdf)
>>> # With grouping by enclosures
>>> nodes, edges = private_to_private_graph(tessellation_gdf, group_col='enclosure_id')

private_to_public_graph

private_to_public_graph(
    private_gdf,
    public_gdf,
    primary_barrier_col=None,
    tolerance=1e-06,
    as_nx=False,
)

Create edges between private polygons and nearby public geometries.

This function identifies spatial relationships between private spaces (tessellations) and public spaces (street segments) by finding intersections between buffered public geometries and private polygons. Input GDFs are expected to have 'private_id' and 'public_id' columns respectively.

Parameters:

Name Type Description Default
private_gdf GeoDataFrame

GeoDataFrame containing private space polygons. Expected to have a 'private_id' column.

required
public_gdf GeoDataFrame

GeoDataFrame containing public space geometries (typically LineStrings). Expected to have a 'public_id' column.

required
primary_barrier_col str

Column name for alternative public geometry. If specified and exists, this geometry will be used instead of the main geometry column.

None
tolerance float

Buffer distance for public geometries to detect proximity to private spaces.

1e-6
as_nx bool

If True, convert the output to a NetworkX graph.

False

Returns:

Type Description
tuple[GeoDataFrame, GeoDataFrame] or Graph

If as_nx is False (default), returns a tuple (nodes, edges) where:

  • nodes is a geopandas.GeoDataFrame containing the combined private and public nodes.
  • edges is a geopandas.GeoDataFrame containing the edges between private and public geometries.

If as_nx is True, returns a networkx.Graph representing the private-to-public connections.

Raises:

Type Description
TypeError

If private_gdf or public_gdf are not GeoDataFrames.

ValueError

If 'private_id' or 'public_id' columns are missing from input GDFs.

See Also

morphological_graph : Main function that creates comprehensive morphological graphs. private_to_private_graph : Create adjacency between private spaces. public_to_public_graph : Create connectivity between public spaces.

Notes

Edge geometries are created as LineStrings connecting the centroids of private polygons and public geometries. The function uses spatial joins to identify overlapping areas within the specified tolerance. Input GDFs are expected to have 'private_id' and 'public_id' columns respectively.

Examples:

>>> # Create private-to-public interface graph
>>> nodes, edges = private_to_public_graph(tessellation_gdf, segments_gdf)
>>> # With custom tolerance
>>> nodes, edges = private_to_public_graph(tessellation_gdf, segments_gdf, tolerance=2.0)

public_to_public_graph

public_to_public_graph(public_gdf, as_nx=False)

Create edges between connected public segments based on topological connectivity.

This function identifies topological connections between public 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
public_gdf GeoDataFrame

GeoDataFrame containing public space geometries (typically LineString).

required
as_nx bool

If True, convert the output to a NetworkX graph.

False

Returns:

Type Description
tuple[GeoDataFrame, GeoDataFrame] or Graph

If as_nx is False (default), returns a tuple (nodes, edges) where:

  • nodes is a geopandas.GeoDataFrame containing the public nodes.
  • edges is a geopandas.GeoDataFrame containing the topological connections.

If as_nx is True, returns a networkx.Graph representing the public connectivity.

Raises:

Type Description
TypeError

If public_gdf is not a GeoDataFrame.

See Also

morphological_graph : Main function that creates comprehensive morphological graphs. private_to_private_graph : Create adjacency between private spaces. private_to_public_graph : Create connections between private and public 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:

>>> # Create public-to-public connectivity graph
>>> nodes, edges = public_to_public_graph(segments_gdf)
>>> # Convert to NetworkX format
>>> graph = public_to_public_graph(segments_gdf, as_nx=True)

segments_to_graph

segments_to_graph(segments_gdf, multigraph=False, as_nx=False)

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 and there are multiple edges between the same pair of nodes, an additional index level (edge_key) is added to distinguish them.

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 edge_key level to the MultiIndex. This is useful when the input contains duplicate node-to-node connections that should be preserved as separate edges.

False
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:

  • nodes_gdf: A GeoDataFrame of unique nodes (Points), indexed by node_id.
  • edges_gdf: A GeoDataFrame of edges (LineStrings), with a MultiIndex mapping to the node_id in nodes_gdf. If multigraph is True, the index includes a third level (edge_key) for duplicate connections.

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
0            1                  A           LINESTRING (0 0, 1 1)
1            2                  B           LINESTRING (1 1, 1 0)
>>> # Example with duplicate connections (multigraph)
>>> 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, multigraph=True)
>>> print(edges_gdf.index.names)
['from_node_id', 'to_node_id', 'edge_key']