Fix invalid polygon in Shapely

34,708

Solution 1

I found a solution that works for the specific case given:

>>> pp2 = pp.buffer(0)
>>> pp2.is_valid
True
>>> pp2.exterior.coords[:]
[(0.0, 0.0), (0.0, 3.0), (3.0, 3.0), (3.0, 0.0), (2.0, 0.0), (0.0, 0.0)]
>>> pp2.interiors[0].coords[:]
[(2.0, 1.0), (2.0, 2.0), (1.0, 2.0), (1.0, 1.0), (2.0, 1.0)]

Solution 2

Shapely implemented a solution for this matter. Through pip you can use shapely 1.8a3 version and import this way:

from shapely.validation import make_valid

Unfortunately, if you have had to install other libraries via conda such as geopandas you will probably face a dependency problem because at this point conda only offers shapely 1.7.1 version. So you can use the shapely solution at your program as shown below:

def make_valid(ob):

from shapely.geometry.base import geom_factory
from shapely.geos import lgeos

if ob.is_valid:
    return ob
return geom_factory(lgeos.GEOSMakeValid(ob._geom))

Solution 3

Untested, but it appears that Shapely have added a function to support this now.

https://shapely.readthedocs.io/en/latest/manual.html#validation.make_valid

Solution 4

simplest solution

new_polygon = pp.buffer(0)
new_polygon.is_valid

maybe it would be work.

Solution 5

I have used the .buffer(0) method a lot, but it gave different results on Windows and on Linux. Therefore if you encounter such a problem, remember that:

Warning: The .buffer(0) function of shapely may behave different on different operating systems, i.e. Windows and Linux. I had examples, where on Linux an empty Polygon is returned while on Windows the correct non-empty Polygon is returned!

This problem took me days to solve, that's why I want to add that as an answer (my suggested edit to the accepted answer was sadly rejected).

Share:
34,708

Related videos on Youtube

jpcgt
Author by

jpcgt

Updated on July 23, 2022

Comments

  • jpcgt
    jpcgt almost 2 years

    Shapely defines a Polygon as invalid if any of its segments intersect, including segments that are colinear. Many software packages will create a region or area with a "cutout" as shown here which has colinear segments:

    enter image description here

    >>> pp = Polygon([(0,0), (0,3), (3,3), (3,0), (2,0), 
                      (2,2), (1,2), (1,1), (2,1), (2,0), (0,0)])
    >>> pp.is_valid
    WARNING:shapely.geos:Self-intersection at or near point 2 0
    False
    

    Naturally, the cutout can be implemented natively in Shapely, or this same geometry can be implemented as two valid polygons, but if I only have the list of points shown above, is there an easy to "fix" this (create valid geometry from this list of points)?

  • M Katz
    M Katz about 10 years
    I find that this buffer( 0 ) method works in general for fixing polygons with coincident lines among sub-polygons. This is very useful. Do you know of a place where this trick is officially recommended/sanctioned?
  • Rutger Hofste
    Rutger Hofste over 6 years
    This method did not fix my issue: I had some self-intersecting multipolygons.
  • Aidan Kane
    Aidan Kane over 6 years
    You need to be a little careful with the buffer(0) technique. We've had bowtie cases where it destroyed the big part of the polygon and left just a small bowtied corner. YMMV.
  • Casivio
    Casivio about 3 years
    For me it made a valid polygon but it no longer had any .exterior.coords so it still did not work for a .within(polygon) analysis.
  • José Rojas
    José Rojas almost 3 years
    Does anyone knows if a solution exists for this now? As much as i undertand @AidanKane didn't recommended the buffer(0).
  • Aidan Kane
    Aidan Kane almost 3 years
    @JoséRojas It's.....complicated. The solution we ended up using is to break invalid polygons into a map of valid polygons using shapely.ops.polygonize. We then iterated of each one and decided if it was inside or outside using winding rules. We then union the included ones together.
  • Aidan Kane
    Aidan Kane almost 3 years
    @JoséRojas See my new answer, looks like shapely have added a function to do this! shapely.readthedocs.io/en/latest/…
  • LegNaiB
    LegNaiB over 2 years
    This doesn't work, the following exception is raised: AttributeError: 'LGEOS360' object has no attribute 'GEOSMakeValid' Any objections, how to solve this? I would like to use the make_valid function but on a stable release (and no alpha release) ...
  • LegNaiB
    LegNaiB over 2 years
    buffer(0) also behaves different on different os (see my answer)!