Contributing guidelines
Documentation
Existing issues
Describe the bug
The contiguity_graph(..., as_nx=False) method returns an edges_gdf in which each contiguity edge appears only once, with the smaller (in the order of the type) node id as the first MultiIndex level. The total edge count is correct for undirected edges. However, when transformed into a PyG graph, the edge table is assumed to be undirected, leading to missing edges.
PyG treats every row of edge_index as a directed edge. The edge_index is a 2 x |E| matrix where (under the default flow="source_to_target") the messages from the nodes in edge_index[0] are sent to nodes in edge_index[1]. With gdf_to_pyg, level 0 of the multi-index becomes the source and level 1 becomes the target node that receives the message. As each edge appears only once in the edge table, only one direction is included in the resulting edge_index.
To Reproduce
import geopandas as gpd
import pandas as pd
from shapely.geometry import Polygon
import city2graph as c2g
# Create simple geodataframe
polys, codes = [], []
for r in range(4):
for c in range(4):
polys.append(Polygon([(c, r), (c + 1, r), (c + 1, r + 1), (c, r + 1)]))
codes.append(f"id{r}{c}")
gdf = (
gpd.GeoDataFrame({"v": range(16)}, geometry=polys, crs="EPSG:27700")
.set_index(pd.Index(codes, name="id"))
)
# Plot
ax = gdf.plot(color="lightgray", categorical=True, edgecolor="black")
for idx, row in gdf.iterrows():
ax.annotate(idx, xy=(row.geometry.centroid.x, row.geometry.centroid.y),
ha="center", va="center")
ax.set_axis_off()
nodes, edges = c2g.contiguity_graph(gdf, contiguity="queen", as_nx=False)
pyg_graph = c2g.gdf_to_pyg(nodes, edges=edges)
# Check output, using id22 as an example
print("\n\nEdges with id22 as level 0 in the multi-index", flush=True)
print(edges.xs("id22", level=0), flush=True)
print("\n\nEdges with id22 as focal", flush=True)
print(pyg_graph.edge_index[:, pyg_graph.edge_index[0] == nodes.loc["id22"]["v"]], flush=True)
# Plot id22 and its neighbors where id22 is level 0 in the multi-index
id22_edges = edges.xs("id22", level=0)
ax = gdf.plot(color="lightgray", categorical=True, edgecolor="black")
nodes[nodes.index.isin(id22_edges.index)].plot(ax=ax, color="tab:orange")
nodes[nodes.index == "id22"].plot(ax=ax, color="tab:blue")
id22_edges.plot(ax=ax, color="tab:blue")
for idx, row in gdf.iterrows():
ax.annotate(idx, xy=(row.geometry.centroid.x, row.geometry.centroid.y),
ha="center", va="center")
ax.set_axis_off()
# Plot id22 and its neighbors (both levels in the multi-index)
# this is what PyG expects
ax = gdf.plot(color="lightgray", categorical=True, edgecolor="black")
nodes[nodes.index.isin(id22_edges.index)].plot(ax=ax, color="tab:orange")
nodes[nodes.index == "id22"].plot(ax=ax, color="tab:blue")
id22_edges.plot(ax=ax, color="tab:blue")
# Add edges where id22 is on level 1
id22_lvl1 = edges.xs("id22", level=1)
nodes[nodes.index.isin(id22_lvl1.index)].plot(ax=ax, color="tab:red")
id22_lvl1.plot(ax=ax, color="tab:blue")
for idx, row in gdf.iterrows():
ax.annotate(idx, xy=(row.geometry.centroid.x, row.geometry.centroid.y),
ha="center", va="center")
ax.set_axis_off()
Expected behavior
All directed edges should be added for queen adjacency.
Environment (please complete the following information):
- Python version: 3.12
city2graph version: 0.3.1
torch version: 2.8
torch_geometric version: 2.7
How did you install city2graph?
via PyPI (e.g., pip)
Additional context
No response
Contributing guidelines
Documentation
Existing issues
Describe the bug
The
contiguity_graph(..., as_nx=False)method returns anedges_gdfin which each contiguity edge appears only once, with the smaller (in the order of the type) node id as the first MultiIndex level. The total edge count is correct for undirected edges. However, when transformed into a PyG graph, the edge table is assumed to be undirected, leading to missing edges.PyG treats every row of
edge_indexas a directed edge. Theedge_indexis a 2 x |E| matrix where (under the defaultflow="source_to_target") the messages from the nodes inedge_index[0]are sent to nodes inedge_index[1]. Withgdf_to_pyg, level 0 of the multi-index becomes the source and level 1 becomes the target node that receives the message. As each edge appears only once in the edge table, only one direction is included in the resultingedge_index.To Reproduce
Expected behavior
All directed edges should be added for queen adjacency.
Environment (please complete the following information):
city2graphversion: 0.3.1torchversion: 2.8torch_geometricversion: 2.7How did you install city2graph?
via PyPI (e.g., pip)
Additional context
No response