Using Python2.7 and shapely, let:

import shapely
coords = [(0, 0), (0, 2), (2, 0), (2, 2), (0, 0)]
bowtie = shapely.geometry.Polygon(coords)

which gives this :

Self-intersection at or near point 1 1  
Out[2]: False

So let try the buffer(0) method as describer in the doc (http://toblerity.org/shapely/manual.html):

clean = bowtie.buffer(0)

which gives that:

Out[4]: shapely.geometry.polygon.Polygon

The difference between the example in the doc is that in the present case, the crossing point is not defined in the original coordinates, so it's not resulting in a multipolygon and it's not really consistent with these initial coordinates, as this command:


shows when it returns:

Out[16]: 'POLYGON ((0 0, 0 2, 1 1, 0 0))'

And the resulting image for a more visual understanding:

bowtie cleaned polygon vs original self-intersecting bowtie polygon

Red: original self-intersecting polygon
Teal: cleaned bowtie polygon with buffer(0) method (only one half of the original polygon. Take care of the different scaling effect on iPython...)

How to easily get the original shape back with a valid geometry so that we can perform further operations like intersections, etc?

  • It seems that using slightly bigger buffer than zero has solved same kind of problems.
    – user30184
    Commented Jun 7, 2017 at 19:32
  • I've also tried in this example with buffer(0.1) to buffer(0.5) by increment 0.1; result is the same: clean is a simple polygon, not a multipolygon. Commented Jun 7, 2017 at 19:36
  • You can use GeometryCollection((bowtie, clean)) to plot both at once. Commented Jun 10, 2017 at 14:26

2 Answers 2


A different hack would be using only the exterior of the bowtie, intersecting it with itself (generating a MultiLineString), polygonizing that (generating Polygons) and finally aggregating into a MultiPolygon:

be = bowtie.exterior
mls = be.intersection(be)
polygons = polygonize(mls)
valid_bowtie = MultiPolygon(polygons)

MULTIPOLYGON (((0 0, 0 2, 1 1, 0 0)), ((2 0, 1 1, 2 2, 2 0)))

In my case, exterior was returning LinearRing, and anyway, intersection with itself didn't work because the original polygon isn't valid. I ended up finding this answer which was more helpful.

This is the code I came up with:

coords = [[0,0],[1,1],[0,1],[1,0],[0,0]]
line_non_simple = shapely.geometry.LineString(coords)
mls = shapely.ops.unary_union(line_non_simple)
polygons = list(shapely.ops.polygonize(mls))

Your Answer

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

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