Skip to content

City2Graph: Geospatial Graphs for Network Analysis and GNNs

City2Graph is a Python library that turns geospatial data into analysis-ready graphs. Build networks from buildings, streets, public transport feeds, origin–destination matrices, zones, and points of interest; analyse them with NetworkX or convert them to PyTorch Geometric for Graph Neural Networks (GNNs).

City2Graph logo

GitHub Stars PyPI version conda-forge Version PyPI Downloads DOI License Platform codecov Ruff

City2Graph provides one interface across GeoPandas, NetworkX, PyTorch Geometric, and rustworkx. It preserves geospatial geometries and attributes while converting between graph representations, so the same graph can support mapping, spatial network analysis, and machine-learning workflows.

City2Graph workflow from geospatial data to NetworkX and PyTorch Geometric graphs

For details, please read the paper published in Computers, Environment and Urban Systems.

City2Graph paper in Computers, Environment and Urban Systems

Sato, Y., Pietrostefani, E., Mahabir, R., & Arribas-Bel, D. (2026). City2Graph: A Python library for Heterogeneous Graph Neural Networks and spatial analysis in urban systems. Computers, Environment and Urban Systems, 130, 102492. https://doi.org/10.1016/j.compenvurbsys.2026.102492

@article{sato2026city2graph,
  title = {City2Graph: A Python library for Heterogeneous Graph Neural Networks and spatial analysis in urban systems},
  author = {Sato, Yuta and Pietrostefani, Elisabetta and Mahabir, Ron and Arribas-Bel, Daniel},
  journal = {Computers, Environment and Urban Systems},
  volume = {130},
  pages = {102492},
  year = {2026},
  issn = {0198-9715},
  doi = {10.1016/j.compenvurbsys.2026.102492},
  url = {https://www.sciencedirect.com/science/article/pii/S0198971526000943},
}

Quickstart

pip install city2graph

This installs the graph construction and spatial network analysis features. Install city2graph[cpu] or a CUDA extra when you also need PyTorch Geometric. See the installation guide for a package comparison, supported Python and CUDA versions, and conda-forge instructions.

import city2graph as c2g

# Buildings + street segments -> heterogeneous morphological graph
nodes, edges = c2g.morphological_graph(
    buildings_gdf, segments_gdf, center_point, distance=500
)

A morphological graph of 500m walking distance in Liverpool

import city2graph as c2g

gtfs = c2g.load_gtfs("itm_london_gtfs.zip")

# Stop-to-stop travel-time graph from a GTFS feed
nodes, edges = c2g.travel_summary_graph(
    gtfs, calendar_start="20250601", calendar_end="20250601"
)

A bus transportation graph in London

import city2graph as c2g

# OD matrix + zone geometries -> weighted spatial graph
nodes, edges = c2g.od_matrix_to_graph(
    od_df, zones_gdf,
    source_col="origin", target_col="destination",
    weight_cols=["flow"], zone_id_col="zone_id",
)

An OD matrix graph showing migration flows and degree centrality in England and Wales

import city2graph as c2g

# Proximity graphs over points of interest
knn_nodes, knn_edges = c2g.knn_graph(poi_gdf, k=5)
wax_nodes, wax_edges = c2g.waxman_graph(poi_gdf, r0=100, beta=0.5)

# Queen contiguity between polygonal zones
w_nodes, w_edges = c2g.contiguity_graph(wards_gdf, contiguity="queen")

Waxman graph of points of interest in Liverpool

import city2graph as c2g

# Compose relations: amenity -> segment -> segment -> amenity
metapaths = [[("amenity", "is_nearby", "segment"),
              ("segment", "connects", "segment"),
              ("segment", "is_nearby", "amenity")]]

nodes, edges = c2g.add_metapaths(
    (nodes, edges), metapaths, edge_attr="distance_m", edge_attr_agg="sum"
)

Animation showing metapath connections between amenities through street segments in Soho, London

import city2graph as c2g

# GeoPandas -> NetworkX
G = c2g.gdf_to_nx(nodes, edges)

# GeoPandas -> PyTorch Geometric
data = c2g.gdf_to_pyg(nodes, edges)

# PyTorch Geometric -> GeoPandas
nodes, edges = c2g.pyg_to_gdf(data)

# PyTorch Geometric -> NetworkX
G = c2g.pyg_to_nx(data)

# NetworkX -> rustworkx
G_rx = c2g.nx_to_rx(G_nx)

# rustworkx -> NetworkX
G_nx = c2g.rx_to_nx(G_rx)

Examples

Applied projects

Tutorials

Browse all examples →

Why City2Graph?

Turning a city into a graph is rarely the interesting part of the work. It usually means writing throwaway code to parse a feed, deciding what counts as a node, flattening geometries into indices, and then writing it all again in a different shape as soon as the analysis moves from mapping to centrality to a GNN. City2Graph removes that step.

  • A city is more than one network. Buildings, streets, transit stops, zones, and amenities can live in the same graph as distinct node and relation types rather than being collapsed into a single homogeneous network. That is the structure heterogeneous GNNs expect, and it keeps the question "which kind of thing is connected to which" answerable.
  • Build the graph once, use it everywhere. The same graph moves between GeoDataFrames, NetworkX, PyTorch Geometric Data and HeteroData, and rustworkx. Explore it in NetworkX, run heavy algorithms in rustworkx, train on it in PyTorch Geometric, and map the results, without rebuilding it for each tool or maintaining conversion code of your own.
  • Start from the data you already have. Overture Maps, OpenStreetMap-derived data, GTFS and GBFS feeds, origin–destination matrices, points of interest, and ordinary GIS layers are read directly, so a working graph is a few lines away rather than a preprocessing project.

FAQ

What data can City2Graph convert into graphs?

City2Graph supports buildings, street segments, tessellations, Overture Maps features, GTFS and GBFS feeds, origin–destination matrices, points of interest, polygonal zones, and existing GeoDataFrame or NetworkX graphs. The workflow table links each input to its builder and tutorial.

Is PyTorch required?

No. The core installation builds and analyses geospatial graphs with GeoPandas, NetworkX, and rustworkx without installing PyTorch. PyTorch and PyTorch Geometric are optional dependencies for GNN-ready Data and HeteroData tensors.

Can graphs be converted between GeoPandas, NetworkX, and PyTorch Geometric?

Yes. City2Graph supports round-trip conversion between GeoDataFrames, NetworkX, and PyTorch Geometric, including heterogeneous graphs. See the graph conversion API for the supported functions.

How does City2Graph relate to OSMnx?

OSMnx is a focused toolkit for downloading and analysing OpenStreetMap street networks. City2Graph can use street data from OSMnx and combines it with buildings, Overture Maps, transit, mobility, proximity, and heterogeneous graph workflows. The two libraries are complementary.

Sample workflow

Input or task Graph produced Main API Typical use Guide
Buildings, streets, and tessellations Heterogeneous urban morphology graph morphological_graph Urban form, walkability, GNN embeddings Morphology tutorial
GTFS public transport feed Stop-to-stop travel-time graph travel_summary_graph Accessibility, centrality, multimodal routing GTFS tutorial
GBFS shared-mobility JSON feeds DuckDB tables with station or vehicle point geometry load_gbfs Bike-share and shared-mobility preprocessing Transportation API
OD matrix or flow edge list Weighted mobility graph od_matrix_to_graph Migration, commuting, bike-sharing flows OD matrix tutorial
Points, polygons, or graph layers Proximity, contiguity, bridge, or containment graph knn_graph, contiguity_graph POI access, spatial interaction, zonal adjacency Proximity tutorial
Typed relations in a heterogeneous graph Metapath-derived edges add_metapaths Heterogeneous GNNs and composite relations Metapath tutorial
GeoDataFrames, NetworkX, PyG, or rustworkx Converted graph representation Graph conversion API Spatial analysis, fast graph algorithms, GNN training API reference