I have shape files including all the coordinates (lat, long) of different polygons, for example the black, red, and green shown here. I would like to calculate the distance that the AB line across different polygons. I am using geopandas and also exploring gdal, but have not figured out any functions would allow this computation or I need implement from scratch. Thanks!
import shapely
import geopandas as gpd
import geopy.distance
world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))
dims = (4, 3)
a, b, c, d = world.loc[world["name"].eq("Ukraine")].total_bounds
g = 0.4
# generate some polygons and a line that cuts through some of the polygons
gdf_grid = gpd.GeoDataFrame(
geometry=[
shapely.geometry.box(minx + g, miny + g, maxx - g, maxy - g)
for minx, maxx in zip(
np.linspace(a, c, dims[0]), np.linspace(a, c, dims[0])[1:]
)
for miny, maxy in zip(
np.linspace(b, d, dims[1]), np.linspace(b, d, dims[1])[1:]
)
],
crs="epsg:4326",
)
gdf_line = gpd.GeoDataFrame(
geometry=[
shapely.geometry.LineString(
[shapely.geometry.Point(a, b), shapely.geometry.Point(c, d)]
)
],
crs="epsg:4326",
)
# start point of linestring, point we sill calc distance from
l_start = gdf_line.loc[0, "geometry"].coords[0]
# associate every polygon with the line being measures
df_x = gdf_grid.merge(gdf_line.rename(columns={"geometry": "line"}), how="cross")
# intersection will give a line string of the points where line intersects polygon
# from each of these points calc distance to start point
gdf_grid["distances"] = df_x.intersection(gpd.GeoSeries(df_x["line"])).apply(
lambda g: [round(geopy.distance.geodesic(l_start, p).km, 2) for p in g.coords]
)
# visualize ....
m = gdf_grid.explore(height=200, width=400)
gdf_line.explore(m=m, color="red")
The line does not pass through some of the polygons, hence no distances.
distances | geometry | |
---|---|---|
0 | [120.44, 658.42] | POLYGON ((27.68400190604637 45.69330801043112, 27.68400190604637 48.41419129088147, 22.48560835133485 48.41419129088147, 22.48560835133485 45.69330801043112, 27.68400190604637 45.69330801043112)) |
1 | [] | POLYGON ((27.68400190604637 49.21419129088147, 27.68400190604637 51.9350745713318, 22.48560835133485 51.9350745713318, 22.48560835133485 49.21419129088147, 27.68400190604637 49.21419129088147)) |
2 | [752.25, 937.0] | POLYGON ((33.68239546075789 45.69330801043112, 33.68239546075789 48.41419129088147, 28.48400190604637 48.41419129088147, 28.48400190604637 45.69330801043112, 33.68239546075789 45.69330801043112)) |
3 | [1176.08, 1360.15] | POLYGON ((33.68239546075789 49.21419129088147, 33.68239546075789 51.9350745713318, 28.48400190604637 51.9350745713318, 28.48400190604637 49.21419129088147, 33.68239546075789 49.21419129088147)) |
4 | [] | POLYGON ((39.68078901546941 45.69330801043112, 39.68078901546941 48.41419129088147, 34.48239546075789 48.41419129088147, 34.48239546075789 45.69330801043112, 39.68078901546941 45.69330801043112)) |
5 | [1453.4, 1985.1] | POLYGON ((39.68078901546941 49.21419129088147, 39.68078901546941 51.9350745713318, 34.48239546075789 51.9350745713318, 34.48239546075789 49.21419129088147, 39.68078901546941 49.21419129088147)) |
geometry | |
---|---|
0 | LINESTRING (22.08560835133486 45.29330801043113, 40.08078901546941 52.3350745713318) |
Two distances which relate to the two points line intersects polygons that is being hovered over
gdf_poly = world.loc[(world["continent"]=="Europe") & (~world["iso_a3"].isin(["-99","RUS"]))].copy().reset_index(drop=True)
a,b,c,d = gdf_poly.total_bounds
gdf_line = gpd.GeoDataFrame(
data={"line": ["diagonal", "vertical", "horizontal"]},
geometry=[
shapely.geometry.LineString([(a, b), (c, d)]),
shapely.geometry.LineString([((a + c) / 2, b), ((a + c) / 2, d)]),
shapely.geometry.LineString([(a, (b + d) / 2), (c, (b + d) / 2)]),
],
crs="epsg:4326",
)
# multiple lines, put distances into columns
for _, r in gdf_line.iterrows():
l_start = r["geometry"].coords[0]
gdf_poly[r["line"]] = gdf_poly.intersection(
gpd.GeoSeries([r["geometry"]] * len(gdf_poly), crs=gdf_line.crs)
).apply(
lambda g: [
round(geopy.distance.geodesic(l_start, p).km, 2)
for gg in ([g] if isinstance(g, shapely.geometry.LineString) else g.geoms)
for p in gg.coords
]
)
m = gdf_poly.explore(height=400, width=800)
gdf_line.explore(m=m, color="red")