Spatial Digger
Spatial Digger

Reputation: 1993

split or explode polygon into segments in geopandas or related library

I'm trying to get the individual line segments of a polygon. I want to work with each segment individually, such as get the length, get the vertices etc.

So I have a pandas geodataframe gdf

I can access the polygon through gdf.geometry

The following accesses the polygon as a linestring

for polygon in gdf.geometry:
    boundary = polygon.boundary
    print(boundary)

Adding .length() gets me the total length.

Any ideas how to split or explode out each line segment?

Upvotes: 2

Views: 3602

Answers (1)

Rob Raymond
Rob Raymond

Reputation: 31146

  • I understand that you are looking for series of pairs of Point as LineString that form the boundary of Polygon or MultiPolygon
  • have used Belgium and UK as sample polygons
  • solution is around discipline of using geometry iterators
    • for MultiPolygon it is geoms
    • for exterior which are LineArray it is coords
    • for pairs of co-ordinates use zip() technique to get pairs to reform a two point LineString
import geopandas as gpd
import shapely.geometry

world = gpd.read_file(gpd.datasets.get_path("naturalearth_lowres"))

# pick a polygon and multipolygon to create line segments from
gdf = world.loc[world["iso_a3"].isin(["BEL", "GBR"])]


line_segs = gpd.GeoSeries(
    gdf["geometry"]
    .apply(
        lambda g: [g]
        if isinstance(g, shapely.geometry.Polygon)
        else [p for p in g.geoms]
    )
    .apply(
        lambda l: [
            shapely.geometry.LineString([c1, c2])
            for p in l
            for c1, c2 in zip(p.exterior.coords, list(p.exterior.coords)[1:])
        ]
    )
    .explode()
)

# visualise it's works...
line_segs.plot()
# output for SO
print(line_segs.to_frame().head(10).to_markdown())

sample output data

geometry
129 LINESTRING (6.15665815595878 50.80372101501058, 6.043073357781111 50.12805166279423)
129 LINESTRING (6.043073357781111 50.12805166279423, 5.782417433300907 50.09032786722122)
129 LINESTRING (5.782417433300907 50.09032786722122, 5.674051954784829 49.5294835475575)
129 LINESTRING (5.674051954784829 49.5294835475575, 4.799221632515724 49.98537303323637)
129 LINESTRING (4.799221632515724 49.98537303323637, 4.286022983425084 49.90749664977255)
129 LINESTRING (4.286022983425084 49.90749664977255, 3.588184441755658 50.37899241800356)
129 LINESTRING (3.588184441755658 50.37899241800356, 3.123251580425688 50.78036326761455)
129 LINESTRING (3.123251580425688 50.78036326761455, 2.658422071960274 50.79684804951575)
129 LINESTRING (2.658422071960274 50.79684804951575, 2.513573032246143 51.14850617126183)
129 LINESTRING (2.513573032246143 51.14850617126183, 3.314971144228537 51.34578095153609)

visualize

enter image description here

join polygon attributes to line segments

  • indexes on GeoSeries and GeoDataFrame are the same
  • hence simple join allows attributes of polygon to be joined to line segments
line_segs.to_frame().join(gdf.drop(columns="geometry"))

Upvotes: 4

Related Questions