def convex_hull_ratio(collection): """ ratio of the area of the convex hull to the area of the shape itself Altman's A_3 measure, from Neimi et al 1991. """ ga = _cast(collection) return pygeos.area(ga) / pygeos.area(pygeos.convex_hull(ga))
def _morphological_tessellation(self, gdf, unique_id, limit, shrink, segment, verbose, check=True): objects = gdf if shrink != 0: print("Inward offset...") if verbose else None mask = objects.type.isin(["Polygon", "MultiPolygon"]) objects.loc[mask, objects.geometry.name] = objects[mask].buffer( -shrink, cap_style=2, join_style=2) objects = objects.reset_index(drop=True).explode() objects = objects.set_index(unique_id) print("Generating input point array...") if verbose else None points, ids = self._dense_point_array(objects.geometry.values.data, distance=segment, index=objects.index) hull = pygeos.convex_hull(limit) bounds = pygeos.bounds(hull) width = bounds[2] - bounds[0] leng = bounds[3] - bounds[1] hull = pygeos.buffer(hull, 2 * width if width > leng else 2 * leng) hull_p, hull_ix = self._dense_point_array( [hull], distance=pygeos.length(hull) / 100, index=[0]) points = np.append(points, hull_p, axis=0) ids = ids + ([-1] * len(hull_ix)) print("Generating Voronoi diagram...") if verbose else None voronoi_diagram = Voronoi(np.array(points)) print("Generating GeoDataFrame...") if verbose else None regions_gdf = self._regions(voronoi_diagram, unique_id, ids, crs=gdf.crs) print("Dissolving Voronoi polygons...") if verbose else None morphological_tessellation = regions_gdf[[unique_id, "geometry" ]].dissolve(by=unique_id, as_index=False) morphological_tessellation = gpd.clip( morphological_tessellation, gpd.GeoSeries(limit, crs=gdf.crs)) if check: self._check_result(morphological_tessellation, gdf, unique_id=unique_id) return morphological_tessellation
def boundary_amplitude(collection): """ The boundary amplitude (adapted from Wang & Huang (2012)) is the length of the boundary of the convex hull divided by the length of the boundary of the original shape. Notes ----- This is inverted from Wang & Huang (2012) in order to provide a value between zero and one, like many of the other ideal shape-based indices. """ ga = _cast(collection) return pygeos.measurement.length( pygeos.convex_hull(ga)) / pygeos.measurement.length(ga)
def constructive(arr, operation, *args, **kwargs): if operation == 'boundary': geometries = pg.boundary(pg.from_wkb(arr), **kwargs) elif operation == 'buffer': geometries = pg.buffer(pg.from_wkb(arr), *args, **kwargs) elif operation == 'build_area': geometries = pg.build_area(pg.from_wkb(arr), **kwargs) elif operation == 'centroid': geometries = pg.centroid(pg.from_wkb(arr), **kwargs) elif operation == 'clip_by_rect': geometries = pg.clip_by_rect(pg.from_wkb(arr), *args, **kwargs) elif operation == 'convex_hull': geometries = pg.convex_hull(pg.from_wkb(arr), **kwargs) elif operation == 'delaunay_triangles': geometries = pg.delaunay_triangles(pg.from_wkb(arr), **kwargs) elif operation == 'envelope': geometries = pg.envelope(pg.from_wkb(arr), **kwargs) elif operation == 'extract_unique_points': geometries = pg.extract_unique_points(pg.from_wkb(arr), **kwargs) elif operation == 'make_valid': geometries = pg.make_valid(pg.from_wkb(arr), **kwargs) elif operation == 'normalize': geometries = pg.normalize(pg.from_wkb(arr), **kwargs) elif operation == 'offset_curve': geometries = pg.offset_curve(pg.from_wkb(arr), *args, **kwargs) elif operation == 'point_on_surface': geometries = pg.point_on_surface(pg.from_wkb(arr), **kwargs) elif operation == 'reverse': geometries = pg.reverse(pg.from_wkb(arr), **kwargs) elif operation == 'simplify': geometries = pg.simplify(pg.from_wkb(arr), *args, **kwargs) elif operation == 'snap': geometries = pg.snap(pg.from_wkb(arr), *args, **kwargs) elif operation == 'voronoi_polygons': geometries = pg.voronoi_polygons(pg.from_wkb(arr), **kwargs) else: warnings.warn(f'Operation {operation} not supported.') return None return pg.to_wkb(geometries)
def time_convex_hull(self): pygeos.convex_hull(self.points)
def convex_hull(data): if compat.USE_PYGEOS: return pygeos.convex_hull(data) else: return _unary_geo("convex_hull", data)
def create_network_OD_points(country_network): """Create a list of OD points for the specified country Args: country ([type]): [description] Returns: [type]: [description] """ # set paths to data #data_path = Path(r'/scistor/ivm/data_catalogue/open_street_map/') data_path = Path(r'C:/data/') world_pop = data_path.joinpath('worldpop','ppp_2018_1km_Aggregated.tif') if data_path.joinpath('network_OD_points','{}.csv'.format(country_network)).is_file(): return None #print("{} already finished!".format(country_network)) try: #get country ID print('{} started!'.format(country_network)) # load data nodes = feather.read_dataframe(data_path.joinpath("percolation_networks","{}-nodes.feather".format(country_network))) nodes.geometry = pygeos.from_wkb(nodes.geometry) #create dataframe of country row geometry = pygeos.convex_hull(pygeos.multipoints(nodes.geometry.values)) df = pd.DataFrame([geometry],columns=['geometry']) #specify height of cell in the grid and create grid of bbox def create_final_od_grid(df,height_div): height = numpy.sqrt(pygeos.area(df.geometry)/height_div).values[0] grid = pd.DataFrame(create_grid(create_bbox(df),height),columns=['geometry']) #clip grid of bbox to grid of the actual spatial exterior of the country clip_grid = pygeos.intersection(grid,df.geometry) clip_grid = clip_grid.loc[~pygeos.is_empty(clip_grid.geometry)] # turn to shapely geometries again for zonal stats clip_grid.geometry = pygeos.to_wkb(clip_grid.geometry) clip_grid.geometry = clip_grid.geometry.apply(loads) clip_grid = gpd.GeoDataFrame(clip_grid) # get total population per grid cell if height < 0.01: clip_grid['tot_pop'] = clip_grid.geometry.apply(lambda x: point_query(x,world_pop)) clip_grid['tot_pop'] = clip_grid['tot_pop'].apply(lambda x: np.sum(x)) else: clip_grid['tot_pop'] = clip_grid.geometry.apply(lambda x: zonal_stats(x,world_pop,stats="sum")) clip_grid['tot_pop'] = clip_grid['tot_pop'].apply(lambda x: x[0]['sum']) # remove cells in the grid that have no population data clip_grid = clip_grid.loc[~pd.isna(clip_grid.tot_pop)] if len(clip_grid) > 100: clip_grid = clip_grid.loc[clip_grid.tot_pop > 100] clip_grid.reset_index(inplace=True,drop=True) clip_grid.geometry = clip_grid.geometry.centroid clip_grid['GID_0'] = country_network[:3] clip_grid['grid_height'] = height #print(len(clip_grid),height) return clip_grid length_clip = 0 height_div = 200 save_lengths = [] while length_clip < 150: clip_grid = create_final_od_grid(df,height_div) length_clip = len(clip_grid) save_lengths.append(length_clip) height_div += 50 if (len(save_lengths) == 6) & (numpy.mean(save_lengths[3:]) < 150): break print('{} finished with {} points!'.format(country_network,len(clip_grid))) clip_grid.to_csv(data_path.joinpath('network_OD_points','{}.csv'.format(country_network))) except: None
def convex_hull_all(arr): if isinstance(arr, LazyObj): arr = arr.values() points = pg.union_all(pg.extract_unique_points(pg.from_wkb(arr))) return pg.to_wkb(pg.convex_hull(points))
def convex_hull(arr): return pg.to_wkb(pg.convex_hull(pg.from_wkb(arr)))
def create_voronoi( points: Sequence[pygeos.Geometry]) -> Sequence[pygeos.Geometry]: mp = pygeos.multipoints(points) polys = pygeos.get_parts(pygeos.voronoi_polygons(mp)) convex_hull = pygeos.buffer(pygeos.convex_hull(mp), 2) return pygeos.intersection(convex_hull, polys)