Voronoi regionalizer
In [1]:
Copied!
import geopandas as gpd
import numpy as np
import plotly.express as px
from shapely.geometry import Point
from srai.constants import WGS84_CRS
from srai.plotting.folium_wrapper import plot_regions
from srai.regionalizers import VoronoiRegionalizer, geocode_to_region_gdf
import geopandas as gpd
import numpy as np
import plotly.express as px
from shapely.geometry import Point
from srai.constants import WGS84_CRS
from srai.plotting.folium_wrapper import plot_regions
from srai.regionalizers import VoronoiRegionalizer, geocode_to_region_gdf
Regionalizer whole Earth¶
Basic usage of VoronoiRegionalizer
to cover whole Earth using 6 poles.
In [2]:
Copied!
# 6 poles of the Earth
seeds_gdf = gpd.GeoDataFrame(
{
"geometry": [
Point(0, 0),
Point(90, 0),
Point(180, 0),
Point(-90, 0),
Point(0, 90),
Point(0, -90),
]
},
index=[1, 2, 3, 4, 5, 6],
crs=WGS84_CRS,
)
# 6 poles of the Earth
seeds_gdf = gpd.GeoDataFrame(
{
"geometry": [
Point(0, 0),
Point(90, 0),
Point(180, 0),
Point(-90, 0),
Point(0, 90),
Point(0, -90),
]
},
index=[1, 2, 3, 4, 5, 6],
crs=WGS84_CRS,
)
In [3]:
Copied!
seeds_gdf.plot()
seeds_gdf.plot()
Out[3]:
<Axes: >
In [4]:
Copied!
vr = VoronoiRegionalizer(seeds=seeds_gdf)
vr = VoronoiRegionalizer(seeds=seeds_gdf)
In [5]:
Copied!
result_gdf = vr.transform()
result_gdf = vr.transform()
Generating spherical polygons: 0%| | 0/6 [00:00<?, ?it/s]
Generating spherical polygons: 33%|███▎ | 2/6 [00:00<00:00, 11.40it/s]
Generating spherical polygons: 67%|██████▋ | 4/6 [00:00<00:00, 11.71it/s]
Generating spherical polygons: 100%|██████████| 6/6 [00:00<00:00, 11.71it/s]
Generating spherical polygons: 100%|██████████| 6/6 [00:00<00:00, 11.66it/s]
Interpolating edges: 0%| | 0/36 [00:00<?, ?it/s]
Interpolating edges: 3%|▎ | 1/36 [00:00<00:13, 2.63it/s]
Interpolating edges: 100%|██████████| 36/36 [00:00<00:00, 85.08it/s]
Generating polygons: 0%| | 0/6 [00:00<?, ?it/s]
Generating polygons: 100%|██████████| 6/6 [00:00<00:00, 64.37it/s]
In [6]:
Copied!
result_gdf
result_gdf
Out[6]:
geometry | |
---|---|
region_id | |
6 | POLYGON ((180.00000 -45.18000, 180.00000 -45.2... |
4 | POLYGON ((-45.19105 -35.35420, -45.28673 -35.3... |
1 | POLYGON ((0.12722 44.99993, 0.25444 44.99972, ... |
3 | MULTIPOLYGON (((135.00000 0.08996, 135.00000 0... |
2 | POLYGON ((45.00000 0.08996, 45.00000 0.17992, ... |
5 | POLYGON ((44.80895 35.35420, 44.71327 35.39899... |
Globe view¶
In [7]:
Copied!
fig = px.choropleth(
result_gdf,
geojson=result_gdf.geometry,
locations=result_gdf.index,
color=result_gdf.index,
color_continuous_scale=px.colors.sequential.Viridis,
)
fig2 = px.scatter_geo(seeds_gdf, lat=seeds_gdf.geometry.y, lon=seeds_gdf.geometry.x)
fig.update_traces(marker={"opacity": 0.6}, selector=dict(type="choropleth"))
fig.add_trace(fig2.data[0])
fig.update_traces(marker_color="white", marker_size=10, selector=dict(type="scattergeo"))
fig.update_layout(coloraxis_showscale=False)
fig.update_geos(
projection_type="orthographic",
projection_rotation_lon=20,
projection_rotation_lat=30,
showlakes=False,
)
fig.update_layout(height=800, width=800, margin={"r": 0, "t": 0, "l": 0, "b": 0})
fig.show(renderer="png") # replace with fig.show() to allow interactivity
fig = px.choropleth(
result_gdf,
geojson=result_gdf.geometry,
locations=result_gdf.index,
color=result_gdf.index,
color_continuous_scale=px.colors.sequential.Viridis,
)
fig2 = px.scatter_geo(seeds_gdf, lat=seeds_gdf.geometry.y, lon=seeds_gdf.geometry.x)
fig.update_traces(marker={"opacity": 0.6}, selector=dict(type="choropleth"))
fig.add_trace(fig2.data[0])
fig.update_traces(marker_color="white", marker_size=10, selector=dict(type="scattergeo"))
fig.update_layout(coloraxis_showscale=False)
fig.update_geos(
projection_type="orthographic",
projection_rotation_lon=20,
projection_rotation_lat=30,
showlakes=False,
)
fig.update_layout(height=800, width=800, margin={"r": 0, "t": 0, "l": 0, "b": 0})
fig.show(renderer="png") # replace with fig.show() to allow interactivity
2D OSM View¶
In [8]:
Copied!
folium_map = plot_regions(result_gdf)
seeds_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=3),
)
folium_map = plot_regions(result_gdf)
seeds_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=3),
)
Out[8]:
Make this Notebook Trusted to load map: File -> Trust Notebook
Regionalize single country¶
Drawing a list of arbitrary points inside of the country boundary and using them for regionalization of the same geometry.
In [9]:
Copied!
uk_gdf = geocode_to_region_gdf(query=["R62149"], by_osmid=True)
uk_shape = uk_gdf.iloc[0].geometry # get the Polygon
uk_gdf = geocode_to_region_gdf(query=["R62149"], by_osmid=True)
uk_shape = uk_gdf.iloc[0].geometry # get the Polygon
In [10]:
Copied!
uk_gdf
uk_gdf
Out[10]:
geometry | |
---|---|
region_id | |
United Kingdom | MULTIPOLYGON (((-14.01552 57.60263, -14.01459 ... |
In [11]:
Copied!
def generate_random_points(shape, n_points=100):
"""Generates random points."""
minx, miny, maxx, maxy = shape.bounds
pts = []
rng = np.random.default_rng()
while len(pts) < 4:
randx = rng.uniform(minx, maxx, n_points)
randy = rng.uniform(miny, maxy, n_points)
coords = np.vstack((randx, randy)).T
# use only the points inside the geographic area
pts = [p for p in list(map(Point, coords)) if p.within(shape)]
del coords # not used any more
return pts
def generate_random_points(shape, n_points=100):
"""Generates random points."""
minx, miny, maxx, maxy = shape.bounds
pts = []
rng = np.random.default_rng()
while len(pts) < 4:
randx = rng.uniform(minx, maxx, n_points)
randy = rng.uniform(miny, maxy, n_points)
coords = np.vstack((randx, randy)).T
# use only the points inside the geographic area
pts = [p for p in list(map(Point, coords)) if p.within(shape)]
del coords # not used any more
return pts
In [12]:
Copied!
pts = generate_random_points(uk_shape)
uk_seeds_gdf = gpd.GeoDataFrame(
{"geometry": pts},
index=list(range(len(pts))),
crs=WGS84_CRS,
)
pts = generate_random_points(uk_shape)
uk_seeds_gdf = gpd.GeoDataFrame(
{"geometry": pts},
index=list(range(len(pts))),
crs=WGS84_CRS,
)
Random points on a map¶
In [13]:
Copied!
folium_map = plot_regions(uk_gdf, tiles_style="CartoDB positron")
uk_seeds_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=3),
)
folium_map = plot_regions(uk_gdf, tiles_style="CartoDB positron")
uk_seeds_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=3),
)
Out[13]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [14]:
Copied!
vr_uk = VoronoiRegionalizer(seeds=uk_seeds_gdf)
vr_uk = VoronoiRegionalizer(seeds=uk_seeds_gdf)
In [15]:
Copied!
uk_result_gdf = vr_uk.transform(gdf=uk_gdf)
uk_result_gdf = vr_uk.transform(gdf=uk_gdf)
Generating spherical polygons: 0%| | 0/34 [00:00<?, ?it/s]
Generating spherical polygons: 12%|█▏ | 4/34 [00:00<00:01, 22.37it/s]
Generating spherical polygons: 21%|██ | 7/34 [00:00<00:01, 15.00it/s]
Generating spherical polygons: 26%|██▋ | 9/34 [00:00<00:01, 15.43it/s]
Generating spherical polygons: 62%|██████▏ | 21/34 [00:00<00:00, 31.75it/s]
Generating spherical polygons: 71%|███████ | 24/34 [00:00<00:00, 27.51it/s]
Generating spherical polygons: 79%|███████▉ | 27/34 [00:01<00:00, 27.13it/s]
Generating spherical polygons: 94%|█████████▍| 32/34 [00:01<00:00, 30.21it/s]
Generating spherical polygons: 100%|██████████| 34/34 [00:01<00:00, 27.99it/s]
Interpolating edges: 0%| | 0/153 [00:00<?, ?it/s]
Interpolating edges: 93%|█████████▎| 143/153 [00:00<00:00, 1425.58it/s]
Interpolating edges: 100%|██████████| 153/153 [00:00<00:00, 1417.43it/s]
Generating polygons: 0%| | 0/34 [00:00<?, ?it/s]
Generating polygons: 76%|███████▋ | 26/34 [00:00<00:00, 245.70it/s]
Generating polygons: 100%|██████████| 34/34 [00:00<00:00, 304.23it/s]
In [16]:
Copied!
uk_result_gdf.head()
uk_result_gdf.head()
Out[16]:
geometry | |
---|---|
region_id | |
20 | POLYGON ((-5.32920 50.52689, -5.20828 50.47938... |
7 | POLYGON ((0.12792 51.01421, 0.25561 50.97351, ... |
25 | POLYGON ((1.61636 51.06241, 1.49015 51.10521, ... |
5 | POLYGON ((-0.54453 60.22916, -0.72609 60.23124... |
29 | POLYGON ((0.28454 51.21119, 0.42706 51.23794, ... |
Generated regions on a map¶
In [17]:
Copied!
folium_map = plot_regions(uk_result_gdf, tiles_style="CartoDB positron")
uk_seeds_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=3),
)
folium_map = plot_regions(uk_result_gdf, tiles_style="CartoDB positron")
uk_seeds_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=3),
)
Out[17]:
Make this Notebook Trusted to load map: File -> Trust Notebook
Higher amount of points¶
Example of railway stations in Germany (5000+ seeds) with multiprocessing.
In [18]:
Copied!
stations_csv = gpd.pd.read_csv(
"https://raw.githubusercontent.com/trainline-eu/stations/master/stations.csv",
sep=";",
index_col="id",
usecols=["id", "latitude", "longitude", "country"],
)
stations_csv
stations_csv = gpd.pd.read_csv(
"https://raw.githubusercontent.com/trainline-eu/stations/master/stations.csv",
sep=";",
index_col="id",
usecols=["id", "latitude", "longitude", "country"],
)
stations_csv
Out[18]:
latitude | longitude | country | |
---|---|---|---|
id | |||
1 | 44.081790 | 6.001625 | FR |
2 | 44.061565 | 5.997373 | FR |
3 | 44.063863 | 6.011248 | FR |
4 | 44.350000 | 6.350000 | FR |
6 | 44.088710 | 6.222982 | FR |
... | ... | ... | ... |
74657 | 45.589374 | 12.853022 | IT |
74658 | 39.721407 | 16.242717 | IT |
74659 | 51.208920 | 3.224240 | BE |
74660 | 40.466208 | 17.300564 | IT |
74661 | 43.780650 | 11.246700 | IT |
70519 rows × 3 columns
In [19]:
Copied!
stations = []
positions = set()
for idx, r in stations_csv.iterrows():
if r.country != "DE" or gpd.pd.isna(r.latitude) or gpd.pd.isna(r.longitude):
continue
pos = round(r.longitude, 5), round(r.latitude, 5)
if pos not in positions:
stations.append({"id": idx, "geometry": Point(*pos)})
positions.add(pos)
stations_gdf = gpd.GeoDataFrame(data=stations, crs=WGS84_CRS).set_index("id")
del stations_csv
del stations
del positions
stations_gdf.head()
stations = []
positions = set()
for idx, r in stations_csv.iterrows():
if r.country != "DE" or gpd.pd.isna(r.latitude) or gpd.pd.isna(r.longitude):
continue
pos = round(r.longitude, 5), round(r.latitude, 5)
if pos not in positions:
stations.append({"id": idx, "geometry": Point(*pos)})
positions.add(pos)
stations_gdf = gpd.GeoDataFrame(data=stations, crs=WGS84_CRS).set_index("id")
del stations_csv
del stations
del positions
stations_gdf.head()
Out[19]:
geometry | |
---|---|
id | |
6691 | POINT (9.03081 51.73032) |
6692 | POINT (11.80785 49.09284) |
6693 | POINT (10.48471 53.14212) |
6695 | POINT (6.59351 50.44187) |
6696 | POINT (8.31165 49.93009) |
In [20]:
Copied!
vr_rail = VoronoiRegionalizer(seeds=stations_gdf)
vr_rail = VoronoiRegionalizer(seeds=stations_gdf)
In [21]:
Copied!
rail_result_gdf = vr_rail.transform()
rail_result_gdf = vr_rail.transform()
Generating polygons: 0%| | 0/13616 [00:00<?, ?it/s]
Generating polygons: 3%|▎ | 458/13616 [00:00<00:02, 4553.99it/s]
Generating polygons: 7%|▋ | 914/13616 [00:00<00:02, 4506.06it/s]
Generating polygons: 10%|█ | 1365/13616 [00:00<00:02, 4341.90it/s]
Generating polygons: 14%|█▎ | 1844/13616 [00:00<00:02, 4510.75it/s]
Generating polygons: 17%|█▋ | 2312/13616 [00:00<00:02, 4568.13it/s]
Generating polygons: 20%|██ | 2791/13616 [00:00<00:02, 4641.08it/s]
Generating polygons: 24%|██▍ | 3273/13616 [00:00<00:02, 4698.46it/s]
Generating polygons: 28%|██▊ | 3748/13616 [00:00<00:02, 4712.32it/s]
Generating polygons: 31%|███ | 4226/13616 [00:00<00:01, 4732.06it/s]
Generating polygons: 35%|███▍ | 4700/13616 [00:01<00:01, 4691.66it/s]
Generating polygons: 38%|███▊ | 5170/13616 [00:01<00:01, 4690.71it/s]
Generating polygons: 42%|████▏ | 5656/13616 [00:01<00:01, 4739.74it/s]
Generating polygons: 45%|████▌ | 6131/13616 [00:01<00:01, 4730.31it/s]
Generating polygons: 49%|████▊ | 6605/13616 [00:01<00:01, 4496.75it/s]
Generating polygons: 52%|█████▏ | 7058/13616 [00:01<00:01, 4382.54it/s]
Generating polygons: 55%|█████▌ | 7499/13616 [00:01<00:01, 3934.40it/s]
Generating polygons: 59%|█████▊ | 7990/13616 [00:01<00:01, 4195.54it/s]
Generating polygons: 62%|██████▏ | 8456/13616 [00:01<00:01, 4324.10it/s]
Generating polygons: 66%|██████▌ | 8948/13616 [00:01<00:01, 4491.43it/s]
Generating polygons: 69%|██████▉ | 9408/13616 [00:02<00:00, 4520.44it/s]
Generating polygons: 73%|███████▎ | 9901/13616 [00:02<00:00, 4639.00it/s]
Generating polygons: 76%|███████▋ | 10396/13616 [00:02<00:00, 4729.47it/s]
Generating polygons: 80%|███████▉ | 10880/13616 [00:02<00:00, 4760.14it/s]
Generating polygons: 83%|████████▎ | 11362/13616 [00:02<00:00, 4774.97it/s]
Generating polygons: 87%|████████▋ | 11849/13616 [00:02<00:00, 4802.00it/s]
Generating polygons: 91%|█████████ | 12331/13616 [00:02<00:00, 4624.44it/s]
Generating polygons: 94%|█████████▍| 12803/13616 [00:02<00:00, 4601.44it/s]
Generating polygons: 97%|█████████▋| 13265/13616 [00:02<00:00, 4592.74it/s]
Generating polygons: 100%|██████████| 13616/13616 [00:03<00:00, 4537.52it/s]
Germany view¶
In [22]:
Copied!
folium_map = plot_regions(rail_result_gdf, tiles_style="CartoDB positron")
stations_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=1),
)
folium_map.fit_bounds([(54.98310, 5.98865), (47.30248, 15.01699)])
folium_map
folium_map = plot_regions(rail_result_gdf, tiles_style="CartoDB positron")
stations_gdf.explore(
m=folium_map,
style_kwds=dict(color="#444", opacity=1, fillColor="#f2f2f2", fillOpacity=1),
marker_kwds=dict(radius=1),
)
folium_map.fit_bounds([(54.98310, 5.98865), (47.30248, 15.01699)])
folium_map
Out[22]:
Make this Notebook Trusted to load map: File -> Trust Notebook