Search code examples
openstreetmaposmnx

Extract river data and filters using osmnx


I'm trying to plot the river of a specific area but I don't understand why osmnx cannot find it in certain places. I have this code

import osmnx as ox

Sriver = ox.graph_from_place('Providencia, Chile', 
                             # retain_all=False, 
                             # truncate_by_edge=False,
                             # simplify=True, 
                             custom_filter='["waterway"~"river"]',
                             # custom_filter='way["waterway"]'
                             )

But this fails with: Found no graph nodes within the requested polygon

If I query the features from OSM maps, the river is clearly there https://www.openstreetmap.org/query?lat=-33.41919&lon=-70.61062

enter image description here

Should I use other filters? I could not find more information in the docs. Or, is there a way to extract all available filters I can use from an area?


Solution

  • As described in the OSMnx documentation's Getting Started guide:

    Under the hood, OSMnx does several things to generate the best possible model. It initially creates a 500m-buffered graph before truncating it to your desired query area, to ensure accurate streets-per-node stats and to attenuate graph perimeter effects. It also simplifies the graph topology as discussed below.

    You said:

    I'm trying to plot the river of a specific area but I don't understand why osmnx cannot find it in certain places.

    ... but take a more careful look at the complete error traceback you're getting:

    ---------------------------------------------------------------------------
    ValueError                                Traceback (most recent call last)
    Cell In[2], line 3
          1 import osmnx as ox
    ----> 3 Sriver = ox.graph_from_place('Providencia, Chile', 
          4                              # retain_all=False, 
          5                              # truncate_by_edge=False,
          6                              # simplify=True, 
          7                              custom_filter='["waterway"~"river"]',
          8                              # custom_filter='way["waterway"]'
          9                              )
    
    File ~/Dropbox/Documents/School/Projects/Code/osmnx-repos/osmnx/osmnx/graph.py:375, in graph_from_place(query, network_type, simplify, retain_all, truncate_by_edge, which_result, buffer_dist, clean_periphery, custom_filter)
        372 utils.log("Constructed place geometry polygon(s) to query API")
        374 # create graph using this polygon(s) geometry
    --> 375 G = graph_from_polygon(
        376     polygon,
        377     network_type=network_type,
        378     simplify=simplify,
        379     retain_all=retain_all,
        380     truncate_by_edge=truncate_by_edge,
        381     clean_periphery=clean_periphery,
        382     custom_filter=custom_filter,
        383 )
        385 utils.log(f"graph_from_place returned graph with {len(G):,} nodes and {len(G.edges):,} edges")
        386 return G
    
    File ~/Dropbox/Documents/School/Projects/Code/osmnx-repos/osmnx/osmnx/graph.py:492, in graph_from_polygon(polygon, network_type, simplify, retain_all, truncate_by_edge, clean_periphery, custom_filter)
        485     G_buff = simplification.simplify_graph(G_buff)
        487 # truncate graph by original polygon to return graph within polygon
        488 # caller wants. don't simplify again: this allows us to retain
        489 # intersections along the street that may now only connect 2 street
        490 # segments in the network, but in reality also connect to an
        491 # intersection just outside the polygon
    --> 492 G = truncate.truncate_graph_polygon(G_buff, polygon, retain_all, truncate_by_edge)
        494 # count how many physical streets in buffered graph connect to each
        495 # intersection in un-buffered graph, to retain true counts for each
        496 # intersection, even if some of its neighbors are outside the polygon
        497 spn = stats.count_streets_per_node(G_buff, nodes=G.nodes)
    
    File ~/Dropbox/Documents/School/Projects/Code/osmnx-repos/osmnx/osmnx/truncate.py:162, in truncate_graph_polygon(G, polygon, retain_all, truncate_by_edge, quadrat_width, min_num)
        159 if not to_keep:
        160     # no graph nodes within the polygon: can't create a graph from that
        161     msg = "Found no graph nodes within the requested polygon"
    --> 162     raise ValueError(msg)
        164 # now identify all nodes whose point geometries lie outside the polygon
        165 gs_nodes_outside_poly = gs_nodes[~gs_nodes.index.isin(to_keep)]
    
    ValueError: Found no graph nodes within the requested polygon
    

    OSMnx is finding the river you're searching for. It does so as a 500m buffered graph then truncates it back down to your desired study area. But because you're requesting that OSMnx automatically simplify the graph topology, and because you have a very trivial spatial geometry as your only result, the simplification step removes all the graph nodes within your study area, leaving only a couple endpoints beyond your study area but within that 500m buffer. So, upon truncating to your study area, it finds no graph nodes remaining within your study boundary itself.

    You can solve this problem by 1) not simplifying the graph at all, or 2) simplifying the graph after constructing it. A simple example of both options, plus an illustration of what is happening:

    import osmnx as ox
    
    # get boundary polygon and unsimplified graph
    gdf = ox.geocode_to_gdf("Providencia, Chile")
    geom = gdf.iloc[0]["geometry"]
    G = ox.graph_from_polygon(geom, retain_all=True, truncate_by_edge=True, simplify=False, custom_filter='["waterway"~"river"]')
    
    # plot unsimplified graph over boundary polygon
    ax = gdf.plot()
    fig, ax = ox.plot_graph(G, ax=ax, node_color="r", edge_color="k")
    
    # plot simplified graph over boundary polygon
    Gs = ox.simplify_graph(G)
    ax = gdf.plot()
    fig, ax = ox.plot_graph(Gs, ax=ax, node_color="r", edge_color="k")