Python – How to Create a Shapely Polygon with a Hole

pythonshapely

Sounds like a simple question, and the Shapely doc says all I need to do to create a simple polygon with a hole is to pass two lists of coordinate tuples:

exterior = [(2, 8), (7, 8), (7, 3), (2, 3), (2, 8)]
interior = [(4, 7), (4, 5), (6, 5), (6, 7), (4, 7)]
pgn = Polygon(exterior, holes=interior)

However, I get the following error:

AttributeError: 'tuple' object has no attribute '_ndim'

I also tried passing a Polygon as the interior ring.

interior=Polygon([(4, 7), (4, 5), (6, 5), (6, 7), (4, 7)])
pgn = Polygon(exterior, holes=interior)

>>> TypeError: object of type 'Polygon' has no len()

What is the correct way to use this constructor? Looks like the holes parameter should not be a tuple or a Polygon, so what should it be?

Best Answer

A polygon can have multiple holes in it, so the holes argument is a list of list of coordinate tuples:

>>> exterior = [(2, 8), (7, 8), (7, 3), (2, 3), (2, 8)]
>>> interior = [(4, 7), (4, 5), (6, 5), (6, 7), (4, 7)]

This fails:

>>> pgn = Polygon(exterior, holes=interior)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/rowlings/.local/lib/python2.7/site-packages/shapely/geometry/polygon.py", line 240, in __init__
    ret = geos_polygon_from_py(shell, holes)
  File "/home/rowlings/.local/lib/python2.7/site-packages/shapely/geometry/polygon.py", line 506, in geos_polygon_from_py
    N = exemplar._ndim
AttributeError: 'tuple' object has no attribute '_ndim'

because interior isn't a list of interior polygons, its just one. So make it a list with one member:

>>> pgn = Polygon(exterior, holes=[interior])
>>> pgn
<shapely.geometry.polygon.Polygon object at 0x7fb3639bc250>

Docs:

The second is an optional unordered sequence of ring-like sequences specifying the interior boundaries or “holes” of the feature.

The "source code" links are great working examples of the shapely API, eg this:

ext = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)]
int = [(1, 0), (0.5, 0.5), (1, 1), (1.5, 0.5), (1, 0)][::-1]
polygon = Polygon(ext, [int])

in https://shapely.readthedocs.io/en/latest/code/polygon.py