I have many polygons, and I want to know how many holes are in the polygon using field calculator. Like this polygon that has three holes.
1 Answer
ArcGIS Polygon
objects can have one or more parts, with each part containing one or more subparts (rings).
There are a number of ways to extract the number of "holes" (interior subparts), but the easiest is to subtract the number of parts from the number of subparts. While there is a Polygon.partCount
property, there isn't a subpartCount
, but converting the Polygon
to Polyline
boundaries will generate the subparts, which can be counted. Thus the equation is:
Polygon.boundary().partCount - Polygon.partCount
We can see this work with the following script:
import arcpy
def num_holes(poly):
return poly.boundary().partCount - poly.partCount
wkts = [
'POLYGON ((0 0, 9 0, 9 9, 0 9, 0 0))',
'POLYGON ((0 0, 9 0, 9 9, 0 9, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2))',
'POLYGON ((0 0, 9 0, 9 9, 0 9, 0 0),(2 2, 2 4, 4 4, 4 2, 2 2),(7 1, 7 8, 8 8, 8 1, 7 1))',
'MULTIPOLYGON (((0 0, 5 0, 5 9, 0 9, 0 0)),((6 0, 9 0, 9 9, 6 9, 6 0)))',
'MULTIPOLYGON (((0 0, 5 0, 5 9, 0 9, 0 0),(2 2, 4 2, 4 4, 2 4, 2 2)),((6 0, 9 0, 9 9, 6 9, 6 0)))',
'MULTIPOLYGON (((0 0, 5 0, 5 9, 0 9, 0 0),(2 2, 4 2, 4 4, 2 4, 2 2)),((6 0, 9 0, 9 9, 6 9, 6 0),(7 1, 7 8, 8 8, 8 1, 7 1)))']
sr = arcpy.SpatialReference(4326)
for i,wkt in enumerate(wkts,start=1):
shp = arcpy.FromWKT(wkt,sr)
print("i={:d} parts={:d} subparts={:d} holes={:d}".format(
i,shp.partCount,shp.boundary().partCount,num_holes(shp)))
Which displays:
i=1 parts=1 subparts=1 holes=0
i=2 parts=1 subparts=2 holes=1
i=3 parts=1 subparts=3 holes=2
i=4 parts=2 subparts=2 holes=0
i=5 parts=2 subparts=3 holes=1
i=6 parts=2 subparts=4 holes=2
In CalculateField, the syntax would be:
!shape!.boundary().partCount - !shape!.partCount
-
While revisiting geometry topology to respond to an earlier comment, I came across an uncommon but interesting situation where a given visual shape has two different implementations (at least two I figured out), and those different implementations have many properties in common but not all, including number of holes. For example an inverted polygon,
'POLYGON((0 0, 10 0, 10 10, 5 10, 5 15, 10 15, 10 10, 15 10, 15 20, 0 20, 0 0))'
, and its donut hole equivalent,'POLYGON((0 0, 10 0, 10 10, 15 10, 15 20, 0 20, 0 0),(10 10, 5 10, 5 15, 10 15, 10 10))'
.– bixb0012Commented Aug 8, 2022 at 20:06 -
Esri topology has a preference, though PostGIS/OGC has a different one. Within a "valid" geometry, the answer will be right for that system. I'll poke at that example and address it if I have some insight.– VinceCommented Aug 8, 2022 at 20:14
-
Esri Check Geometry tool using Esri's rules said both are valid. Esri Check Geometry using OGC said the inverted was "non simple." I don't work with PostGIS, but SQL Server IsValidDetailed said both were valid. I thought SQL Server would be using an OGC validation but I guess not exactly.– bixb0012Commented Aug 8, 2022 at 20:22
num_interior_rings( $geometry)
that you could use directly in the field calculator to get the number of interior rings/holes. Isn't there anything similar in ArcGIS?