Search code examples
pythonpandasopenstreetmaposmnx

How to get the number of roundabouts in a given city/ area in OSMnx?


I am still trying to figure out OSM and OSMnx. I want to count how many roundabouts are there in Paris for example. The problem is that many roundabouts are stored as ways, but in pieces. So, if I count all the tags where junction=roundabout, I will count some roundabouts more than once.

How can I avoid this and only count each roundabout once?

# This is what I used to plot all the roundabouts in Paris
roundabouts = ox.graph_from_place('Paris, France', network_type = 'drive', 
              custom_filter = '["junction"~"roundabout"]', retain_all = True, simplify = False)
fig, ax = ox.plot_graph(roundabouts, node_size=0, bgcolor='k')
# This is what I tried to use to count the roundabouts
# 1st option
edges = ox.graph_to_gdfs(roundabouts, nodes=False, edges=True)
print('Roundabouts count:', edges.junction.count() )

# 2nd option, tried to group by OSM id and then count unique IDs
edges = ox.graph_to_gdfs(roundabouts, nodes=False, edges=True)
print('Roundabouts count:', len(edges[edges['junction']=='roundabout'].groupby('osmid').size()))

Both are wrong and I couldn't come up with a right way to do this. Can someone help out?


Solution

  • There is no simple straightforward way to do this, because of how OSM tags these elements. Here are two options that yield similar estimates of the number of roundabouts in a city. Either should get you onto the right track, but will require further experimentation.

    import networkx as nx
    import osmnx as ox
    ox.config(use_cache=True)
    place = 'Berkeley, CA, USA'
    nt = 'drive'
    
    # OPTION ONE
    cf = '["junction"="roundabout"]'
    G = ox.graph_from_place(place, network_type=nt, custom_filter=cf, retain_all=True, simplify=False)
    roundabouts = list(nx.weakly_connected_components(G))
    len(roundabouts) #60
    
    
    # OPTION TWO
    tolerance = 15
    G = ox.graph_from_place(place, network_type=nt)
    Gp = ox.project_graph(G)
    Gc = ox.consolidate_intersections(Gp, tolerance=tolerance)
    
    edges = ox.graph_to_gdfs(Gp, nodes=False)
    roundabouts = edges[edges['junction'] == 'roundabout']
    
    nodes = ox.graph_to_gdfs(Gc, edges=False)
    nodes_in_roundabouts = nodes[nodes.buffer(tolerance).intersects(roundabouts.unary_union)]
    len(nodes_in_roundabouts) #59
    

    The former models just the roundabouts in the city, then looks for all the weakly-connected graph components. Each discrete component is considered a unique roundabout. The latter clusters (topologically consolidates) intersections, then checks to see which ones' buffers overlap a roundabout edge. See also the docs on the consolidate_intersections function.