8

I have many polygon layers, each layer containing many polygons with inner rings. I know that you can delete a ring manually with QGIS (Edit -> Delete ring). I need the python equivalent to automatically process all my polygon layers.

4 Answers 4

6

This blog posts tells how to do it with SQL in PostGIS http://geospatial.commons.gc.cuny.edu/2013/11/04/filling-in-holes-with-postgis/

Spatialite has also ExteriorRing function http://www.gaia-gis.it/gaia-sins/spatialite-sql-latest.html so you do not need to have PostGIS installed. Is it necessary for you to do the job with python inside QGIS? The SQL looks like this:

UPDATE my_spatial_table t
SET geom = a.geom
FROM (
    SELECT gid, ST_Collect(ST_MakePolygon(geom)) AS geom
    FROM (
        SELECT gid, ST_NRings(geom) AS nrings, 
            ST_ExteriorRing((ST_Dump(geom)).geom) AS geom
        FROM my_spatial_table
        WHERE ST_NRings(geom) > 1
        ) s
    GROUP BY gid, nrings
    HAVING nrings > COUNT(gid)
    ) a
WHERE t.gid = a.gid;
3

QGIS offers a tool called Delete holes that you can call via Python in this way:

import processing
vLayer = iface.activeLayer() # Select the layer in QGIS layer tree before calling this
outPath = "/path/to/output.shp"    
processing.runalg( "qgis:deleteholes", vLayer, outPath )

You could iterate through QGIS layers to run such tool on your polygon layers.

You could also access the source code of the tool to see how it works: https://github.com/qgis/QGIS/blob/release-2_14/python/plugins/processing/algs/qgis/DeleteHoles.py Note that the algorithm will change in QGIS v3.0, since there'll be a new geometry().removeInteriorRings() method: https://github.com/qgis/QGIS/blob/master/python/plugins/processing/algs/qgis/DeleteHoles.py

1

If you are comfortable using Python, including ArcPy... Try this...

You can read the shapefiles using:

Step 1:

import shapefile # Required plugin is PyShp
sf = shapefile.Reader("Path to shapefile...")

'sf' will now contain your shapefile information.

Step 2:

Use ArcPy to find the intersection of polygons. If the interior polygons intersect the larger polygon (which they obviously will), delete the shape.

More information about PyShp could be found here.

More information of ArcPy can be found here, including about the Intersection function

5
  • 1
    for arcpy, you'll need an ArcGIS licence.
    – radouxju
    Sep 10, 2014 at 6:39
  • Of course.. It can be done, without using ArcPy too.. U can use Shapely or GDAL/OGR bindings too.. See this Question
    – Akhil
    Sep 10, 2014 at 6:41
  • 1
    The question do not mention that holes are separate interior polygons so I believe that they are only inner rings in the big polygons.
    – user30184
    Sep 10, 2014 at 6:43
  • Yes... That clarifies the problem... If I understand correctly - A polygon with internal rings (input) needs a complete polygon without rings (output). Right?
    – Akhil
    Sep 10, 2014 at 6:51
  • That's correct Akhil - I specifically wanted to do it using python and PyQGis to integrate the functionality within one of my scripts. I think I'll manage thanks to all of your answers, cheers! Sep 11, 2014 at 7:08
1

shapely can do this by simply removing the .interiors of a the polygon.

Here is a complete example for removing the interiors of the first geometry of the the first feature of a geojson, assuming it's a valid Polygon:

from shapely.geometry import mapping, shape, Polygon

def load_first_feature(path):
    with open(path) as f:
        root = json.load(f)
        if "features" in root: # collection case, take first
            assert len(root["features"]) == 1
            root = root["features"][0]
        return shape(root["geometry"]

def noholes(path):
    holy = load_first_feature(path)
    assert(isinstance(holy, Polygon))
    poly = Polygon(holy.exterior.coords)
    with open('noholes.geojson', 'w') as f:
        f.write(json.dumps(mapping(poly)))

noholes('polygon-with-hole.geojson')

Sample input/output

{
    "type": "Feature",
    "properties": { "name": "union-with-holes" },
    "geometry": {
        "type": "Polygon",
        "coordinates": [
            [ [ 7, 47 ], [ 2, 49 ], [ 6, 50.6 ], [ 6, 51 ], [ 7, 51 ], [ 8, 51 ], [ 8, 48 ], [ 6, 48 ], [ 7, 47 ] ],
            [ [ 5, 49 ], [ 6, 48 ], [ 6, 50 ], [ 5, 49 ] ]
        ]
    }
}
{"type": "Polygon", "coordinates": [[[6.0, 48.0], [7.0, 47.0], [2.0, 49.0], [6.0, 50.6], [6.0, 51.0], [7.0, 51.0], [8.0, 51.0], [8.0, 48.0], [6.0, 48.0]]]}

Your Answer

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

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