Note
Usage | 5. Custom data imports¶
This notebook explains how custom data sets can be imported into growbikenet to adapt to a specific situation, growing more realistically.
Parameters covered: import_files
We start every Usage notebook with the standard way of importing growbikenet:
[1]:
import growbikenet as gbn
Save and import street network¶
Here we work with Athens. When running growbikenet, it uses OSMnx to fetch street network data from OSM. OSMnx has data caching implemented, so when running it multiple times on the same city, it will load the cached json data. Unfortunately, loading json is slow. To speed up this process, we can first download and save the (undirected) street network locally, under Athens_street_network.gpkg, so we can load that file fast into growbikenet whenever we
will use it (because gpkg files are loaded fast):
[2]:
import osmnx as ox
import networkx as nx
g = ox.graph_from_place("Municipality of Athens", network_type='drive')
g = nx.MultiGraph(ox.convert.to_digraph(g))
ox.io.save_graph_geopackage(g, "Athens_street_network.gpkg")
Now, we can use this local street network file with the "street_network" key inside the import_files dictionary parameter:
[3]:
edges_ranked = gbn.growbikenet("Municipality of Athens",
import_files={"street_network":"Athens_street_network.gpkg"},)
==============================================
RUNNING GROWBIKENET FOR CITY: Municipality of Athens
betweenness_centrality | auto | from scratch
----------------------------------------------╮
Importing network data : 100%|████████████████| 1/1 [00:01<00:00, 1.05s/network]
Creating seed points : 100%|████████████████| 3/3 [00:00<00:00, 4.22step/s]
Triangulation : 100%|████████████████| 1/1 [00:00<00:00, 1032.57step/s]
Routing : 100%|████████████████| 3/3 [00:00<00:00, 10.61step/s]
Computing edge metrics : 100%|████████████████| 2/2 [00:00<00:00, 322.54step/s]
Removing edge overlaps : 100%|████████████████| 59/59 [00:00<00:00, 512.57edge/s]
Exporting data : 100%|████████████████| 1/1 [00:00<00:00, 29.33step/s]
----------------------------------------------╯
Data exported to ./results/
----------------------------------------------
FINISHED IN 0:00:02
==============================================
This way, the street network file can also come from any other data provider than OSM, given that the data is in the same format, or it can be modified.
Limiting the street network definition¶
It could be possible that the city decides it will build protected bicycle infrastructure only on certain streets. Here we assume these are only the primary and secondary roads, implemented with a custom filter:
[4]:
custom_filter_streets = ['["highway"~"primary"]',
'["highway"~"secondary"]']
[5]:
g_limited = ox.graph_from_place("Municipality of Athens",
custom_filter=custom_filter_streets,
retain_all=False,) # fetch only the largest connected component
g_limited = nx.MultiGraph(ox.convert.to_digraph(g_limited))
ox.io.save_graph_geopackage(g_limited, "Athens_street_network_limited.gpkg")
This limitation selects a much smaller subnetwork (red) of the whole street network (white):
[6]:
ec = ["r" if data["highway"] == "primary" or data["highway"] == "secondary" else "w" for u, v, key, data in g.edges(keys=True, data=True)]
el = [1.5 if data["highway"] == "primary" or data["highway"] == "secondary" else 0.25 for u, v, key, data in g.edges(keys=True, data=True)]
ox.plot_graph(g, node_size=0, edge_linewidth=el, edge_color=ec);
Because this limited network is so sparse, we need to set the snap distance for seed points to a high value before running growbikenet - otherwise the resulting network will be disconnected and highly incomplete (see more details on how to use the settings in Usage notebook 6):
[7]:
gbn.settings.seed_point_snap_distance = 1500
[8]:
edges_ranked_limited = gbn.growbikenet("Municipality of Athens",
import_files={"street_network":"Athens_street_network_limited.gpkg"},)
==============================================
RUNNING GROWBIKENET FOR CITY: Municipality of Athens
betweenness_centrality | auto | from scratch
----------------------------------------------╮
Importing network data : 100%|████████████████| 1/1 [00:00<00:00, 15.80network/s]
Creating seed points : 100%|████████████████| 3/3 [00:00<00:00, 36.52step/s]
Quadrangulation : 100%|████████████████| 1/1 [00:00<00:00, 571.35step/s]
Routing : 100%|████████████████| 3/3 [00:00<00:00, 18.96step/s]
Computing edge metrics : 100%|████████████████| 2/2 [00:00<00:00, 130.94step/s]
Removing edge overlaps : 100%|████████████████| 103/103 [00:00<00:00, 471.81edge/s]
Exporting data : 100%|████████████████| 1/1 [00:00<00:00, 28.80step/s]
----------------------------------------------╯
Data exported to ./results/
----------------------------------------------
FINISHED IN 0:00:01
==============================================
Let’s reset the snap distance to 'auto' now:
[9]:
gbn.settings.seed_point_snap_distance = 'auto'
Due to the limited street network, the resulting bicycle network is also much sparser (green) than the network grown on the full street network (orange):
[10]:
import folium
viz = edges_ranked.explore(tiles="CartoDB Positron",
style_kwds={"weight": 3, "color": "#f19730"},
name="Grown bike network (on full street network)")
viz = edges_ranked_limited.iloc[1:].explore(m=viz,
style_kwds={"weight": 3, "color": "#096a51"},
name="Grown bike network (on limited street network)")
folium.LayerControl().add_to(viz)
viz
[10]:
Save and import bike network¶
Analogously, an existing bike network can be downloaded, saved, and imported. The download only needs some more preparation to set up the custom filter:
[11]:
custom_filter = ['["cycleway"~"track"]',
'["highway"~"cycleway"]',
'["highway"~"path"]["bicycle"~"designated"]',
'["cycleway:right"~"track"]',
'["cycleway:left"~"track"]',
'["cycleway:both"~"track"]',
'["cyclestreet"]',
'["highway"~"living_street"]'
]
for custom_tag in ["cycleway", "bicycle", "cycleway:right", "cycleway:left", "cycleway:both", "cyclestreet"]:
if custom_tag not in ox.settings.useful_tags_way:
ox.settings.useful_tags_way.extend(custom_tag)
[12]:
g = ox.graph_from_place("Municipality of Athens",
custom_filter=custom_filter,
retain_all=True,) #fetch all connected components
g = nx.MultiGraph(ox.convert.to_digraph(g))
ox.io.save_graph_geopackage(g, "Athens_bike_network.gpkg")
Now it can be imported with the "bike_network" key inside the import_files dictionary parameter:
[13]:
edges_ranked = gbn.growbikenet("Municipality of Athens",
existing_network_spacing='auto',
seed_point_linking ='triangulate_delaunay',
import_files={"street_network":"Athens_street_network.gpkg",
"bike_network":"Athens_bike_network.gpkg"},)
==============================================
RUNNING GROWBIKENET FOR CITY: Municipality of Athens
betweenness_centrality | auto | from existing bike network
----------------------------------------------╮
Importing network data : | | 2/? [00:01<00:00, 1.01network/s]
Creating seed points : 100%|████████████████| 4/4 [00:00<00:00, 4.80step/s]
Triangulation : 100%|████████████████| 1/1 [00:00<00:00, 771.86step/s]
Routing : 100%|████████████████| 3/3 [00:00<00:00, 8.42step/s]
Computing edge metrics : 100%|████████████████| 2/2 [00:00<00:00, 152.61step/s]
Removing edge overlaps : 100%|████████████████| 81/81 [00:00<00:00, 364.47edge/s]
Exporting data : 100%|████████████████| 1/1 [00:00<00:00, 20.74step/s]
----------------------------------------------╯
Data exported to ./results/
----------------------------------------------
FINISHED IN 0:00:04
==============================================
[14]:
import folium
viz = edges_ranked.iloc[:1].explore(tiles="CartoDB Positron",
style_kwds={"weight": 2, "color": "#9999cc"},
name="Existing bike network")
viz = edges_ranked.iloc[1:].explore(m=viz,
style_kwds={"weight": 3, "color": "#096a51"},
name="Grown bike network")
folium.LayerControl().add_to(viz)
viz
[14]:
Relaxing the bike network definition¶
The import of a custom bike network is useful to change the definition of the bike network. For example, the definition could be relaxed to also consider primary streets as protected bike infrastructure, assuming that the city plans to implement protected bike lanes along all primary streets:
[15]:
custom_filter_relaxed = custom_filter + ['["highway"~"primary"]']
[16]:
g = ox.graph_from_place("Municipality of Athens",
custom_filter=custom_filter_relaxed,
retain_all=True,) #fetch all connected components
g = nx.MultiGraph(ox.convert.to_digraph(g))
ox.io.save_graph_geopackage(g, "Athens_bike_network_relaxed.gpkg")
[17]:
edges_ranked_relaxed = gbn.growbikenet("Municipality of Athens",
existing_network_spacing='auto',
seed_point_linking ='triangulate_delaunay',
import_files={"street_network":"Athens_street_network.gpkg",
"bike_network":"Athens_bike_network_relaxed.gpkg"},)
==============================================
RUNNING GROWBIKENET FOR CITY: Municipality of Athens
betweenness_centrality | auto | from existing bike network
----------------------------------------------╮
Importing network data : | | 2/? [00:01<00:00, 1.00network/s]
Creating seed points : 100%|████████████████| 4/4 [00:01<00:00, 3.07step/s]
Triangulation : 100%|████████████████| 1/1 [00:00<00:00, 643.59step/s]
Routing : 100%|████████████████| 3/3 [00:00<00:00, 6.22step/s]
Computing edge metrics : 100%|████████████████| 2/2 [00:00<00:00, 83.45step/s]
Removing edge overlaps : 100%|████████████████| 144/144 [00:00<00:00, 159.52edge/s]
Exporting data : 100%|████████████████| 1/1 [00:00<00:00, 18.79step/s]
----------------------------------------------╯
Data exported to ./results/
----------------------------------------------
FINISHED IN 0:00:05
==============================================
This creates a different looking bicycle network:
[18]:
viz = edges_ranked_relaxed.iloc[:1].explore(tiles="CartoDB Positron",
style_kwds={"weight": 2, "color": "#9999cc"},
name="Existing bike network (relaxed)")
viz = edges_ranked_relaxed.iloc[1:].explore(m=viz,
style_kwds={"weight": 3, "color": "#096a51"},
name="Grown bike network")
folium.LayerControl().add_to(viz)
viz
[18]:
Import seed points¶
Usage notebook 1 explains how to import custom seed points.
Import city boundary¶
Rest to be written.