Testing point with in/out of a vector shapefile

核能气质少年 提交于 2019-12-10 16:05:16

问题


Here is my question.

1. Intro

  • a shapefile in polygon type represent the study area

http://i8.tietuku.com/08fdccbb7e11c0a9.png

  • some point located in the whole rectangle map

http://i8.tietuku.com/877f87022bf817b8.png

I want to test whether each point was located within/out the polygon and do some further operation(for example, sum the grid point amount within the study area)

2. My idea

I have two methods all thanks to the information on stack overflow.

2.1 Idea A

Rasterize the shapefile into raster file and then test.

I haven't done that yet, but I have asked one question here and get an answer.

2.2 Idea B

I have tried to using poly.contain() to test the scatter point's location, but the result wasn't match with the reality.

3. My code based on Idea B:

For example:

  • Original data represent by pt(a pandas Dataframe) which contain 1000 grids X,Y.
  • shapefile I already shown was the study area, I want to filter the original data leaving only point within this area.
3.1 Preparation
# map four boundaries
xc1,xc2,yc1,yc2 = 113.49805889531724,115.5030664238035,37.39995194888143,38.789235929357105
# grid definition
lon_grid  = np.linspace(x_map1,x_map2,38)
lat_grid  = np.linspace(y_map1,y_map2,32)
3.1 Preparation
# generate (lon,lat)   
xx = lon_grid[pt.X.iloc[:].as_matrix()]
yy = lat_grid[pt.Y.iloc[:].as_matrix()]

sh = (len(xx),2)
data = np.zeros(len(xx)*2).reshape(*sh)
for i in range(0,len(xx),1):
    data[i] = np.array([xx[i],yy[i]])

# reading the shapefile

map = Basemap(llcrnrlon=x_map1,llcrnrlat=y_map1,urcrnrlon=x_map2,\
              urcrnrlat=y_map2)
map.readshapefile('/xx,'xx')
3.2 Test
patches=[]
for info, shape in zip(map.xxx_info, map.xxx):
    x,y=zip(*shape)
    patches.append(Polygon(np.array(shape), True) )
for poly in patches:
     mask = np.array([poly.contains_point(xy) for xy in data])
  • Then, I have a numpy array mask with value 0,1 represent the within/out.
  • Combine mask into pt ==> pt = pt[[pt.mask == 1]], I can filter the points

But the problem is using poly,contains_point(xy), I couldn't get the results match with my attempt.

An example for my idea 2

sum the value 0,1:

unique, counts = np.unique(mask, return_counts=True)      
print np.asarray((unique, counts)).T
#result:  
> [[0 7]  
  [1 3]]

http://i4.tietuku.com/7d156db62c564a30.png

From unique value, there must by 3 point within the shapefile area, but the result shows one point besides.

Another test for 40 points

http://i4.tietuku.com/5fc12514265b5a50.png

4. My problem

The result was wrong, and I haven't figured it out.
But I think the problem may happen by two reasons:

  • the polygon shapefile was wrong(a simple polygon which I don't think the problem remains here).
  • Using poly.contains_point(xy) incorrect.

Add 2016-01-16

Thanks for the answer, the reason I found out was the shapefile itself.
When I change it into shapely.polygon, it works well.

Here is my code and result

c =    fiona.open("xxx.shp")
pol = c.next()
geom = shape(pol['geometry'])
poly_data = pol["geometry"]["coordinates"][0]
poly = Polygon(poly_data)
ax.add_patch(plt.Polygon(poly_data))

xx = lon_grid[pt_select.X.iloc[:].as_matrix()]
yy = lat_grid[pt_select.Y.iloc[:].as_matrix()]

sh = (len(xx),2)
points = np.zeros(len(xx)*2).reshape(*sh)
for i in range(0,len(xx),1):
    points[i] = np.array([xx[i],yy[i]])
mask = np.array([poly.contains(Point(x, y)) for x, y in points])

ax.plot(points[:, 0], points[:, 1], "rx")
ax.plot(points[mask, 0], points[mask, 1], "ro")    

http://i4.tietuku.com/8d895efd3d9d29ff.png


回答1:


you can use shapely:

import numpy as np
from shapely.geometry import Polygon, Point

poly_data = [[0, 0], [0, 1], [1, 0], [0.2, 0.5]]
poly = Polygon(poly_data)

points = np.random.rand(100, 2)

mask = np.array([poly.contains(Point(x, y)) for x, y in points])

and here is the plot code:

import pylab as pl

fig, ax = pl.subplots()
ax.add_patch(pl.Polygon(poly_data))
ax.plot(points[:, 0], points[:, 1], "rx")
ax.plot(points[mask, 0], points[mask, 1], "ro")

the output:

You can also use MultiPoint to speed the calculation:

from shapely.geometry import Polygon, MultiPoint

poly_data = [[0, 0], [0, 1], [1, 0], [0.2, 0.5]]
poly = Polygon(poly_data)
points = np.random.rand(100, 2)
inside_points = np.array(MultiPoint(points).intersection(poly))

you can also use Polygon.contains_point() in matplotlib:

poly = pl.Polygon(poly_data)
mask = [poly.contains_point(p) for p in points]


来源:https://stackoverflow.com/questions/34825074/testing-point-with-in-out-of-a-vector-shapefile

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!