1

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.

  • Does anyone know of a way to clip a networkx graph?

  • Alternatively, what other methods exist to speed up my loop.

  • Note: clipping would work if I could convert the networkx graph to a pandas object. Unfortunately, I think it is not possible to keep the properties which osmnx acts on when the graph is converted to a pandas object. If I'm wrong, please say so.

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())
Ben Mann
  • 173
  • 4
  • 11

1 Answers1

3

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)
gboeing
  • 5,691
  • 2
  • 15
  • 41
  • Thanks for pointing me in that direction. However, I'm having a really hard time implementing your suggestion. Here is the method I use: 1. For each file, write the file out to disk as a shapefile. Each row of the shapefile is a polygon. 2. Read in the shapefile. 3. Get the shapefile for each row with `shapefile.shapeRecord()[row]`. I'm pretty sure that doesn't work but don't know of another method to get a shapefile for each row. 4. Get the graph of the perimeter of the neighbourhood with `networkx.read_shp(row_shape)`. This doesn't work since `row_shape` is a NoneType, not a shapefile. – Ben Mann Feb 18 '20 at 09:46
  • It would really help if you could point me toward a method to spatially intersect graph nodes. – Ben Mann Feb 18 '20 at 09:47
  • @BenMann I edited the answer to provide sample code – gboeing Feb 19 '20 at 18:24
  • Thanks a lot, this accelerated the loop a huge amount. – Ben Mann Feb 23 '20 at 21:12