Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using cascaded_union to combine shapes gives "ValueError: No Shapely geometry can be created from null value"

Tags:

python

shapely

I have a cluster of seven overlapping circles and ellipses that I'm trying to combine into one shape, but when I run cascaded_union() I get the error:

ValueError: No Shapely geometry can be created from null value

Here's what I have written so far:

import numpy as np
import matplotlib.pyplot as plt
from shapely.geometry import Polygon
from shapely.ops import cascaded_union

x = [-1.86203523, -1.91255406, -2.03575331, -2.16247874, -2.22159676, -2.17992322,
     -2.06085035, -1.93121615, -1.86378696, -1.89641216, -1.838166,   -1.88166833,
     -1.98775658, -2.09688125, -2.14778844, -2.1119029,  -2.00936791, -1.89773847,
     -1.83967446, -1.86776838, -1.55136662, -1.60188546, -1.72508471, -1.85181013,
     -1.91092815, -1.86925461, -1.75018174, -1.62054755, -1.55311836, -1.58574355,
     -1.29187795, -1.33538028, -1.44146853, -1.5505932,  -1.60150039, -1.56561485,
     -1.46307986, -1.35145041, -1.2933864,  -1.32148032, -1.07173048, -1.11382951,
     -1.21649555, -1.32210007, -1.37136508, -1.33663714, -1.23740975, -1.12938125,
     -1.07319027, -1.10037793, -1.87340556, -1.79563936, -1.5818673,  -1.35208399,
     -1.23527147, -1.29699902, -1.50261769, -1.73670954, -1.86787402, -1.82248584,
     -1.98180156, -1.89591919, -1.66476691, -1.4180952,  -1.29436593, -1.36303087,
     -1.58554696, -1.83701142, -1.97627207, -1.92515911]
y = [0.80459679,  0.9296353,   0.98448714,  0.93836285,  0.81715295,  0.68889502,
     0.62558285,  0.66275485,  0.77954562,  0.91039814,  0.63006386,  0.73773591,
     0.78496944,  0.74525131,  0.6408761,   0.53043177,  0.47591296,  0.50792219,
     0.60849203,  0.72117057,  0.6981317,   0.82317021,  0.87802205,  0.83189777,
     0.71068786,  0.58242993,  0.51911776,  0.55628977,  0.67308054,  0.80393305,
     0.60213859,  0.70981064,  0.75704417,  0.71732605,  0.61295084,  0.50250651,
     0.44798769,  0.47999693,  0.58056676,  0.6932453,   0.77841685,  0.8826156,
     0.92832546,  0.88988856,  0.78888032,  0.6819987,   0.62923856,  0.66021523,
     0.75754088,  0.86658463,  0.84706981,  0.76282008,  0.69418295,  0.67968584,
     0.7274663,   0.81070415,  0.88267631,  0.90298332,  0.86022645,  0.77840601,
     0.56517702,  0.48654992,  0.41794253,  0.39786557,  0.43758864,  0.51481438,
     0.5861944,   0.61166165,  0.57692084,  0.50147268]

m = 7
n = 10

x_1 = np.zeros(shape=(m,n))
y_1 = np.zeros(shape=(m,n))
for i in range(m):
    for j in range(n):
        x_1[i][j] = x[j+(n*i)]
        y_1[i][j] = y[j+(n*i)]
    plt.plot(x_1[i],y_1[i])
    plt.axis('scaled')
plt.show()

Poly1 = Polygon(zip(x_1[0],y_1[0]))
Poly2 = Polygon(zip(x_1[1],y_1[1]))
Poly3 = Polygon(zip(x_1[2],y_1[2]))
Poly4 = Polygon(zip(x_1[3],y_1[3]))
Poly5 = Polygon(zip(x_1[4],y_1[4]))
Poly6 = Polygon(zip(x_1[5],y_1[5]))
Poly7 = Polygon(zip(x_1[6],y_1[6]))

polygons = [Poly1,Poly2,Poly3,Poly4,Poly5,Poly6,Poly7]

boundary = cascaded_union(polygons)

My goal is to get something like the picture on the right: enter image description here where the rest of my code will determine how many points in a random distribution fall within the boundaries of an irregular shape. I'm confused on what the error is referring to when it returns the "null value" comment. Am I not accounting for the overlap of individual shapes in the right way? From what I've searched for already cascaded_union takes an input of an array of shapes but for some reason that isn't working in this case.

like image 231
user3555455 Avatar asked Jun 10 '14 21:06

user3555455


1 Answers

All of your geometries are invalid.

[p.is_valid for p in polygons]  # [False, False, False, ...]

If you look closely at your plot, the lines used for each LinearRing cross near the start and end. This makes Polygons invalid, which inevitably yield unpredictable results.

Here's my version of what you are doing:

# Discard the first and last points from each list of coordinates
x_2 = x_1[:, 1:-1]
y_2 = y_1[:, 1:-1]
# Build a list of polygons
polygons = [Polygon(zip(x_2[i], y_2[i])) for i in range(x_2.shape[0])]
boundary = cascaded_union(polygons)  # POLYGON ((-1.343821678336245 0.4932102...
like image 192
Mike T Avatar answered Oct 23 '22 01:10

Mike T