Reputation: 11
I am trying to build a polygon from a set of long/lat tuples in python. By polygon I mean I need to define an area containing the points, something like a concave hull. The python code I use:
from shapely.geometry import Polygon
import geopandas as gpd
import geoplot
crs = {'init': 'epsg:4326'}
z=[(-88.09614, 42.21828), (-88.09605, 42.21903), (-88.09558, 42.21758), (-88.09466, 42.21857), (-88.09448, 42.2176), (-88.09425999999999, 42.2191), (-88.09406, 42.2186), (-88.09352, 42.21763), (-88.09329, 42.21859), (-88.09317, 42.21907), (-88.09226, 42.218779999999995), (-88.09185, 42.217659999999995), (-88.09176, 42.218779999999995), (-88.09138, 42.217659999999995), (-88.09127, 42.218779999999995), (-88.09094, 42.217620000000004), (-88.0907, 42.2188), (-88.09052, 42.21753), (-88.09005, 42.218709999999994), (-88.08998000000001, 42.2174), (-88.08957, 42.218309999999995), (-88.08889, 42.217290000000006), (-88.08830999999999, 42.21763)]
poly = Polygon(z)
pg=gpd.GeoDataFrame(index=[0], crs=crs, geometry=[poly])
geoplot.polyplot(pg)
and the result: view plot The points are ordered by longitude and the function considers this ordering but it's irrelevant as long as the plotted result is clearly not a polygon.
Upvotes: 1
Views: 5326
Reputation: 6757
A polygon can be, but isn't necessarily, a convex hull. In your case, you have a self-intersecting polygon, but a polygon none the less. If your goal is to compute a convex hull, you can use scipy.spatial.ConvexHull
, which uses qhull to compute convex hulls
From the documentation:
from scipy.spatial import ConvexHull, convex_hull_plot_2d
points = np.random.rand(30, 2) # 30 random points in 2-D
hull = ConvexHull(points)
and
import matplotlib.pyplot as plt
plt.plot(points[:,0], points[:,1], 'o')
for simplex in hull.simplices:
plt.plot(points[simplex, 0], points[simplex, 1], 'k-')
to plot.
The concept of a concave hull is less well defined. One possible definition are alpha shapes. These can be generated with the alphashape package. In fact, the documentation includes examples using geopandas:
import os
import geopandas
data = os.path.join(os.getcwd(), 'data', 'Public_Airports_March2018.shp')
gdf = geopandas.read_file(data)
import cartopy.crs as ccrs
gdf_proj = gdf.to_crs(ccrs.AlbersEqualArea().proj4_init)
gdf_proj.plot()
import alphashape
alpha_shape = alphashape.alphashape(gdf_proj)
alpha_shape.plot()
import matplotlib.pyplot as plt
ax = plt.axes(projection=ccrs.PlateCarree())
ax.scatter([p.x for p in gdf_proj['geometry']],
[p.y for p in gdf_proj['geometry']],
transform=ccrs.AlbersEqualArea())
ax.add_geometries(
alpha_shape['geometry'],
crs=ccrs.AlbersEqualArea(), alpha=.2)
plt.show()
Upvotes: 1