Search code examples
pythongeopandas

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?


Solution

    • 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"))