# How to inverse the orientation of the holes coordinates of a polygon in geopandas

I have a polygon shapefile which I am reading with geopandas. The polygon contains holes. My purpose is to add a random point inside each hole. In order to create the points inside the holes (interior polygon rings), the definition of their coordinates needs to be reversed (from counterclockwise to clockwise) otherwise the point falls outside of the polygon.

I get the coordinates of the interior rings using `GeoSeries.interiors` and what I get is

LINEARRING (85002.811 446988.023, 85010.79399999999 446992.869, 85005.61900000001 447001.417, 84982.78599999999 446987.513, 84987.933 446978.99, 85001.89999999999 446987.47, 85002.811 446988.023)

How can I reverse the definition of the coordinates? Alternatively, I could get the x,y coordinates in a list and reverse it, but even in this case I cannot find a way to convert the geometry to list.

• Can you post the entire geometry, with the interior rings inside? Apr 10, 2019 at 20:52
• You can use shapely for that. Geopandas uses fiona, a gdal/ogr wrapper for python for reading and writing from various geodata file formats. As far as i know geopandas does not support any geometric operations, but Shapely does. Apr 10, 2019 at 21:08

Since the orientation of the exterior ring doesn't matter, you could use the `shapely.geometry.polygon.orient` function, which will orient the interiors colckwise or counterclockwise.

Simple example:

``````from shapely.geometry import Polygon
from shapely.geometry import polygon
pol = Polygon([(0,0),(1,0),(1,1),(0,1)],[[(0.1,0.1),(0.1,0.2),(0.2,0.2)]])

[[*p.coords] for p in polygon.orient(pol,-1).interiors]
#Out[]: [[(0.1, 0.1), (0.2, 0.2), (0.1, 0.2), (0.1, 0.1)]]
[[*p.coords] for p in polygon.orient(pol,1).interiors]
#Out[]: [[(0.1, 0.1), (0.1, 0.2), (0.2, 0.2), (0.1, 0.1)]]
``````

In geopandas you will map the function over the gemetry column with:

``````new_geometry_series = dataframe.geometry.apply(polygon.orient,args=(1)) #or -1
``````

This should do what you want, and works in cases where a polygon has multiple holes. It involves using `shapely`, which is a `geopandas` dependency.

``````import geopandas as gpd
from shapely.geometry import Polygon

# Initializing a polygon with two holes
# See: https://stackoverflow.com/questions/48770822/how-to-make-holes-in-a-polygon-in-shapely-python-having-polygons
outer = Polygon(((0,0),(20,0),(20,20),(0,20),(0,0)))
inners = (Polygon(((4,4),(4,6),(6,6),(6,4),(4,4))), Polygon(((7,7),(7,8),(8,8),(8,7),(7,7))))
p = Polygon(outer.exterior.coords, [inner.exterior.coords for inner in inners])

# Make a geoseries with this polygon
gs = gpd.GeoSeries({0: p})

print("Before:")
print(gs[0])

# Get the interiors and initialize a list for new interior polygons
interiors = gs.interiors
reversed_interior_polys = []

# Iterate through the interiors, and through their subsequent rings
for interior in interiors:
for ring in interior:
# Unpack the ring's coordinates and convert it to a polygon
interior_poly_reversed = Polygon(list(ring.coords)[::-1])
reversed_interior_polys.append(interior_poly_reversed)
reversed_interior_polys = tuple(reversed_interior_polys)

# Reconstruct the original polygon from the list reversed polygons we just made
# See (again): https://stackoverflow.com/questions/48770822/how-to-make-holes-in-a-polygon-in-shapely-python-having-polygons
fixed_polygon = Polygon(outer.exterior.coords, [inner.exterior.coords for inner in reversed_interior_polys])

# Map this value back to the GeoSeries
gs[0] = fixed_polygon

print("\nAfter:")
print(gs[0])
``````

Output:

``````Before:
POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0), (4 4, 4 6, 6 6, 6 4, 4 4), (7 7, 7 8, 8 8, 8 7, 7 7))

After:
POLYGON ((0 0, 20 0, 20 20, 0 20, 0 0), (4 4, 6 4, 6 6, 4 6, 4 4), (7 7, 8 7, 8 8, 7 8, 7 7))
``````

You can extract the interior rings with `.interiors`, Polygonize them, and sample a point inside each.

``````import geopandas as gpd
from shapely.geometry import Polygon