如何填充用 geopandas 溶解地理数据框时创建的多边形中的孔?

How to fill holes in Multi-polygons created when dissolving geodataframe with geopandas?

我的目标是绘制 MSOA(英国的连续地理单位)簇的边界,我已经从 here 下载了 MSOA 边界的 shapefile。然后我添加一列簇标签并使用 geopandas 溶解。

df.dissolve(by='label', aggfunc='sum')

当我使用 Folium 绘图时,有多个内孔,如附图所示。我如何删除这些?

#creates map
m = folium.Map([54.5,-3],zoom_start=6.8,tiles='cartodbpositron')

#makes boundaries plot
Boundaries = folium.GeoJson(
    df,
    name='Boundaries',
    style_function = lambda x: {
        'color': 'black',
        'weight': 3,
        'fillOpacity': 0
    }).add_to(m)
m

万一有人遇到同样的问题,我找到了一个网站,您可以从该网站上载、简化和导出名为 mapshaper 的形状文件,这成功地将我的边界简化为所需的形式。

这有望帮助您仅使用 geopandas 来组织您的多边形。您可以使用以下函数覆盖几何体。额外处理用于保留或减少 MultiPolygons。我想 MapShaper 会发生非常相似的事情,但这样您就不需要进行额外的处理。

from shapely.geometry import MultiPolygon, Polygon


def remove_interiors(poly):
    """
    Close polygon holes by limitation to the exterior ring.

    Arguments
    ---------
    poly: shapely.geometry.Polygon
        Input shapely Polygon

    Returns
    ---------
    Polygon without any interior holes
    """
    if poly.interiors:
        return Polygon(list(poly.exterior.coords))
    else:
        return poly


def pop_largest(gs):
    """
    Pop the largest polygon off of a GeoSeries

    Arguments
    ---------
    gs: geopandas.GeoSeries
        Geoseries of Polygon or MultiPolygon objects

    Returns
    ---------
    Largest Polygon in a Geoseries
    """
    geoms = [g.area for g in gs]
    return geoms.pop(geoms.index(max(geoms)))


def close_holes(geom):
    """
    Remove holes in a polygon geometry

    Arguments
    ---------
    gseries: geopandas.GeoSeries
        Geoseries of Polygon or MultiPolygon objects

    Returns
    ---------
    Largest Polygon in a Geoseries
    """
    if isinstance(geom, MultiPolygon):
        ser = gpd.GeoSeries([remove_interiors(g) for g in geom])
        big = pop_largest(ser)
        outers = ser.loc[~ser.within(big)].tolist()
        if outers:
            return MultiPolygon([big] + outers)
        return Polygon(big)
    if isinstance(geom, Polygon):
        return remove_interiors(geom)

df.geometry = df.geometry.apply(lambda p: close_holes(p))