Network analysis in Python¶
Finding a shortest path using a specific street network is a common GIS problem that has many practical applications. For example navigators are one of those “every-day” applications where routing using specific algorithms is used to find the optimal route between two (or multiple) points.
It is also possible to perform network analysis such as tranposrtation routing in Python. Networkx is a Python module that provides a lot tools that can be used to analyze networks on various different ways. It also contains algorithms such as Dijkstras algorithm or A* algoritm that are commonly used to find shortest paths along transportation network.
To be able to conduct network analysis, it is, of course, necessary to have a network that is used for the analyses.
Osmnx package that we just explored in previous tutorial, makes it really easy to
retrieve routable networks from OpenStreetMap with different transport modes (walking, cycling and driving). Osmnx also
combines some functionalities from
networkx module to make it straightforward to conduct routing along OpenStreetMap data.
Next we will test the routing functionalities of osmnx by finding a shortest path between two points based on drivable roads.
Let’s first download the OSM data from Kamppi but this time include only such street segments that are walkable.
In omsnx it is possible to retrieve only such streets that are drivable by specifying
network_type parameter that can be used to
specify what kind of streets are retrieved from OpenStreetMap (other possibilities are
In : import osmnx as ox In : import networkx as nx In : import geopandas as gpd In : import matplotlib.pyplot as plt In : import pandas as pd In : place_name = "Kamppi, Helsinki, Finland" In : graph = ox.graph_from_place(place_name, network_type='drive') In : fig, ax = ox.plot_graph(graph)
Okey so now we have retrieved only such streets where it is possible to drive with a car. Let’s confirm this by taking a look at the attributes of the street network. Easiest way to do this is to convert the graph (nodes and edges) into GeoDataFrames.
In : edges = ox.graph_to_gdfs(graph, nodes=False, edges=True)
- Let’s check what columns do we have in our data
In : edges.columns Out: Index(['bridge', 'geometry', 'highway', 'key', 'lanes', 'length', 'maxspeed', 'name', 'oneway', 'osmid', 'u', 'v'], dtype='object')
Okey, so we have quite many columns in our GeoDataFrame. Most of the columns are fairly self-exploratory but the following table describes all of them.
|geometry||Geometry of the feature||Shapely.geometry|
|highway||Tag for roads, paths (road type)||str (list if multiple)|
|lanes||Number of lanes||int (or nan)|
|lenght||The length of a feature in meters||float|
|maxspeed||maximum legal speed limit||int (list if multiple)|
|name||Name of the (street) element||str (or nan)|
|oneway||Street is usable only in one direction||boolean|
|osmid||Unique node ids of the element||list|
|u||The first node of networkx edge tuple||int|
|v||The last node of networkx edge tuple||int|
Most of the attributes comes directly from the OpenStreetMap, however, columns
v are networkx specific ids.
- Let’s take a look what kind of features we have in
In : edges['highway'].value_counts() Out: residential 110 tertiary 82 primary 25 secondary 18 unclassified 11 living_street 4 primary_link 1 Name: highway, dtype: int64 In : print("Coordinate system:", edges.crs)