Created
April 26, 2017 23:07
-
-
Save kuanb/ca953faf85e7b2d3464470f5b2087615 to your computer and use it in GitHub Desktop.
Using OSMnx, pull down a network and remove "unneeded" intersections from boulevards and like, so as to not double count.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import matplotlib | |
# Force matplotlib to not use any Xwindows backend. | |
matplotlib.use('Agg') | |
import geopandas as gpd | |
import pandas as pd | |
from shapely.geometry import Point | |
import osmnx as ox | |
COUNTER = 0 | |
def plot(gdf): | |
global COUNTER | |
COUNTER += 1 | |
name = 'output_' + str(COUNTER) + '.png' | |
gdf.plot().get_figure().savefig(name) | |
# let's start with beautiful Merced, CA | |
location_point = (37.3022, -120.4830) | |
# get the network graph for a radius of 500 meters | |
radius = 500 # meter unit measure | |
G = ox.graph_from_point(location_point, distance=radius) | |
G = remove_osmnx_false_intersections(G, min_streets_per_int=3) | |
G = remove_osmnx_unwalkable_intersections(G, unwalkable_types=['motorway','motorway_link','trunk','trunk_link','primary_link']) | |
node_geom = [Point(data['x'], data['y']) for _, data in G.nodes(data=True)] | |
gdf_nodes = gpd.GeoDataFrame({'node':pd.Series(G.nodes()), 'geometry':node_geom}) | |
gdf_nodes.crs = G.graph['crs'] | |
# create and visually inspect intersection nodes | |
gdf_nodes = gdf_nodes.to_crs(epsg=3310) | |
plot(gdf_nodes) | |
# create and visually inspect buffered nodes | |
gdf_nodes['geometry'] = gdf_nodes.buffer(20) | |
plot(gdf_nodes) | |
# 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] | |
# preserved osmnx helper functions | |
def remove_osmnx_false_intersections(G, min_streets_per_int=3): | |
if 'streets_per_node' in G.graph: | |
# get the degrees saved as a graph attribute (from an undirected representation of the graph) | |
# this is not the degree of the nodes in the directed graph, but rather represents the number | |
# of streets (unidirected edges) emanating from each node. see count_streets_per_node function. | |
streets_per_node = G.graph['streets_per_node'] | |
else: | |
# count how many street segments emanate from each node in this graph | |
streets_per_node = count_streets_per_node(G) | |
# count number of intersections in graph, as nodes with >1 street emanating from them | |
node_ids = set(G.nodes()) | |
nodes_to_drop = [node for node, count in streets_per_node.items() if (count < min_streets_per_int) and (node in node_ids)] | |
G.remove_nodes_from(nodes_to_drop) | |
return G | |
def remove_osmnx_unwalkable_intersections(G, unwalkable_types=['motorway', | |
'motorway_link', | |
'trunk', | |
'trunk_link']): | |
unwalkable_nodes_to_drop = [] | |
for node in G.nodes(): | |
edge_types = [list(edge.values())[0]['highway'] for edge in G.edge[node].values()] | |
if any(unwalkable_type in edge_types for unwalkable_type in unwalkable_types): | |
unwalkable_nodes_to_drop.append(node) | |
G.remove_nodes_from(unwalkable_nodes_to_drop) | |
return G |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment