Ben Mann
Ben Mann

Reputation: 311

Clipping a networkx graph according to georeferenced polygon

I am running a loop that computes a networkx.classes.multidigraph.MultiDiGraph for each row (neighbourhood) of a list of GeoDataFrames (cities). It then computes some statistics for each row and writes the file out to disk. The problem is that the loop is extremely long to compute because the graph is computed for each row.

The way I want to quicken the loop is by computing the graph for the whole GeoDataFrame and then clipping the graph into each row (each row has a polygon). You can do this for GeoSeries with geopandas.clip. It seems, however, that no equivalent to geopandas.clip exists for networkx graphs.

Here is my initial code:

import osmnx as ox
import pandas as pd
import geopandas as gpd
import os

path="C:/folder/"
files=[os.path.join(path, f) for f in os.listdir(path)]

for i in range(0,2):
    city=gpd.read_file(files[i])
    circ=[]

    for i in range(0,181):
        graph_for_row=ox.graph_from_polygon(city.geometry[i])
        #above is the long command
        stat = ox.basic_stats(graph_for_row)
        circ.append(stat['circuity_avg'])

    circ=pd.Series(circ)
    merged.append(pd.concat([city, circ], axis=1))

for i in (range(0,len(merged))):
    with open(geofiles[i], 'w') as f:
        f.write(merged[i].to_json())

Here is the new loop I'm aiming for:

clipped_graph=[]

for i in range(0,2):
    city=gpd.read_file(files[i])
    whole_city=city.unary_union
    graph=ox.graph_from_polygon(whole_city)
    clipped_graph.append(gpd.clip(graph, city.geometry))#this line 
    #does not work since 'graph' is a networkx object, not
    #a GeoDataFrame or GeoSeries
    circ=[]

    for i in range(0,181)
        stat = ox.basic_stats(clipped_graph[i])
        circ.append(stat['circuity_avg'])

    circ=pd.Series(circ)
    merged.append(pd.concat([city, circ], axis=1))

for i in (range(0,len(merged))):
    with open(geofiles[i], 'w') as f:
        f.write(merged[i].to_json())

Upvotes: 1

Views: 1816

Answers (1)

gboeing
gboeing

Reputation: 6442

You can use your individual polygons to (spatially) intersect the graph nodes, then use those nodes to induce a subgraph. MWE:

import osmnx as ox
ox.config(use_cache=True, log_console=True)

# load a shapefile of polygons as geodataframe using geopandas
# here i just get 3 cities from OSM to make example reproducible without a shapefile
places = ['Cudahy, CA, USA', 'Bell, CA, USA', 'Maywood, CA, USA']
gdf = ox.gdf_from_places(places)

# get a graph of the union of their boundaries, then extract nodes as geodataframe
G = ox.graph_from_polygon(gdf.unary_union, network_type='drive')
nodes = ox.graph_to_gdfs(G, edges=False)

# for each city polygon, find intersecting nodes then induce subgraph
for polygon in gdf['geometry']:
    intersecting_nodes = nodes[nodes.intersects(polygon)].index
    G_sub = G.subgraph(intersecting_nodes)
    fig, ax = ox.plot_graph(G_sub)

Upvotes: 3

Related Questions