3

I need to edit data downloaded by osmnx in geopackage format and then import it as a graph for calculating distances, isochrones etc.

Current Process:

  1. Download osm data using ox.graph_from_point
  2. Save to Geopackage edges and nodes using ox.io.save_graph_geopackage, to allow user to add edges, extra roads in QGIS by digitising roads (with snapping) and save edits.
  3. Convert edited edges back to OSMNX as a graph using ox.graph_from_gdfs.

At this point the 'ox.graph_from_gdfs' returns an empty Graph object. It appears to complain that the x attribute doesn't exist but the x and y attributes do exist in the geopackage nodes layer- so I don't understand the error.

Error:

coords = ((n, d["x"], d["y"]) for n, d in G.nodes(data=True))
KeyError: 'x'

Can anyone assist?

Code:

import osmnx as ox
import networkx as nx
import geopandas as gpd
from shapely.geometry import Point, LineString, MultiLineString,Polygon,MultiPolygon
print("OX ver: {}".format(ox.__version__))
print("NX ver: {}".format(nx.__version__))

geopPath = "osmnx_roaddata.gpkg"
xG = -1.08762688688598
yG = 53.9547041755247

orig = (yG,xG)
print(orig)

gdf_edges = gpd.read_file(geopPath, layer='edges')
gdf_nodes = gpd.read_file(geopPath, layer='nodes')
## Test to see if x exists in geodataframe- looks fine
#for index, row in gdf_nodes.iterrows():
#    print("y: {}. x: {}".format(row['y'],row['x']))


print("######## Using Existing geopackage road edges and nodes")

### readthedocs: graph_attrs (dict) – the new G.graph attribute dict; if None, add crs as the only graph-level attribute
## don't know what the graph attribute dict should contain...or if providing the crs object is what is expected...

G = ox.graph_from_gdfs(gdf_nodes,gdf_edges) #, graph_attrs=gdf_nodes.crs)
print("G appears empty....: '{}'".format(G))

origin_node = ox.get_nearest_node(G, orig)
print("Roads geopackage now being used as variable 'G' graph object")

I understand I will probably need to calculate any missing nodes for new roads that have been digitised. But I should still be able to create a valid G graph object using 'ox.graph_from_gdfs' I thought before I encounter that issue. I've tested another geopackage with no additional roads or nodes other than the osmnx downloaded ones and same result.

Using OSMnx 0.16.0, NetworkX 2.5.

geopPath Geopackage Download

GIS_py
  • 133
  • 1
  • 5

1 Answers1

2

I will demonstrate how to do this with OSMnx v1.0 because it will be released in two days and provides slightly more robust support for converting GeoPandas GeoDataFrames to a NetworkX MultiDiGraph. See the docs for usage details.

Your problem appears to be that the u, v, and key columns in your edges GeoDataFrame contain null values, presumably from when you created them in QGIS. These are the unique identifiers of an edge and should be non-null integers. Both GeoDataFrames indexes should be unique.

import geopandas as gpd
import osmnx as ox

# create a graph, save as a GeoPackage
fp = 'graph.gpkg'
G = ox.graph_from_point((53.956748, -1.081676))
ox.save_graph_geopackage(G, fp)

# do some stuff in QGIS
# ensure the index attributes are non-null when you're finished
pass

# load GeoPackage as node/edge GeoDataFrames indexed as described in OSMnx docs
gdf_nodes = gpd.read_file(fp, layer='nodes').set_index('osmid')
gdf_edges = gpd.read_file(fp, layer='edges').set_index(['u', 'v', 'key'])
assert gdf_nodes.index.is_unique and gdf_edges.index.is_unique

# convert the node/edge GeoDataFrames to a MultiDiGraph
graph_attrs = {'crs': 'epsg:4326', 'simplified': True}
G2 = ox.graph_from_gdfs(gdf_nodes, gdf_edges, graph_attrs)
gboeing
  • 5,691
  • 2
  • 15
  • 41
  • thanks, installing v1.0 from github works (pip install git+https://github.com/gboeing/osmnx.git) in order to go back and forth from the graph to geopackage and it can calculate the nearest node now. The next issue for me is after adding new edges in QGIS: I need to 1. Add nodes with a unique osmid at the ends of the new lines, 2. Calculate u,v, key attributes. Is there a function already existing to do either of those? If not- I can see the relationship between osm 'to' and 'from' for u, v but I don't understand how 'key' is produced. – GIS_py Dec 30 '20 at 10:51
  • ok thanks, that answers the how keys are formed. Should I gather that there are no in-built methods to calculate missing u,v, key attributes in osmnx/networkx automatically? – GIS_py Dec 31 '20 at 09:53
  • If you are creating new edges outside of networkx, you need to assign u, v, key yourself to define the edge. – gboeing Dec 31 '20 at 15:58
  • ok thanks, will perform the intersections with shapely to get the coordinates for the missing nodes and the relationships To-Form write the attributes/features with ogr (i hope) to the geopackage edges and nodes layers. Then I can feed it back in for analysis. – GIS_py Dec 31 '20 at 16:49
  • Update: I wasn't able to successfully use the 'ox.graph_from_gdfs' function even at v 1.0. Even when I just used the raw geopackage exported from the Graph (no editing), it produced strange results with the returned nodes from: nx.ego_graph(G=G, n=origin_node, radius=trip_time, distance='time')'. When attempting to generate isochrones for different trip times, it creates the same polygon for all trips, the same nodes are found despite the trip travel time increasing. I will have to post a second question. – GIS_py Jan 05 '21 at 16:27