Network API¶
These helpers analyse OD data obtained through Mobility. Use Zones for geographic context and territorial mappings. For runnable examples, start with Network examples.
build_network()constructs a directed network from processed OD rows.NetworkSpecselects the weight column and self-loop policy.SparseMobilityNetworkholds the sparse matrix, zone IDs and flow audit.NodeIndexpreserves node order across independently built networks.symmetrize_network()combines directions using an explicit weight rule.
Build a network¶
- pyspainmobility.network.builder.build_network(data: str | Path | DataFrame | DataFrame | LazyFrame, *, spec: NetworkSpec | None = None, node_ids: Sequence[object] | None = None, node_index: NodeIndex | None = None, provenance: Mapping[str, object] | None = None) SparseMobilityNetwork[source]¶
Build a directed, weighted CSR network from processed OD observations.
Repeated OD rows, including observations from different dates, hours or categories, are summed for each origin-destination pair. Select the rows needed for your analysis before calling this function.
- Parameters:
data (str, pathlib.Path, pandas.DataFrame, polars.DataFrame or polars.LazyFrame) – A processed OD Parquet path, a pandas/Polars DataFrame, or a Polars LazyFrame. It must contain the columns named in
spec.spec (NetworkSpec, optional) – Weight column and self-loop policy. Defaults to directed sum aggregation with
weight='n_trips'andself_loops='keep'.node_ids (sequence, optional) – Optional complete, ordered node universe. It preserves the same row and column positions across independently built networks and includes nodes with no observed flows. With
None, observed endpoints are sorted lexicographically to create a deterministic index.node_index (NodeIndex, optional) – Optional
NodeIndexreplacingnode_ids. It associates the matrix with a zoning identifier/version and must not be combined withnode_ids.provenance (mapping, optional) – Optional audit context carried into the immutable network result.
- Returns:
Canonical CSR matrix, node IDs, and an audit trail. Missing or non-finite OD values are rejected rather than silently becoming a missing flow.
- Return type:
Examples
>>> import polars as pl >>> from pyspainmobility import build_network >>> od = pl.DataFrame({ ... "id_origin": ["A", "A"], "id_destination": ["B", "B"], ... "n_trips": [3.0, 2.0], ... }) >>> network = build_network(od) >>> network.total_weight 5.0 >>> network.to_edge_table().rows() [('A', 'B', 5.0)]
Construction options¶
- class pyspainmobility.network.model.NetworkSpec(origin: str = 'id_origin', destination: str = 'id_destination', weight: str = 'n_trips', directed: bool = True, aggregation: str = 'sum', self_loops: str = 'keep')[source]¶
Rules used to turn an OD table into a network.
Pass these options to
build_network()orbuild_temporal_network().- Parameters:
origin (str) – Origin ID column. Default is
'id_origin'.destination (str) – Destination ID column. Default is
'id_destination'.weight (str) – Additive flow column. Default is
'n_trips'. For total trip-kilometres, use'trips_total_length_km'.directed (bool) – Must be True. After construction, use
symmetrize_network()to combine directions with an explicit rule.aggregation (str) – Must be
'sum'; repeated OD observations are added together.self_loops ({'keep', 'drop'}) – Retain or exclude flows within the same zone. Default is
'keep'.
Examples
>>> from pyspainmobility import NetworkSpec >>> spec = NetworkSpec(weight="n_trips", self_loops="drop") >>> spec.self_loops 'drop'
Network result¶
- class pyspainmobility.network.model.SparseMobilityNetwork(adjacency: csr_array, node_ids: ndarray, metadata: NetworkMetadata, provenance: Mapping[str, object] | None = None, node_index: NodeIndex | None = None)[source]¶
A weighted mobility network with an immutable node contract.
node_ids[i]is the zone represented by row and columniinadjacency. The IDs are sorted lexicographically when inferred from the OD data, or retain the caller-provided order whennode_idsis supplied tobuild_network().- Variables:
adjacency (scipy.sparse.csr_array) – Read-only matrix of edge weights, with origins as rows and destinations as columns. Keep this representation sparse for large networks.
node_ids (numpy.ndarray) – Zone IDs in matrix order.
metadata (NetworkMetadata) – Weight field, construction rules and represented/excluded flow totals.
provenance (mapping) – Immutable context and transformation history;
audit()returns a serializable description.node_index (NodeIndex) – Shared node order and optional zoning identity.
- to_edge_table(origin: str = 'id_origin', destination: str = 'id_destination', weight: str = 'weight', *, sort: bool = True) DataFrame[source]¶
Return one row per non-zero connection as a Polars DataFrame.
- Parameters:
origin (str) – Output column names. Defaults are
'id_origin','id_destination'and'weight'; names must be distinct.destination (str) – Output column names. Defaults are
'id_origin','id_destination'and'weight'; names must be distinct.weight (str) – Output column names. Defaults are
'id_origin','id_destination'and'weight'; names must be distinct.sort (bool) – Sort by origin and destination IDs. Default is True.
- Returns:
Zone IDs and edge weights. Undirected pairs appear once, with endpoints ordered by their matrix positions.
- Return type:
polars.DataFrame
- align_to(target: SparseMobilityNetwork | NodeIndex) SparseMobilityNetwork[source]¶
Return this network reordered to a compatible target node index.
Combine flow directions¶
- pyspainmobility.network.transforms.symmetrize_network(network: SparseMobilityNetwork, *, method: Literal['sum', 'mean', 'max', 'mutual'] = 'sum') SparseMobilityNetwork[source]¶
Turn a directed OD network into an auditable undirected network.
The returned adjacency is symmetric, with one logical undirected edge per unordered node pair. The explicit rule determines its edge weight:
sum: total bilateral OD flow,A[i, j] + A[j, i];mean: mean bilateral OD flow, treating a missing direction as zero;max: strongest direction;mutual: weakest direction, removing non-reciprocal pairs.
Self-loops are preserved once under every rule. Provenance records both logical edge weight and stored symmetric-matrix weight, avoiding accidental double counting of off-diagonal edges.
- Parameters:
network (SparseMobilityNetwork) – Directed network to transform.
method ({'sum', 'mean', 'max', 'mutual'}) – Rule for combining the two directions, as defined above. Default is
'sum'.
- Returns:
Undirected network with the same node index.
total_weightandto_edge_table()count each undirected connection once.- Return type:
Examples
>>> import polars as pl >>> from pyspainmobility import build_network, symmetrize_network >>> od = pl.DataFrame({ ... "id_origin": ["A", "B"], "id_destination": ["B", "A"], ... "n_trips": [3.0, 2.0], ... }) >>> symmetrize_network(build_network(od), method="sum").to_edge_table().rows() [('A', 'B', 5.0)]