-
Notifications
You must be signed in to change notification settings - Fork 826
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Method to weigh boulevards for intersection density calculations #49
Comments
This is primarily an issue with the data model that OSM (and TIGER/Line shapefiles, etc) use to represent street networks. Generally, divided roads get represented as separate centerline edges. I've floated some ideas for dealing with this from a geometric perspective (see #12) but dealing with it topologically is a different story and probably outside the scope of OSMnx for now. |
Just to add my solution here for anyone else interested in dealing with this, I set up a simple for loop that (hopefully) should not get "out of control" with larger datasets. Here's what the results look like with a small subset of data: The gist is here with the most critical bit of code in lines 40 - up. Basically, I create a boolean column and for loop through the geodataframe, marking "off" any intersections whose buffer intersects the one being currently reviewed. As I move through the whole geodataframe, I skip any rows that have already been marked as "off," thereby avoiding repeating the intersection test on any of an already reviewed intersection's "siblings." # set a bool column to track which intersections to use
gdf_nodes['use'] = True
list_of_nodes = gdf_nodes.index.values
for node_id in list_of_nodes:
current = gdf_nodes.loc[node_id]
# only proceed if has not already been marked as False (don't use)
if current['use']:
ints_with = gdf_nodes.intersects(current.geometry)
# review intersecting buffered nodes
sub_gdf = gdf_nodes[ints_with]
sub_gdf_sans_current = sub_gdf[sub_gdf.index != node_id]
# get the indexes of other rows and 'turn them off'
turn_these_off = sub_gdf_sans_current.index.values
for sub_node_id in turn_these_off:
gdf_nodes.loc[sub_node_id, 'use'] = False
# here is a dataframe of unique geometries
cleaned_ints = gdf_nodes[gdf_nodes['use'] == True] |
@kelanstoy @kuanb here's a simple solution using the geometric dissolve method I suggested in #12: import osmnx as ox, matplotlib.pyplot as plt, numpy as np, geopandas as gpd
# get a street network and plot it with all edge intersections
address = '2700 Shattuck Ave, Berkeley, CA'
G = ox.graph_from_address(address, network_type='drive', distance=750)
G_proj = ox.project_graph(G)
fig, ax = ox.plot_graph(G_proj, fig_height=10, node_color='orange', node_size=30,
node_zorder=2, node_edgecolor='k')
# clean up intersections by buffering 15 meters, dissolving, and using centroid
gdf_nodes = ox.graph_to_gdfs(G_proj, edges=False)
buff = gdf_nodes.buffer(15)
unified = gpd.GeoDataFrame(geometry=list(buff.unary_union))
intersections = unified.centroid
# plot the cleaned-up intersections
fig, ax = ox.plot_graph(G_proj, fig_height=10, show=False, close=False, node_alpha=0)
points = np.array([point.xy for point in intersections])
ax.scatter(x=points[:,0], y=points[:,1], zorder=2, color='#66ccff', edgecolors='k')
plt.show() ...and you get something like this: before (left) and after (right): It doesn't fix the topology (i.e., reconnect all the streets to the new intersection point), but it improves the intersection density counts. |
Fantastic! So a plain language interpretation of your methodology:
|
Update - Geoff's method took under 2 minutes whereas for the |
I think this solution is fast, powerful, and useful enough that I'll bake it into OSMnx directly. It'll be pushed shortly and released in the upcoming minor version. |
@kuanb @kelanstoy see OSMnx's new clean_intersections function and this example notebook demonstrating it. |
Nice, thanks!! |
Problem description (what did you do, what did you expect to happen, and what actually happened)
When calculating intersection density for an area, I would like to be able to identify 'boulevards' - or any sort of split roadway in the network - and either consolidate intersections at these locations into 1 node or reduce the 'weight' of the intersection such that all locations where a road crosses a boulevard only count as 1 intersection in the density calculation.
At first, I thought I could use the
one-way
attribute of edges in OSM networks to identify nodes that intersect with boulevards, and reduce their weight in the intersection density count by manually counting intersection density using a spatial intersection in geopandas. (see example 1 below, of downtown Merced, CA). However, this method would undercount valid one-way street intersections, such as those that exist when two one-way streets intersect (see example 2 of downtown San Francisco).My next thought was that I could use the
length
attribute of edges to identify nodes that are shorter than a certain threshold and also connected to a one-way street. I then could either, reduce the weight applied to nodes that touch these edges based on how manyone-way
edges connect to it (two intersection boulevards should reduce intersection weight to 0.25, for example).I'm wondering if anyone has already thought about a method for cleaning up intersection density count for the OSMnx library, and if code already exists within the repo for systematically addressing how to define an 'intersection' for the purpose of generating intersection density stats. Thanks!
Code that reproduces the issue
The text was updated successfully, but these errors were encountered: