2

I would like to find the common area between my polygons, in this example my polygons touch and share a line See Here

df = GeoDataFrame.from_file('path')
df

                                            geometry  id
0  POLYGON ((598298.993 2436032.831, 598294.993 2...   1
1  POLYGON ((598090.693 2436754.332, 598312.993 2...   2

df.iloc[1].geometry.touches(df.iloc[0].geometry)

True

When I verify if my polygons touch, I get True as response. So I would like to get the length of the line shared between them

2 Answers 2

0

You can spatial join the dataframe to itself, intersect, the output will be the lines where two polygons share a border, and measure length:

import geopandas as gpd
import numpy as np
df = gpd.read_file(r"/home/bera/Desktop/GIStest/shared_length.shp")
#    id                                           geometry
# 0   1  POLYGON ((594912.796 7238961.152, 596731.160 7...
# 1   2  POLYGON ((594912.796 7238961.152, 595300.862 7...
# 2   3  POLYGON ((595300.862 7239216.167, 594912.796 7...
# 3   4  POLYGON ((598039.495 7240524.502, 598294.510 7...

df["geombackup"] = df.geometry
sj = gpd.sjoin(df[["id","geometry"]], df[["id","geombackup","geometry"]], how="left", predicate="intersects")
# sj[["id_left","id_right","geombackup"]].head()
#    id_left  id_right                                         geombackup
# 0        1         1  POLYGON ((594912.796 7238961.152, 596731.160 7...
# 0        1         2  POLYGON ((594912.796 7238961.152, 595300.862 7...
# 0        1         3  POLYGON ((595300.862 7239216.167, 594912.796 7...
# 1        2         1  POLYGON ((594912.796 7238961.152, 596731.160 7...
# 1        2         2  POLYGON ((594912.796 7238961.152, 595300.862 7...

#Drop self joins, like the first row above
sj = sj.loc[sj["id_left"]!=sj["id_right"]] 

#Drop duplicates, like the second row is the same as 4th. 1-2 and 2-1. https://stackoverflow.com/questions/55480504/efficient-way-in-pandas-for-removing-columns-with-duplicate-values-in-different
mask = gpd.pd.DataFrame(np.sort(sj[["id_left","id_right"]].values, axis=1)).duplicated().to_list()
sj = sj[[not x for x in mask]]

sj["borderline"] = sj.apply(lambda x: x["geometry"].intersection(x["geombackup"]), axis=1)
# sj[["id_left","id_right","borderline"]].head(1)
#    id_left  id_right                                         borderline
# 0        1         2  LINESTRING (594912.796 7238961.152, 596731.160...

sj["borderlength"] = sj["borderline"].length

sj = sj.set_geometry(col="borderline", crs=df.crs).drop(columns=["geometry","geombackup"])
sj.to_file(r"/home/bera/Desktop/GIStest/shared_borders.shp")

enter image description here

0

If your polygons are exactly as depicted, you can:

  1. Merge the polygons and calculate the perimeter.
  2. Calculate the perimeters separately.

The difference will be 2x the length of shared line. The code would be something like:

shared_length = (df.geometry.length.sum() - df.geometry.unary_union.length) / 2

However, this won't be robust to imprecise geometries.

If you want the area of overlap, use the same principle: the area of the separate polygons minus the area of the union.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.