Skip to content

Commit

Permalink
handle networkx 2.0-dev's new generator-based API
Browse files Browse the repository at this point in the history
  • Loading branch information
gboeing committed Jan 11, 2017
1 parent cf54419 commit 53b51f7
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 35 deletions.
26 changes: 13 additions & 13 deletions osmnx/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ def remove_isolated_nodes(G):
-------
G : graph
"""
isolated_nodes = [node for node, degree in G.degree().items() if degree < 1]
isolated_nodes = [node for node, degree in dict(G.degree()).items() if degree < 1]
G.remove_nodes_from(isolated_nodes)
log('Removed {:,} isolated nodes'.format(len(isolated_nodes)))
return G
Expand All @@ -714,7 +714,7 @@ def truncate_graph_dist(G, source_node, max_distance=1000, weight='length', reta
start_time = time.time()
G = G.copy()
distances = nx.shortest_path_length(G, source=source_node, weight=weight)
distant_nodes = {key:value for key, value in distances.items() if value > max_distance}
distant_nodes = {key:value for key, value in dict(distances).items() if value > max_distance}
G.remove_nodes_from(distant_nodes.keys())
log('Truncated graph by weighted network distance in {:,.2f} seconds'.format(time.time()-start_time))

Expand Down Expand Up @@ -758,7 +758,7 @@ def truncate_graph_bbox(G, north, south, east, west, truncate_by_edge=False, ret
else:
# if we're truncating by edge, see if any of node's neighbors are within bounding box
any_neighbors_in_bbox = False
neighbors = G.successors(node) + G.predecessors(node)
neighbors = list(G.successors(node)) + list(G.predecessors(node))
for neighbor in neighbors:
x = G.node[neighbor]['x']
y = G.node[neighbor]['y']
Expand Down Expand Up @@ -893,7 +893,7 @@ def truncate_graph_polygon(G, polygon, retain_all=False, truncate_by_edge=False)

# get a GeoDataFrame of all the nodes, for spatial analysis
node_geom = [Point(data['x'], data['y']) for _, data in G.nodes(data=True)]
gdf_nodes = gpd.GeoDataFrame({'node':G.nodes(), 'geometry':node_geom})
gdf_nodes = gpd.GeoDataFrame({'node':pd.Series(G.nodes()), 'geometry':node_geom})
gdf_nodes.crs = G.graph['crs']

# find all the nodes in the graph that lie outside the polygon
Expand Down Expand Up @@ -994,13 +994,13 @@ def add_path(G, data, one_way):

# zip together the path nodes so you get tuples like (0,1), (1,2), (2,3) and so on
path_edges = list(zip(path_nodes[:-1], path_nodes[1:]))
G.add_edges_from(path_edges, attr_dict=data)
G.add_edges_from(path_edges, **data)

# if the path is NOT one-way
if not one_way:
# reverse the direction of each edge and add this path going the opposite direction
path_edges_opposite_direction = [(v, u) for u, v in path_edges]
G.add_edges_from(path_edges_opposite_direction, attr_dict=data)
G.add_edges_from(path_edges_opposite_direction, **data)


def add_paths(G, paths, network_type):
Expand Down Expand Up @@ -1079,7 +1079,7 @@ def create_graph(response_jsons, name='unnamed', retain_all=False, network_type=

# add each osm node to the graph
for node, data in nodes.items():
G.add_node(node, attr_dict=data)
G.add_node(node, **data)

# add each osm way (aka, path) to the graph
G = add_paths(G, paths, network_type)
Expand All @@ -1088,7 +1088,7 @@ def create_graph(response_jsons, name='unnamed', retain_all=False, network_type=
if not retain_all:
G = get_largest_component(G)

log('Created graph with {:,} nodes and {:,} edges in {:,.2f} seconds'.format(len(G.nodes()), len(G.edges()), time.time()-start_time))
log('Created graph with {:,} nodes and {:,} edges in {:,.2f} seconds'.format(len(list(G.nodes())), len(list(G.edges())), time.time()-start_time))

# add length (great circle distance between nodes) attribute to each edge to use as weight
G = add_edge_lengths(G)
Expand Down Expand Up @@ -1190,7 +1190,7 @@ def graph_from_bbox(north, south, east, west, network_type='all_private', simpli
if simplify:
G = simplify_graph(G)

log('graph_from_bbox() returning graph with {:,} nodes and {:,} edges'.format(len(G.nodes()), len(G.edges())))
log('graph_from_bbox() returning graph with {:,} nodes and {:,} edges'.format(len(list(G.nodes())), len(list(G.edges()))))
return G


Expand Down Expand Up @@ -1242,7 +1242,7 @@ def graph_from_point(center_point, distance=1000, distance_type='bbox', network_
else:
raise ValueError('distance_type must be "bbox" or "network"')

log('graph_from_point() returning graph with {:,} nodes and {:,} edges'.format(len(G.nodes()), len(G.edges())))
log('graph_from_point() returning graph with {:,} nodes and {:,} edges'.format(len(list(G.nodes())), len(list(G.edges()))))
return G


Expand Down Expand Up @@ -1283,7 +1283,7 @@ def graph_from_address(address, distance=1000, distance_type='bbox', network_typ
# then create a graph from this point
G = graph_from_point(point, distance, distance_type, network_type=network_type, simplify=simplify, retain_all=retain_all,
truncate_by_edge=truncate_by_edge, name=name, timeout=timeout, memory=memory, max_query_area_size=max_query_area_size, clean_periphery=clean_periphery)
log('graph_from_address() returning graph with {:,} nodes and {:,} edges'.format(len(G.nodes()), len(G.edges())))
log('graph_from_address() returning graph with {:,} nodes and {:,} edges'.format(len(list(G.nodes())), len(list(G.edges()))))

if return_coords:
return G, point
Expand Down Expand Up @@ -1357,7 +1357,7 @@ def graph_from_polygon(polygon, network_type='all_private', simplify=True, retai
if simplify:
G = simplify_graph(G)

log('graph_from_polygon() returning graph with {:,} nodes and {:,} edges'.format(len(G.nodes()), len(G.edges())))
log('graph_from_polygon() returning graph with {:,} nodes and {:,} edges'.format(len(list(G.nodes())), len(list(G.edges()))))
return G


Expand Down Expand Up @@ -1405,7 +1405,7 @@ def graph_from_place(query, network_type='all_private', simplify=True, retain_al
G = graph_from_polygon(polygon, network_type=network_type, simplify=simplify, retain_all=retain_all,
truncate_by_edge=truncate_by_edge, name=name, timeout=timeout, memory=memory, max_query_area_size=max_query_area_size, clean_periphery=clean_periphery)

log('graph_from_place() returning graph with {:,} nodes and {:,} edges'.format(len(G.nodes()), len(G.edges())))
log('graph_from_place() returning graph with {:,} nodes and {:,} edges'.format(len(list(G.nodes())), len(list(G.edges()))))
return G


6 changes: 3 additions & 3 deletions osmnx/projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def project_graph(G):

# clear the graph to make it a blank slate for the projected data
start_time = time.time()
edges = G_proj.edges(keys=True, data=True)
edges = list(G_proj.edges(keys=True, data=True))
graph_name = G_proj.graph['name']
G_proj.clear()

Expand All @@ -155,13 +155,13 @@ def project_graph(G):
attributes = gdf_nodes_utm.to_dict()
for name in gdf_nodes_utm.columns:
nx.set_node_attributes(G_proj, name, attributes[name])

# add the edges and all their attributes (including reconstructed geometry, when it exists) to the graph
for u, v, key, attributes in edges:
if 'geometry' in attributes:
row = gdf_edges_utm[(gdf_edges_utm['u']==u) & (gdf_edges_utm['v']==v) & (gdf_edges_utm['key']==key)]
attributes['geometry'] = row['geometry'].iloc[0]
G_proj.add_edge(u, v, key, attributes)
G_proj.add_edge(u, v, key=key, **attributes)

# set the graph's CRS attribute to the new, projected CRS and return the projected graph
G_proj.graph['crs'] = gdf_nodes_utm.crs
Expand Down
15 changes: 8 additions & 7 deletions osmnx/save_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,15 @@ def save_graph_shapefile(G, filename='graph', folder=None, encoding='utf-8'):
-------
None
"""

start_time = time.time()
if folder is None:
folder = globals.data_folder

# convert directed graph G to an undirected graph for saving as a shapefile
G_save = G.copy()
G_save = get_undirected(G_save)


# create a GeoDataFrame of the nodes and set CRS
nodes = {node:data for node, data in G_save.nodes(data=True)}
Expand All @@ -89,7 +90,7 @@ def save_graph_shapefile(G, filename='graph', folder=None, encoding='utf-8'):
gdf_nodes['osmid'] = gdf_nodes['osmid'].astype(np.int64)
for col in [c for c in gdf_nodes.columns if not c == 'geometry']:
gdf_nodes[col] = gdf_nodes[col].fillna('').map(make_str)

# create a list to hold our edges, then loop through each edge in the graph
edges = []
for u, v, key, data in G_save.edges(keys=True, data=True):
Expand All @@ -106,7 +107,7 @@ def save_graph_shapefile(G, filename='graph', folder=None, encoding='utf-8'):
edge_details['geometry'] = LineString([point_u, point_v])

edges.append(edge_details)

# create a geodataframe from the list of edges and set the CRS
gdf_edges = gpd.GeoDataFrame(edges)
gdf_edges.crs = G_save.graph['crs']
Expand Down Expand Up @@ -225,8 +226,8 @@ def load_graphml(filename, folder=None):
if 'geometry' in data:
data['geometry'] = wkt.loads(data['geometry'])

log('Loaded graph with {:,} nodes and {:,} edges in {:,.2f} seconds from "{}"'.format(len(G.nodes()),
len(G.edges()),
log('Loaded graph with {:,} nodes and {:,} edges in {:,.2f} seconds from "{}"'.format(len(list(G.nodes())),
len(list(G.edges())),
time.time()-start_time,
path))
return G
Expand Down Expand Up @@ -274,7 +275,7 @@ def get_undirected(G):
if not (geom1 == geom2 or geom1_r == geom2):
# add it as a new edge to the graph to be saved (with key equal to the current largest key plus one)
new_key = max(G.edge[u][v]) + 1
G_undir.add_edge(u, v, new_key, attr_dict=data)
G_undir.add_edge(u, v, new_key, **data)
except:
pass

Expand Down Expand Up @@ -389,7 +390,7 @@ def gdfs_to_graph(gdf_nodes, gdf_edges):
for label, value in row.iteritems():
if (label not in ['u', 'v', 'key']) and (isinstance(value, list) or pd.notnull(value)):
attrs[label] = value
G.add_edge(u=row['u'], v=row['v'], key=row['key'], attr_dict=attrs)
G.add_edge(u=row['u'], v=row['v'], key=row['key'], **attrs)

return G

Expand Down
10 changes: 5 additions & 5 deletions osmnx/simplify.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def is_endpoint(G, node, strict=True):
-------
bool
"""
neighbors = set(G.predecessors(node) + G.successors(node))
neighbors = set(list(G.predecessors(node)) + list(G.successors(node)))
n = len(neighbors)
d = G.degree(node)

Expand Down Expand Up @@ -187,8 +187,8 @@ def simplify_graph(G_, strict=True):

log('Begin topologically simplifying the graph...')
G = G_.copy()
initial_node_count = len(G.nodes())
initial_edge_count = len(G.edges())
initial_node_count = len(list(G.nodes()))
initial_edge_count = len(list(G.edges()))
all_nodes_to_remove = []
all_edges_to_add = []

Expand Down Expand Up @@ -238,13 +238,13 @@ def simplify_graph(G_, strict=True):

# for each edge to add in the list we assembled, create a new edge between the origin and destination
for edge in all_edges_to_add:
G.add_edge(edge['origin'], edge['destination'], attr_dict=edge['attr_dict'])
G.add_edge(edge['origin'], edge['destination'], **edge['attr_dict'])

# finally remove all the interstitial nodes between the new edges
G.remove_nodes_from(set(all_nodes_to_remove))

msg = 'Simplified graph (from {:,} to {:,} nodes and from {:,} to {:,} edges) in {:,.2f} seconds'
log(msg.format(initial_node_count, len(G.nodes()), initial_edge_count, len(G.edges()), time.time()-start_time))
log(msg.format(initial_node_count, len(list(G.nodes())), initial_edge_count, len(list(G.edges())), time.time()-start_time))
return G


9 changes: 5 additions & 4 deletions osmnx/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ def basic_stats(G, area=None):
G_undirected = None

# calculate the number of nodes, n, and the number of edges, m, in the graph
n = len(G.nodes())
m = len(G.edges())
n = len(list(G.nodes()))
m = len(list(G.edges()))

# calculate the average degree of the graph
k_avg = 2 * m / n
Expand Down Expand Up @@ -86,7 +86,7 @@ def basic_stats(G, area=None):
if G_undirected is None:
G_undirected = G.to_undirected(reciprocal=False)
street_length_total = sum([d['length'] for u, v, d in G_undirected.edges(data=True)])
street_segments_count = len(G_undirected.edges(keys=True))
street_segments_count = len(list(G_undirected.edges(keys=True)))
street_length_avg = street_length_total / street_segments_count

# we can calculate density metrics only if area is not null
Expand Down Expand Up @@ -271,7 +271,8 @@ def extended_stats(G, connectivity=False, anc=False, ecc=False, bc=False, cc=Fal
if ecc:
# precompute shortest paths between all nodes for eccentricity-based stats
start_time = time.time()
sp = {source:nx.single_source_dijkstra_path_length(G_strong, source, weight='length') for source in G_strong.nodes()}
sp = {source:dict(nx.single_source_dijkstra_path_length(G_strong, source, weight='length')) for source in G_strong.nodes()}

log('Calculated shortest path lengths in {:,.2f} seconds'.format(time.time() - start_time))

# eccentricity of a node v is the maximum distance from v to all other nodes in G
Expand Down
6 changes: 3 additions & 3 deletions osmnx/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,18 +199,18 @@ def get_largest_component(G, strongly=False):
"""

start_time = time.time()
original_len = len(G.nodes())
original_len = len(list(G.nodes()))

if strongly:
# if the graph is not connected and caller did not request retain_all, retain only the largest strongly connected component
if not nx.is_strongly_connected(G):
G = max(nx.strongly_connected_component_subgraphs(G), key=len)
log('Graph was not connected, retained only the largest strongly connected component ({:,} of {:,} total nodes) in {:.2f} seconds'.format(len(G.nodes()), original_len, time.time()-start_time))
log('Graph was not connected, retained only the largest strongly connected component ({:,} of {:,} total nodes) in {:.2f} seconds'.format(len(list(G.nodes())), original_len, time.time()-start_time))
else:
# if the graph is not connected and caller did not request retain_all, retain only the largest weakly connected component
if not nx.is_weakly_connected(G):
G = max(nx.weakly_connected_component_subgraphs(G), key=len)
log('Graph was not connected, retained only the largest weakly connected component ({:,} of {:,} total nodes) in {:.2f} seconds'.format(len(G.nodes()), original_len, time.time()-start_time))
log('Graph was not connected, retained only the largest weakly connected component ({:,} of {:,} total nodes) in {:.2f} seconds'.format(len(list(G.nodes())), original_len, time.time()-start_time))

return G

Expand Down

1 comment on commit 53b51f7

@gboeing
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolves #23

Please sign in to comment.