pythonnetworkxosmnx

OSMnx throws exception when called on graph created from graph_from_gdfs


I'm trying to simplify a graph after modifying the gdf_edges and recreating the graph from the dataframes. My workflow is as follows:

ox.graph_from_polygon => graph_to_gdfs => modify gdf_edges => ox.graph_from_gdfs => ox.simplify_graph

However, this throws a TypeError in simplification.py: TypeError: unhashable type: 'list'.

File .../osmnx/simplification.py:362, in simplify_graph(G, strict, edge_attrs_differ, endpoint_attrs, remove_rings, track_merged)
    359 if attr in attrs_to_sum:
    360     # if this attribute must be summed, sum it now
    361     path_attributes[attr] = sum(path_attributes[attr])
--> 362 elif len(set(path_attributes[attr])) == 1:
    363     # if there's only 1 unique value in this attribute list,

The same occurs also without modifying the dataframe. MRE:

import shapely
import osmnx as ox

poly = shapely.from_wkt("POLYGON((9.493474960327147 51.228210969202365,"
                        "9.493346214294432 51.223359875812804,"
                        "9.498442411422728 51.22356145497176,"
                        "9.498571157455443 51.228036284963565,"
                        "9.493474960327147 51.228210969202365))")

G = ox.graph_from_polygon(poly, network_type="drive")

nodes_gdf, edges_gdf = ox.graph_to_gdfs(G.to_undirected())

G2 = ox.graph_from_gdfs(gdf_nodes=nodes_gdf, gdf_edges=edges_gdf)

nodes_gdf_2, edges_gdf_2 = ox.graph_to_gdfs(ox.simplify_graph(G2))

Question: How can I prevent this exception and simplify G2?


Solution

  • The problem (and solution) is that you are essentially simplifying your graph twice: once when you run graph_from_polygon (due to the default function argument), and a second time when you manually run ox.simplify_graph(G2). However, you can only simplify a graph once because of the nature of the algorithm.

    OSMnx normally tries to be helpful and tell you this... but the way you're converting back and forth to/from GeoDataFrames, you threw away the simplification information so OSMnx doesn't know it was previously simplified! This is fixed by making sure you keep the graph metadata by passing the graph_attrs argument:

    import shapely
    import osmnx as ox
    
    poly = shapely.from_wkt("POLYGON((9.493474960327147 51.228210969202365,"
                            "9.493346214294432 51.223359875812804,"
                            "9.498442411422728 51.22356145497176,"
                            "9.498571157455443 51.228036284963565,"
                            "9.493474960327147 51.228210969202365))")
    
    G = ox.graph_from_polygon(poly, network_type="drive")
    nodes_gdf, edges_gdf = ox.graph_to_gdfs(G.to_undirected())
    G2 = ox.graph_from_gdfs(gdf_nodes=nodes_gdf, gdf_edges=edges_gdf, graph_attrs=G.graph)
    nodes_gdf_2, edges_gdf_2 = ox.graph_to_gdfs(ox.simplify_graph(G2))
    

    This doesn't solve your problem, but it at least identifies its nature: "GraphSimplificationError: This graph has already been simplified, cannot simplify it again."

    To solve your problem, just simplify the graph one time, when you're fully ready to:

    import shapely
    import osmnx as ox
    
    poly = shapely.from_wkt("POLYGON((9.493474960327147 51.228210969202365,"
                            "9.493346214294432 51.223359875812804,"
                            "9.498442411422728 51.22356145497176,"
                            "9.498571157455443 51.228036284963565,"
                            "9.493474960327147 51.228210969202365))")
    
    G = ox.graph_from_polygon(poly, network_type="drive", simplify=False)
    nodes_gdf, edges_gdf = ox.graph_to_gdfs(G.to_undirected())
    G2 = ox.graph_from_gdfs(gdf_nodes=nodes_gdf, gdf_edges=edges_gdf, graph_attrs=G.graph)
    nodes_gdf_2, edges_gdf_2 = ox.graph_to_gdfs(ox.simplify_graph(G2))