I am tyring to find if the lon and lat values are there in the shape file. When I am reading shape file, I can see the POLYGON values POLYGON ((130.8928 -12.4831, 130.8922 -12.484,..)
When I am passing the first lon, lat values which is available as first value in polygon/shape. It's still returing the FALSE value. Please suggest what I am doing wrong here?
My python code:
import geopandas as gpd
from shapely.geometry import shape, Point, Polygon
in_shp = 'C:\\shape_file.shp'
soa_shape_map = gpd.read_file(in_shp)
# Convert to WGS84
soa_shape_map_geo = soa_shape_map.to_crs(epsg=4326)
# Extract geometry
polygon = soa_shape_map_geo['geometry'].iloc[0]
# Extract coordinates and format them
formatted_polygon = [(round(coord[0], 4), round(coord[1], 4)) for coord in polygon.exterior.coords]
# Create a Shapely Polygon object
polygon_shape = Polygon(formatted_polygon)
print(f"polygon_shape: {polygon_shape}")
def check_point_in_polygon (lon, lat):
print(f"lon:{lon}")
print (f"lat: {lat}")
# build a shapely point from your geopoint
point = Point(round(lon,4), round(lat,4))
print (f"point: {point}")
# the contains function does exactly what you want
return polygon_shape.contains(point)
print (check_point_in_polygon(130.8928, -12.4831))
print (check_point_in_polygon(-12.4831, 130.8928))
I think there are multiple issues that might cause a False
value to be returned :
exterior
to get coordinates;contains
method for a point on the boundary will return False
.You might want to use the intersects
method that will work on a boundary point also.
In the following example, the use of intersects
allows for a point on the boundary to be flagged as True
when it was flagged as False
with contains
.
The two other points are here for control :
True
;False
.Here is some working code for demonstration :
import geopandas as gpd
from shapely.geometry import Polygon, MultiPolygon, Point
# We are creating MultiPolygons with holes to mimic a shapefile with random
# MultiPolygon 1
exterior1 = [(0.039427, 0.184263), (0.039632, 0.184263), (0.039632, 0.184528), (0.039427, 0.184528)]
interior1 = [(0.039487, 0.184313), (0.039487, 0.184478), (0.039572, 0.184478), (0.039572, 0.184313)]
multipolygon1 = MultiPolygon([Polygon(exterior1, [interior1])])
# MultiPolygon 2
exterior2 = [(0.058101, 0.194362), (0.058306, 0.194362), (0.058306, 0.194627), (0.058101, 0.194627)]
interior2 = [(0.058161, 0.194412), (0.058161, 0.194577), (0.058246, 0.194577), (0.058246, 0.194412)]
multipolygon2 = MultiPolygon([Polygon(exterior2, [interior2])])
# Create a GeoDataFrame to mimic shapefile import (already in EPSG 4326)
gdf = gpd.GeoDataFrame(
{"id": [1, 2],
"geometry": [multipolygon1, multipolygon2]},
crs="epsg:4326",
)
# Extract geometry without using exterior
polygon = gdf["geometry"].iloc[0]
# First function to work with contains (strict, not on boundaries)
def check_point_in_polygon_with_contains(lon, lat):
return polygon.contains(Point(lon, lat))
# Second function to works with intersects
def check_point_in_polygon_with_intersects(lon, lat):
return Point(lon, lat).intersects(polygon)
################
# 3 test cases :
################
# a) Point on boundary :
p1 = (exterior1[0][0], exterior1[0][1])
# b) Point slightly inside :
p2 = (exterior1[0][0] * 1.001, exterior1[0][1] * 1.001)
# c) Point slighlty outside :
p3 = (exterior1[0][0] * 0.999, exterior1[0][1] * 0.999)
# testing CONTAINS
print(check_point_in_polygon_with_contains(p1[0], p1[1])) # --> a) FALSE
print(check_point_in_polygon_with_contains(p2[0], p2[1])) # --> b) TRUE
print(check_point_in_polygon_with_contains(p3[0], p3[1])) # --> c) FALSE
# testing INTERSECTS
print(check_point_in_polygon_with_intersects(p1[0], p1[1])) # --> a) TRUE
print(check_point_in_polygon_with_intersects(p2[0], p2[1])) # --> b) TRUE
print(check_point_in_polygon_with_intersects(p3[0], p3[1])) # --> c) FALSE