Tuesday, 30 January 2018

shapely - Finding differences between two shapefiles in Python


I'm trying to find out whether there were any border changes between two yearly shapefiles. I've heard a lot of praise for Python's open source GIS tools like Shapely/Fiona, and thought I would try those, but I'm at a loss for how to go about implementing this. Is Shapely poorly suited for this task, and, if so, what tool would be better? Any advice you have would be greatly appreciated. Thanks!



Answer



Suppose we have two polygons (green and blue):


enter image description here


They are not equal (as Fetzer suggest):


green.equals(blue)
False


and


blue.equals(green)
False

And we can can determine the difference (in red):


blue.difference(green)

enter image description here


and


green.difference(blue)


gives an empty geometry


Thus, you can use a supplementary condition:


if not poly1.difference(poly2).is_empty:
process

And if you want to find the nodes that have been modified:


 S1 = set(list(blue.difference(green).exterior.coords)
S2 = set(list(blue.exterior.coords)
S3 = set(list(green.exterior.coords)


S1 - S2 and S1 - S3 gives the points (two here blue and red):


enter image description here


and the distance:


point1.distance(point2)

New : compare multiple polygons:


Here is one solution:
For that, I use Fiona to open the polygon shapefiles and save a resulting shapefile with differences:


enter image description here



import fiona
from shapely.geometry import shape
green = fiona.open("poly1.shp")
blue = fiona.open("poly2.shp")
# test the function difference between green and blue shapefiles
[not shape(i['geometry']).difference(shape(j['geometry'])).is_empty for i,j in zip(list(green),list(blue))]
[False, False, False, True]
# control
for geom in [shape(i['geometry']).difference(shape(j['geometry'])) for i,j in zip(list(green),list(blue))]:
print geom

GEOMETRYCOLLECTION EMPTY
GEOMETRYCOLLECTION EMPTY
GEOMETRYCOLLECTION EMPTY
POLYGON ((-0.0806077747083538 0.6329375155131045, 0.0085568963219002 0.5081069760707490, -0.0816567708381215 0.6025166277498414, -0.1529885076623247 0.5437728444828506, -0.1292856235630944 0.6206937720158269, -0.0806077747083538 0.6329375155131045))
# test the function difference between blue and green shapefiles
[not shape(i['geometry']).difference(shape(j['geometry'])).is_empty for i,j in zip(list(blue),list(green))]
[True, False, False, False]
# control
for geom in [shape(i['geometry']).difference(shape(j['geometry'])) for i,j in zip(list(blue),list(green))]:
print geom

POLYGON ((0.2292711598746081 0.7386363636363635, 0.6691026645768023 0.6691026645768023, 0.2440830721003134 0.7205329153605015, 0.1074843260188087 0.3452978056426331, 0.2292711598746081 0.7386363636363635))
GEOMETRYCOLLECTION EMPTY
GEOMETRYCOLLECTION EMPTY
GEOMETRYCOLLECTION EMPTY
# thus you can write a resulting shapefile withe the differences
from shapely.geometry import mapping
schema = {'geometry': 'Polygon','properties': {'test': 'int'}}
with fiona.open('diff.shp','w','ESRI Shapefile', schema) as e:
for geom in [shape(i['geometry']).difference(shape(j['geometry'])) for i,j in zip(list(green),list(blue)]:
if not geom.is_empty:

e.write({'geometry':mapping(geom), 'properties':{'test':1}})
for geom in [shape(i['geometry']).difference(shape(j['geometry'])) for i,j in zip(list(blue),list(green))]:
if not geom.is_empty:
e.write({'geometry':mapping(geom), 'properties':{'test':2}})

Result:


enter image description here


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...