Library / SDK
c2g-dev/city2graph avatar
c2g-dev/city2graph

City2Graph decides which graph your city data becomes

Transform geospatial relations into graphs for Graph Neural Networks and spatial network analysis

1,947 stars205 forksPythonBSD-3-Clause

At a glance

What is it?
City2Graph is a Python library that converts buildings, streets, transit feeds, origin-destination matrices and points of interest into spatial and heterogeneous graphs, bridging GeoPandas, NetworkX and PyTorch Geometric. It fits urban analytics and GNN work, and it insists on Python 3.12 or newer with PyTorch kept as an optional extra.
Who is it for?
Adopt City2Graph when your analysis starts from raw urban geodata and you want the graph construction, the network and the GNN tensors to share one vocabulary, particularly for heterogeneous graphs with metapath edges. Do not adopt it on Python 3.11 or older, since requires-python is >=3.12,<3.15, and prefer pip over conda for any PyTorch work because the README states conda is no longer officially supported upstream.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The hard part of urban GNNs is choosing the graph, not learning on it

City2Graph's description says it transforms geospatial relations into graphs for graph neural networks and spatial network analysis. That framing matters, because the library's real work is a decision about representation. Two buildings can be neighbours by footprint adjacency, by walking distance, or by appearing in the same origin-destination flow, and those three graphs send a GNN completely different signal.

The input surface is wide: buildings, streets, tessellated urban fabric from OpenStreetMap and Overture Maps, GTFS public transport feeds, GBFS shared mobility feeds, origin-destination matrices covering migration, bike-sharing and pedestrian counts, zones, and points of interest. The output surface is two graph flavours, spatial graphs and heterogeneous graphs, plus the tensor formats a GNN trainer needs.

The declared audience in pyproject.toml is Science/Research, with keywords running from urban mobility to digital twins and geospatial foundation models. The classifiers mark it Development Status :: 5 - Production/Stable and Python 3.12, 3.13 and 3.14 only.

DuckDB sits under the transport side, GTFS collapses into stop-to-stop graphs

Transportation data is handled differently from the rest. GTFS and GBFS feeds are loaded into DuckDB, and GTFS is then aggregated into stop-to-stop transit graphs. That is a sensible separation: a feed is a set of relational tables that can be large and awkward to hold in memory, and pushing the filtering into a columnar engine keeps the pandas side small.

Mobility data takes the weighted-graph route. Origin-destination matrices and flow data, described as migration, bike-sharing and pedestrian counts, become weighted spatial graphs, where the weight is the observed flow rather than a computed distance.

The proximity and contiguity family is the other place choices accumulate. KNN, Delaunay, Gilbert and Waxman graphs cover distance-based relations, and queen and rook contiguity covers grid adjacency. Each of these can be built under Euclidean, Manhattan or network distance, which is the single most consequential parameter in the library. A Delaunay graph under Euclidean distance is a plausible urban adjacency structure; under network distance it is a different and more expensive computation that many city street networks make sparse.

The repository depends on shapely for geometry, geoPandas for frames, pyproj for projection, libpysal and momepy for spatial and urban morphology analysis, rustworkx for graph algorithms, scipy and numpy for numerics, and geopy for distances.

Heterogeneous graphs and metapaths for mixing node and edge types

A heterogeneous graph holds several node types and several edge types at once, and City2Graph adds metapath-derived edges, which compose relations across those types. In practice this is what lets a building be connected to a street, a transit stop to a zone, and then a zone to a zone through a flow record, all inside a single graph.

The consumer of that graph is PyTorch Geometric. The library describes round-trip conversion between GeoDataFrames, NetworkX graphs, and the Data and HeteroData objects, in both directions. Round trip is the useful word: you can start in a GeoDataFrame, drop into NetworkX for a centrality computation, and come back without rebuilding the graph by hand.

The dependency choice is interesting. Both networkx and rustworkx appear, and Both networkx and rustworkx are core dependencies. Carrying both means city2graph can serve an analysis-only workflow that never touches PyTorch, which is why the core install does not require torch at all.

Installation: pip by default, and the CUDA extras are not interchangeable

The core install is one command and deliberately excludes the deep learning stack:

bash
pip install city2graph

That gives you the graph construction and the NetworkX side without PyTorch and PyTorch Geometric. If you need GNN functionality on CPU, the README gives the extra:

bash
pip install "city2graph[cpu]"

For GPU you select a CUDA build explicitly, and the supported values are cu126, cu128 and cu130:

bash
pip install "city2graph[cu130]"

The subtlety worth flagging: the cpu, cu126 and cu130 extras use PyTorch 2.13 or newer, while cu128 is pinned to PyTorch 2.11 because PyTorch no longer publishes CUDA 12.8 wheels past 2.11. So the four extras do not resolve to the same torch version, and a project that upgrades between extras can see its torch version move under it.

The conda path exists, and it comes with a warning from the README. PyTorch and PyTorch Geometric are no longer officially supported through conda, and only conda-forge distributions are available, so with conda you install the two libraries yourself, matching the build string to your CUDA version. The README's own advice is to use pip or uv if you need PyTorch functionality. Build and test instructions live in the Contributing Guide, and development uses a uv.lock file.

Where the library stops, and the research citation requirement

This is a construction library, not an analysis or modelling one. It does not train GNNs, it does not define a model architecture, and it does not visualise results. The heaviest part of a typical project using it will be writing the model, the training loop and the evaluation yourself on top of the HeteroData it produces.

Data quality is the other limit. The README describes inputs and graph constructions but does not document schema validation for third-party feeds, and it does not document what happens when a feed is missing an optional table.

The citation requirement is unusually firm. The README states that any use in research or software must cite the paper by Sato, Pietrostefani, Mahabir and Arribas-Bel, published in Computers, Environment and Urban Systems, volume 130, article 102492, with a DOI of 10.1016/j.compenvurbsys.2026.102492. That is a requirement stated by the authors for use of the software, and the same record is kept in CITATION.cff. The license is BSD-3-Clause, which permits use in commercial software; the citation request is separate from the license terms, and honouring both is straightforward.

Release history and the cost of a fast moving dependency floor

Version 1.0.0 was tagged on 2026-08-01, preceded by v0.4.0 on 2026-06-11 and v0.3.1 on 2026-03-21. The last push was on 2026-10-10, so work is continuing after the 1.0 tag, and CHANGELOG.md in the repository root is where those changes are recorded.

The real upgrade cost here is not City2Graph's own version, it is the floor it sets on everything else. Every dependency carries a lower bound: geoPandas 1.1.1, shapely 2.1.0, libpysal 4.12.1, momepy 1.0.0, DuckDB 1.1.0, networkx 2.8, overturemaps 0.18.1, rustworkx 0.17.1, pyproj 3.5 and Python 3.12 through 3.14. Combined with a torch floor of 2.13 for the GPU and CPU extras, this pins you to recent versions of a long list of packages. If your existing environment holds an older geospatial stack, adopting city2graph means upgrading that stack too.

Development tooling is also visible: codecov.yml and a codecov badge, Ruff through a pre-commit config, and mkdocs.yml driving the documentation at city2graph.net with readthedocs configuration alongside it. A SECURITY.md exists for reporting, which is a reasonable signal for a library intended to be embedded in research pipelines.

Editorial conclusion

Adopt City2Graph when your analysis starts from raw urban geodata and you want the graph construction, the network and the GNN tensors to share one vocabulary, particularly for heterogeneous graphs with metapath edges. Do not adopt it on Python 3.11 or older, since requires-python is >=3.12,<3.15, and prefer pip over conda for any PyTorch work because the README states conda is no longer officially supported upstream. Before committing, pin an install with the CUDA extra matching your driver, check the cited paper in Computers, Environment and Urban Systems for the design rationale, and confirm your Overture Maps and GTFS inputs match the schema City2Graph expects.

Frequently asked questions

How do I install City2Graph with GPU support?

Install with the CUDA extra matching your driver, for example pip install "city2graph[cu130]". Supported extras are cu126, cu128 and cu130, and cu128 resolves to PyTorch 2.11 because PyTorch no longer publishes CUDA 12.8 wheels past 2.11.

What Python version does City2Graph require?

pyproject.toml sets requires-python to >=3.12,<3.15, and the classifiers list Python 3.12, 3.13 and 3.14. The README states City2Graph supports Python 3.12 to 3.14.

What kinds of graph can City2Graph build?

It builds graphs from OSM and Overture Maps buildings, streets and urban fabric, GTFS and GBFS feeds aggregated into stop-to-stop transit graphs, origin-destination and flow data as weighted graphs, proximity graphs including KNN, Delaunay, Gilbert and Waxman under Euclidean, Manhattan or network distance, and queen or rook contiguity graphs.

Do I need to cite a paper if I use City2Graph?

The README states that any use in research or software must cite Sato, Pietrostefani, Mahabir and Arribas-Bel, City2Graph: A Python library for Heterogeneous Graph Neural Networks and spatial analysis in urban systems, Computers, Environment and Urban Systems, volume 130, article 102492. The license itself is BSD-3-Clause.

Official sources

  1. c2g-dev/city2graph on GitHub
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/c2g-dev-city2graph.svg)](https://hysenlabs.com/projects/c2g-dev-city2graph)

Was this useful?