I have a geodataframe called map
which contains a list of points and a column, Closest_TrainStation_name
which contains the name of the closest train station to that point.
geometry | Closest_TrainStation_name | |
---|---|---|
1 | POINT(1,1) | Station_1 |
2 | POINT(10,10) | Station_2 |
... | ... | ... |
Is it possible to create boundary polygons containing each group like in the picture below? With each polygon having the name of the nearest train station from the original file.
The points were made using a nearest neighbour algorithm so they won't intersect with each other.
I also have a boundary geodataframe for the whole country called boundary
which I think might be needed for defining the outer bounds of this map. And a file of the train stations.
All of the methods I can find are about making boundaries from points on the boundary, e.g. convex_hull.
sjoin()
to associate polygon with point that carries all the associated attributesimport shapely.ops
# points for hospitals
gdf = gpd.GeoDataFrame(
geometry=dfhos.loc[:, ["Longitude", "Latitude"]].apply(
shapely.geometry.Point, axis=1
)
)
# generate voroni polygon for each hospital
gdfv = gpd.GeoDataFrame(
geometry=[
p.intersection(uk)
for p in shapely.ops.voronoi_diagram(
shapely.geometry.MultiPoint(gdf["geometry"].values)
).geoms
]
)
# spatial join polygons to points to pick up full details of hospital
gdf3 = gpd.sjoin(gdfv, gdf, how="left").merge(
dfhos, left_on="index_right", right_index=True
)
gdf3["Color"] = pd.factorize(gdf3["Postcode"], sort=True)[0]
# and visualize
fig = (
px.choropleth_mapbox(
gdf3,
geojson=gdf3.__geo_interface__,
locations=gdf3.index,
hover_data=["OrganisationCode","OrganisationName","Postcode"],
color="Color",
color_continuous_scale="phase",
)
.update_layout(
mapbox={
"style": "carto-positron",
"center": {
"lon": sum(gdf3.total_bounds[[0, 2]]) / 2,
"lat": sum(gdf3.total_bounds[[1, 3]]) / 2,
},
"zoom": 5,
},
margin={"l": 0, "r": 0, "t": 0, "b": 0},
coloraxis={"showscale":False}
)
)
fig
import geopandas as gpd
import shapely.geometry
import numpy as np
import plotly.express as px
import requests, io
from pathlib import Path
from zipfile import ZipFile
import urllib
import pandas as pd
# fmt: off
# uk geometry
url = "http://geoportal1-ons.opendata.arcgis.com/datasets/687f346f5023410ba86615655ff33ca9_1.zip"
f = Path.cwd().joinpath(urllib.parse.urlparse(url).path.split("/")[-1])
if not f.exists():
r = requests.get(url, stream=True, headers={"User-Agent": "XY"})
with open(f, "wb") as fd:
for chunk in r.iter_content(chunk_size=128):
fd.write(chunk)
zfile = ZipFile(f)
zfile.extractall(f.stem)
f2 = Path.cwd().joinpath("uk.geojson")
if not f2.exists():
gdf2 = gpd.read_file(list(f.parent.joinpath(f.stem).glob("*.shp"))[0])
gdf2 = gdf2.loc[gdf2["ctyua16cd"].str[0] == "E"]
uk = gpd.GeoDataFrame(geometry=[p for p in shapely.ops.unary_union(gdf2.to_crs(gdf2.estimate_utm_crs())["geometry"].values).simplify(5000).geoms]).set_crs(gdf2.estimate_utm_crs()).to_crs("EPSG:4326")
uk.to_file(Path.cwd().joinpath("uk.geojson"), driver='GeoJSON')
uk = gpd.read_file(f2)
uk = shapely.geometry.MultiPolygon(uk["geometry"].values)
# fmt: on
# get hospitals in UK
dfhos = pd.read_csv(io.StringIO(requests.get("https://assets.nhs.uk/data/foi/Hospital.csv").text),sep="Č",engine="python",)
dfhos = dfhos.loc[lambda d: d["Sector"].eq("NHS Sector") & d["SubType"].eq("Hospital")].groupby("ParentODSCode").first()