简体   繁体   中英

geopandas not recognizing point in polygon

I have two data frames. One has polygons of buildings (around 70K) and the other has points that may or not be inside the polygons (around 100K). I need to identify if a point is inside a polygon or not.

When I plot both dataframes (example below), the plot shows that some points are inside the polygons and other are not. However, when I use .within(), the outcome says none of the points are inside polygons.

I recreated the example creating one polygon and one point "by hand" rather than importing the data and in this case .within() does recognize that the point is in the polygon. Therefore, I assume I'm making a mistake but I don't know where.

Example: (I'll just post the part that corresponds to one point and one polygon for simplicity. In this case, each data frame contains either a single point or a single polygon)

1) Using the imported data. The data frame dmR has the points and the data frame dmf has the polygon

import pandas as pd
import geopandas as gpd
import numpy as np
import matplotlib.pyplot as plt
from shapely import wkt
from shapely.geometry import Point, Polygon
plt.style.use("seaborn")

# I'm skipping the data manipulation stage and 
# going to the point where the data are used.

print(dmR)

               geometry
35  POINT (-95.75207 29.76047)

print(dmf)
               geometry
41964  POLYGON ((-95.75233 29.76061, -95.75194 29.760...

# Plot
fig, ax = plt.subplots(figsize=(5,5))
minx, miny, maxx, maxy = ([-95.7525, 29.7603, -95.7515, 29.761])
ax.set_xlim(minx, maxx)
ax.set_ylim(miny, maxy)
dmR.plot(ax=ax, c='Red')
dmf.plot(ax=ax, alpha=0.5)
plt.savefig('imported_data.png')

The outcome shows that the point is inside the polygon . However,

print(dmR.within(dmf))
35       False
41964    False
dtype: bool

2) If I try to recreate this by hand, it would be as follows (there may be a better way to do this but I couldn't figure it out):

# Get the vertices of the polygon to create it by hand
poly1 = dmf['geometry']
g = [i for i in poly1]
x,y = g[0].exterior.coords.xy
x,y

(array('d', [-95.752332508564, -95.75193554162979, -95.75193151831627, -95.75232848525047, -95.752332508564]),
 array('d', [29.760606530637265, 29.760607694859385, 29.76044470363038, 29.76044237518235, 29.760606530637265]))

# Create the polygon by hand using the corresponding vertices
coords = [(-95.752332508564, 29.760606530637265),
          (-95.75193554162979, 29.760607694859385),
          (-95.75193151831627, 29.7604447036303),
          (-95.75232848525047, 29.76044237518235),
         (-95.752332508564, 29.760606530637265)]
poly = Polygon(coords)

# Create point by hand (just copy the point from 1) above
p1 = Point(-95.75207, 29.76047)

# Create the GeoPandas data frames from the point and polygon
ex = gpd.GeoDataFrame()
ex['geometry']=[poly]
ex = ex.set_geometry('geometry')
ex_p = gpd.GeoDataFrame()
ex_p['geometry'] = [p1]
ex_p = ex_p.set_geometry('geometry')

# Plot and print
fig, ax = plt.subplots(figsize=(5,5))
ax.set_xlim(minx, maxx)
ax.set_ylim(miny, maxy)
ex_p.plot(ax=ax, c='Red')
ex.plot(ax = ax, alpha=0.5)
plt.savefig('by_hand.png')

In this case, the outcome also shows the point in the polygon . However,

ex_p.within(ex)
0    True
dtype: bool

which recognize that the point is in the polygon. All suggestions on what to do are appreciated! Thanks.

I don't know if this is the most efficient way to do it but I was able to do what I needed within Python and using Geopandas.

Instead of using point.within(polygon) approach, I did a spatial join ( geopandas.sjoin(df_1, df_2, how = 'inner', op = 'contains') ) This results in a new data frame that contains the points that are within polygons and excludes the ones that are not. More information on how to do this can be found here .

I assume something is fishy about your coordinate reference system (crs). I cannot tell about dmr as it is not provided but ex_p is a naive geometry as you generated it from points without specifying the crs. You can check the crs using:

dmr.crs

Let's assume it's in 4326, then it will return:

<Geographic 2D CRS: EPSG:4326>
Name: WGS 84
Axis Info [ellipsoidal]:
- Lat[north]: Geodetic latitude (degree)
- Lon[east]: Geodetic longitude (degree)
Area of Use:
- name: World
- bounds: (-180.0, -90.0, 180.0, 90.0)
Datum: World Geodetic System 1984
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich

In this case you would need to set a CRS for ex_p first using:

ex_p = ex_p.set_crs(epsg=4326)

If you want to inherit the crs of dmr dynamically you can also use:

ex_p = ex_p.set_crs(dmr.crs)

After you set a crs, you can re-project from one crs to another using:

ex_p = ex_p.to_crs(epsg=3395)

More on that topic: https://geopandas.org/projections.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM