Generate a network
For more details on downloading for a boundary, see this example .
Assume we have the following network.
import osmnx as ox
from cityseer.tools import io, plot
bounds_gdf = ox.geocode_to_gdf(
"R1536593" , # OSM relation ID
by_osmid= True ,
)
bounds_gdf = bounds_gdf.to_crs(3035 ) # projected CRS
bounds_geom = bounds_gdf.union_all().simplify(500 )
G_nx = io.osm_graph_from_poly(
bounds_geom,
poly_crs_code= 3035 , # set to your CRS
to_crs_code= 3035 , # output CRS
simplify= False , # set to True for automatic simplification
)
plot.plot_nx(G_nx, plot_geoms= True )
INFO:cityseer.tools.io:Converting networkX graph from EPSG code 4326 to EPSG code 3035.
INFO:cityseer.tools.io:Processing node x, y coordinates.
0%| | 0/18052 [00:00<?, ?it/s]100%|██████████| 18052/18052 [00:00<00:00, 686221.08it/s]
INFO:cityseer.tools.io:Processing edge geom coordinates, if present.
0%| | 0/19745 [00:00<?, ?it/s]100%|██████████| 19745/19745 [00:00<00:00, 1416757.03it/s]
INFO:cityseer.tools.graphs:Generating interpolated edge geometries.
0%| | 0/19745 [00:00<?, ?it/s] 56%|█████▌ | 11003/19745 [00:00<00:00, 110021.97it/s]100%|██████████| 19745/19745 [00:00<00:00, 108997.23it/s]
INFO:cityseer.tools.graphs:Removing filler nodes.
0%| | 0/18052 [00:00<?, ?it/s] 6%|▌ | 994/18052 [00:00<00:01, 9911.44it/s] 12%|█▏ | 2159/18052 [00:00<00:01, 10902.39it/s] 18%|█▊ | 3321/18052 [00:00<00:01, 11194.64it/s] 25%|██▌ | 4563/18052 [00:00<00:01, 11663.64it/s] 33%|███▎ | 5902/18052 [00:00<00:00, 12270.56it/s] 40%|███▉ | 7189/18052 [00:00<00:00, 12463.58it/s] 47%|████▋ | 8436/18052 [00:00<00:00, 12459.81it/s] 54%|█████▍ | 9736/18052 [00:00<00:00, 12585.45it/s] 62%|██████▏ | 11102/18052 [00:00<00:00, 12911.15it/s] 69%|██████▊ | 12394/18052 [00:01<00:00, 12909.79it/s] 76%|███████▌ | 13686/18052 [00:01<00:00, 12559.57it/s] 83%|████████▎ | 14944/18052 [00:01<00:00, 12417.87it/s] 90%|█████████ | 16329/18052 [00:01<00:00, 12840.57it/s] 98%|█████████▊| 17616/18052 [00:01<00:00, 12770.29it/s]100%|██████████| 18052/18052 [00:01<00:00, 12455.77it/s]
INFO:cityseer.tools.graphs:Ironing edges.
0%| | 0/6961 [00:00<?, ?it/s] 8%|▊ | 587/6961 [00:00<00:01, 5862.50it/s] 17%|█▋ | 1189/6961 [00:00<00:00, 5947.04it/s] 27%|██▋ | 1845/6961 [00:00<00:00, 6224.10it/s] 36%|███▌ | 2489/6961 [00:00<00:00, 6305.25it/s] 45%|████▌ | 3137/6961 [00:00<00:00, 6363.99it/s] 54%|█████▍ | 3774/6961 [00:00<00:00, 6348.27it/s] 63%|██████▎ | 4420/6961 [00:00<00:00, 6383.97it/s] 73%|███████▎ | 5059/6961 [00:00<00:00, 6306.64it/s] 82%|████████▏ | 5702/6961 [00:00<00:00, 6343.92it/s] 91%|█████████ | 6337/6961 [00:01<00:00, 6279.97it/s]100%|██████████| 6961/6961 [00:01<00:00, 6291.37it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 1.
0%| | 0/6961 [00:00<?, ?it/s]100%|██████████| 6961/6961 [00:00<00:00, 201654.52it/s]
INFO:cityseer.tools.plot:Preparing graph nodes
INFO:cityseer.tools.plot:Preparing graph edges
0%| | 0/6954 [00:00<?, ?it/s] 35%|███▌ | 2453/6954 [00:00<00:00, 24519.09it/s] 71%|███████ | 4905/6954 [00:00<00:00, 14898.79it/s] 95%|█████████▍| 6603/6954 [00:00<00:00, 12087.91it/s]100%|██████████| 6954/6954 [00:00<00:00, 12741.10it/s]
Convert to GeoPandas
You can now convert the network to a geopandas
GeoDataFrame
.
# convert to a LineString GeoDataFrame
edges_gdf = io.geopandas_from_nx(G_nx, crs= 3035 )
edges_gdf.head()
INFO:cityseer.tools.io:Preparing node and edge arrays from networkX graph.
0
LINESTRING (3686135.767 2665023.326, 3686194.5...
[rue francoise dolto, rue de gireugne]
[]
[tertiary]
448239596
10746741880
0
1
LINESTRING (3686215.164 2665464.119, 3686216.1...
[rue de gireugne]
[]
[tertiary]
10746741880
1969279930
0
2
LINESTRING (3686586.641 2665354.037, 3686435.5...
[]
[]
[track]
10746741880
10746741876
0
3
LINESTRING (3683478.127 2667452.761, 3683515.2...
[rue de chatellerault]
[d 925]
[secondary]
1563458310
1527199968
0
4
LINESTRING (3683926.884 2667717.073, 3683959.4...
[rue de chatellerault]
[d 925]
[secondary]
1527199968
9328420068
0
Save
It is then possible to save the GeoDataFrame
. Create a temp
folder or update your path accordingly:
from pathlib import Path
# create the directory if necessary
Path.mkdir(Path("temp" ), exist_ok= True )
edges_gdf.to_file("temp/output_file.gpkg" )
INFO:pyogrio._io:Created 6,954 records
The GPKG file can now be explored or modified in GIS software such as QGIS.
Reload
To reload, you can read the LineString
file with geopandas
.
import geopandas as gpd
in_edges_gdf = gpd.read_file("temp/output_file.gpkg" )
in_edges_gdf.head()
0
['rue francoise dolto', 'rue de gireugne']
[]
['tertiary']
448239596
10746741880
0
LINESTRING (3686135.767 2665023.326, 3686194.5...
1
['rue de gireugne']
[]
['tertiary']
10746741880
1969279930
0
LINESTRING (3686215.164 2665464.119, 3686216.1...
2
[]
[]
['track']
10746741880
10746741876
0
LINESTRING (3686586.641 2665354.037, 3686435.5...
3
['rue de chatellerault']
['d 925']
['secondary']
1563458310
1527199968
0
LINESTRING (3683478.127 2667452.761, 3683515.2...
4
['rue de chatellerault']
['d 925']
['secondary']
1527199968
9328420068
0
LINESTRING (3683926.884 2667717.073, 3683959.4...
Convert back to nx
Then use cityseer
to convert the LineString
GeoDataFrame
back into a networkx
graph.
in_G_nx = io.nx_from_generic_geopandas(in_edges_gdf)
plot.plot_nx(in_G_nx, plot_geoms= True )
0%| | 0/6954 [00:00<?, ?it/s] 10%|█ | 718/6954 [00:00<00:00, 7177.83it/s] 21%|██ | 1451/6954 [00:00<00:00, 7264.64it/s] 31%|███▏ | 2178/6954 [00:00<00:00, 7180.70it/s] 42%|████▏ | 2921/6954 [00:00<00:00, 7275.64it/s] 53%|█████▎ | 3667/6954 [00:00<00:00, 7338.23it/s] 63%|██████▎ | 4401/6954 [00:00<00:00, 5005.25it/s] 74%|███████▍ | 5131/6954 [00:00<00:00, 5565.32it/s] 85%|████████▍ | 5881/6954 [00:00<00:00, 6070.57it/s] 95%|█████████▌| 6615/6954 [00:01<00:00, 6414.58it/s]100%|██████████| 6954/6954 [00:01<00:00, 6394.35it/s]
INFO:cityseer.tools.graphs:Merging parallel edges within buffer of 1.
0%| | 0/6952 [00:00<?, ?it/s]100%|██████████| 6952/6952 [00:00<00:00, 173975.41it/s]
INFO:cityseer.tools.plot:Preparing graph nodes
INFO:cityseer.tools.plot:Preparing graph edges
0%| | 0/6952 [00:00<?, ?it/s] 32%|███▏ | 2250/6952 [00:00<00:00, 22481.15it/s] 65%|██████▍ | 4499/6952 [00:00<00:00, 14818.86it/s] 88%|████████▊ | 6129/6952 [00:00<00:00, 11416.97it/s]100%|██████████| 6952/6952 [00:00<00:00, 11516.06it/s]