Skip to content

Instantly share code, notes, and snippets.

@ashnair1
Last active November 10, 2025 09:30
Show Gist options
  • Select an option

  • Save ashnair1/636e5ce38e03492c09d1226ba06a76d7 to your computer and use it in GitHub Desktop.

Select an option

Save ashnair1/636e5ce38e03492c09d1226ba06a76d7 to your computer and use it in GitHub Desktop.
Script to download nodes, edges and traffic lights of a road network
import osmnx as ox
import geopandas as gpd
from shapely.geometry import Polygon, MultiPolygon
# --- INPUTS ---
polygon_path = "<ADD-GEOJSON-PATH-HERE>"
out_nodes = "<ADD-GEOJSON-PATH-HERE>"
out_edges = "<ADD-GEOJSON-PATH-HERE>"
out_traffic_lights = "<AADD-GEOJSON-PATH-HERE>"
# 1) Read polygon and ensure WGS84 (lat/lon)
poly_gdf = gpd.read_file(polygon_path)
if poly_gdf.empty:
raise ValueError("No features found in the supplied GeoJSON.")
# dissolve to a single geometry (handles multiple features)
poly = poly_gdf.union_all()
# ensure it's polygonal (e.g., drop points/lines if present)
if not isinstance(poly, (Polygon, MultiPolygon)):
# try to collect only polygonal parts if the file contains mixed geometry types
polys = [geom for geom in poly_gdf.geometry if isinstance(geom, (Polygon, MultiPolygon))]
if not polys:
raise ValueError("GeoJSON must contain a Polygon/MultiPolygon geometry.")
poly = gpd.GeoSeries(polys).unary_union
# reproject to WGS84 if needed
if poly_gdf.crs is not None and str(poly_gdf.crs).lower() not in ["epsg:4326", "wgs84", "ogc:crs84"]:
poly = gpd.GeoSeries([poly], crs=poly_gdf.crs).to_crs(epsg=4326).iloc[0]
# 2) Download the road network inside the polygon
# - network_type="drive": car-navigable roads
# - truncate_by_edge=True: keep edges that cross the polygon boundary
# - retain_all=False: drop small disconnected fragments outside
graph = ox.graph_from_polygon(
poly,
network_type="drive",
simplify=True,
retain_all=False,
truncate_by_edge=True
)
# (Optional) If you want to strictly clip to the polygon boundary again:
# graph = ox.truncate.truncate_graph_polygon(graph, poly, retain_all=True)
# 3) Convert to GeoDataFrames
nodes, edges = ox.graph_to_gdfs(graph)
# 4) Download traffic lights within the polygon
# - highway=traffic_signals: traffic light nodes in OSM
try:
traffic_lights = ox.features_from_polygon(
poly,
tags={'highway': 'traffic_signals'}
)
except Exception as e:
print(f"Error fetching traffic lights: {e}")
traffic_lights = gpd.GeoDataFrame(columns=['geometry'], geometry='geometry', crs='EPSG:4326')
# 5) Save to GeoJSON
nodes.to_file(out_nodes, driver="GeoJSON")
edges.to_file(out_edges, driver="GeoJSON")
traffic_lights.to_file(out_traffic_lights, driver="GeoJSON")
print(f"Saved:\n- {out_nodes}\n- {out_edges}\n- {out_traffic_lights}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment