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 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)] 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'] = GID_0 clip_grid['grid_height'] = height return clip_grid
def test_simplify_nan(): actual = pygeos.simplify( np.array([point, np.nan, np.nan, None, point]), np.array([np.nan, 1.0, np.nan, 1.0, 1.0]), ) assert pygeos.equals(actual[-1], point) assert pygeos.is_empty(actual[:-1]).all()
def test_intersection_nan(): actual = pygeos.intersection( np.array([point, np.nan, np.nan, point, None, None, point]), np.array([np.nan, point, np.nan, None, point, None, point]), ) assert pygeos.equals(actual[-1], point) assert pygeos.is_empty(actual[:-1]).all()
def test_get_rings(geom): if (pygeos.get_type_id(geom) != pygeos.GeometryType.POLYGON) or pygeos.is_empty(geom): rings = pygeos.get_rings(geom) assert len(rings) == 0 else: rings = pygeos.get_rings(geom) assert len(rings) == 1 assert rings[0] == pygeos.get_exterior_ring(geom)
def __init__(self, geometry): # set empty geometries to None to avoid segfault on GEOS <= 3.6 # see: # https://github.com/pygeos/pygeos/issues/146 # https://github.com/pygeos/pygeos/issues/147 non_empty = geometry.copy() non_empty[pygeos.is_empty(non_empty)] = None # set empty geometries to None to mantain indexing super().__init__(non_empty) # store geometries, including empty geometries for user access self.geometries = geometry.copy()
def _intersects_pyg(geom, gdf, sindex, tolerance=1e-9): buf = pygeos.buffer(geom, tolerance) if pygeos.is_empty(buf): # can have an empty buffer with too small a tolerance, fallback to original geom buf = geom try: return _intersects_gdf_pyg(buf, gdf, sindex) except shapely.errors.TopologicalError: #this still needs to be changed # can exceptionally buffer to an invalid geometry, so try re-buffering buf = pygeos.buffer(geom, 0) return _intersects_gdf_pyg(buf, gdf, sindex)
def trim_similarity_matrix(self, similarity_matrix, detections, ground_truths, label_mean_area=None): r"""Compute an array containing the indices in columns of similarity passing the first trimming. Here a detection/ground truth pair is kept if the detection :class:`~playground_metrics.utils.geometry_utils.geometry.Point` is within the ground truth :class:`~playground_metrics.utils.geometry_utils.geometry.BoundingBox` or :class:`~playground_metrics.utils.geometry_utils.geometry.Polygon` Args: similarity_matrix: The similarity matrix between detections and ground truths : dimension (#detection, #gt) detections (ndarray, list) : A ndarray of detections stored as: * Bounding boxes for a given class where each row is a detection stored as: ``[BoundingBox, confidence]`` * Polygons for a given class where each row is a detection stored as: ``[Polygon, confidence]`` * Points for a given class where each row is a detection stored as: ``[Point, confidence]`` ground_truths (ndarray,list) : A ndarray of ground truth stored as: * Bounding boxes for a given class where each row is a ground truth stored as: ``[BoundingBox]`` * Polygons for a given class where each row is a ground truth stored as: ``[Polygon]`` label_mean_area (float) : Optional, default to ``None``. The mean area for each label in the dataset. Returns: ndarray: An array of dimension (2, N) where each column is a tuple (detection, ground truth) describing a potential match. To be more precise, each match-tuple in the array corresponds to a position in the similarity matrix which will be used by the match algorithm to compute the final match. """ potential = np.stack(np.nonzero(similarity_matrix != -np.Inf)) potential = potential[:, np.argsort( np.nonzero(similarity_matrix != -np.Inf)[0])] trim = [] for i in range(potential.shape[1]): r, c = potential[:, i] if np.all( is_empty( intersection(detections[r, 0], ground_truths[c, 0]))): trim.append(i) return np.delete(potential, trim, axis=1)
def __init__(self, geometry): # for compatibility with old RTree implementation, store ids/indexes original_indexes = geometry.index # set empty geometries to None to avoid segfault on GEOS <= 3.6 # see: # https://github.com/pygeos/pygeos/issues/146 # https://github.com/pygeos/pygeos/issues/147 non_empty = geometry.values.data.copy() non_empty[pygeos.is_empty(non_empty)] = None # set empty geometries to None to mantain indexing self.objects = self.ids = original_indexes super().__init__(non_empty) # store geometries, including empty geometries for user access self.geometries = geometry.values.data.copy()
def _pygeos_to_shapely(geom): if geom is None: return None if compat.PYGEOS_SHAPELY_COMPAT: geom = shapely.geos.lgeos.GEOSGeom_clone(geom._ptr) return shapely.geometry.base.geom_factory(geom) # fallback going through WKB if pygeos.is_empty(geom) and pygeos.get_type_id(geom) == 0: # empty point does not roundtrip through WKB return shapely.wkt.loads("POINT EMPTY") else: return shapely.wkb.loads(pygeos.to_wkb(geom))
def country_grid_gdp_filled(trans_network, country, data_path, rough_grid_split=100, from_main_graph=False): """[summary] Args: trans_network ([type]): [description] rough_grid_split (int, optional): [description]. Defaults to 100. Returns: [type]: [description] """ if from_main_graph == True: node_df = trans_network.copy() envelop = pygeos.envelope( pygeos.multilinestrings(node_df.geometry.values)) height = np.sqrt(pygeos.area(envelop) / rough_grid_split) else: node_df = trans_network.nodes.copy() node_df.geometry, approximate_crs = convert_crs(node_df) envelop = pygeos.envelope( pygeos.multilinestrings(node_df.geometry.values)) height = np.sqrt(pygeos.area(envelop) / rough_grid_split) gdf_admin = pd.DataFrame(create_grid(create_bbox(node_df), height), columns=['geometry']) #load data and convert to pygeos country_shape = gpd.read_file(os.path.join(data_path, 'GADM', 'gadm36_levels.gpkg'), layer=0) country_shape = pd.DataFrame( country_shape.loc[country_shape.GID_0 == country]) country_shape.geometry = pygeos.from_shapely(country_shape.geometry) gdf_admin = pygeos.intersection(gdf_admin, country_shape.geometry) gdf_admin = gdf_admin.loc[~pygeos.is_empty(gdf_admin.geometry)] gdf_admin['centroid'] = pygeos.centroid(gdf_admin.geometry) gdf_admin['km2'] = area(gdf_admin) gdf_admin['gdp'] = get_gdp_values(gdf_admin, data_path) gdf_admin = gdf_admin.loc[gdf_admin.gdp > 0].reset_index() gdf_admin['gdp_area'] = gdf_admin.gdp / gdf_admin['km2'] return gdf_admin
def test_get_rings_return_index(): geom = np.array([polygon, None, empty_polygon, polygon_with_hole]) expected_parts = [] expected_index = [] for i, g in enumerate(geom): if g is None or pygeos.is_empty(g): continue expected_parts.append(pygeos.get_exterior_ring(g)) expected_index.append(i) for j in range(0, pygeos.get_num_interior_rings(g)): expected_parts.append(pygeos.get_interior_ring(g, j)) expected_index.append(i) parts, index = pygeos.get_rings(geom, return_index=True) assert len(parts) == len(expected_parts) assert np.all(pygeos.equals_exact(parts, expected_parts)) assert np.array_equal(index, expected_index)
def naive_compute_point_in_box_distance_similarity_matrix(sorted_detections, ground_truths): """Computes a similarity based on euclidean distance between all pairs of geometries in a naive fashion. Args: sorted_detections (ndarray, list) : A ndarray of detections stored as: * Bounding boxes for a given class where each row is a detection stored as: ``[BoundingBox, confidence]`` * Polygons for a given class where each row is a detection stored as: ``[Polygon, confidence]`` * Points for a given class where each row is a detection stored as: ``[Point, confidence]`` ground_truths (ndarray,list) : A ndarray of ground truth stored as: * Bounding boxes for a given class where each row is a ground truth stored as: ``[BoundingBox]`` * Polygons for a given class where each row is a ground truth stored as: ``[Polygon]`` * Points for a given class where each row is a ground truth stored as: ``[Point]`` Returns: ndarray : An similarity matrix (#detections, #ground truth) """ # We prepare the distance matrix (#detection, #gt) distance_matrix = np.zeros((sorted_detections.shape[0], len(ground_truths))) # Naive iterative distance matrix construction (Note: we iterate over the sorted detections) for k, ground_truth in enumerate(ground_truths): for m, detection in enumerate(sorted_detections): distance_matrix[m, k] = distance(centroid(detection[0]), centroid(ground_truth[0])) for i in range(distance_matrix.shape[0]): for j in range(distance_matrix.shape[1]): if is_empty(intersection(centroid(sorted_detections[i, 0]), ground_truths[j, 0])): distance_matrix[i, j] = np.inf return 1 - distance_matrix
def test_get_geometry_simple(geom): actual = pygeos.get_geometry(geom, [0, -1, 1, -2]) assert pygeos.equals(actual[0], actual[1]).all() assert pygeos.is_empty(actual[2:4]).all()
def test_from_wkt_empty(wkt): geom = pygeos.from_wkt(wkt) assert pygeos.is_geometry(geom).all() assert pygeos.is_empty(geom).all() assert pygeos.to_wkt(geom) == wkt
def is_empty(self): return pygeos.is_empty(self.g)
def test_clone_nan(): actual = pygeos.clone(np.array([point, np.nan, None])) assert pygeos.equals(actual[0], point) assert pygeos.is_empty(actual[1]) assert pygeos.is_empty(actual[2])
def test_get_geometry_collection(geom): n = pygeos.get_num_geometries(geom) actual = pygeos.get_geometry(geom, [0, -n, n, -(n + 1)]) assert pygeos.equals(actual[0], actual[1]).all() assert pygeos.is_empty(actual[2:4]).all()
(pygeos.intersection_all, pygeos.intersection), (pygeos.symmetric_difference_all, pygeos.symmetric_difference), (pygeos.union_all, pygeos.union), # (pygeos.coverage_union_all, pygeos.coverage_union) is tested seperately ) reduce_test_data = [ pygeos.box(0, 0, 5, 5), pygeos.box(2, 2, 7, 7), pygeos.box(4, 4, 9, 9), pygeos.box(5, 5, 10, 10), ] non_polygon_types = [ geom for geom in all_types if (not pygeos.is_empty(geom) and geom not in (polygon, multi_polygon)) ] @pytest.mark.parametrize("a", all_types) @pytest.mark.parametrize("func", SET_OPERATIONS) def test_set_operation_array(a, func): actual = func([a, a], point) assert actual.shape == (2, ) assert isinstance(actual[0], Geometry) @pytest.mark.parametrize("n", range(1, 5)) @pytest.mark.parametrize("func, related_func", REDUCE_SET_OPERATIONS) def test_set_operation_reduce_1dim(n, func, related_func): actual = func(reduce_test_data[:n])
def test_get_interior_ring(): actual = pygeos.get_interior_ring(polygon_with_hole, [0, -1, 1, -2]) assert pygeos.equals(actual[0], actual[1]).all() assert pygeos.is_empty(actual[2:4]).all()
def test_get_point_non_linestring(geom): actual = pygeos.get_point(geom, [0, 2, -1]) assert pygeos.is_empty(actual).all()
def is_empty(data): if compat.USE_PYGEOS: return pygeos.is_empty(data) else: return _unary_op("is_empty", data, null_value=False)
def test_from_wkb_point_empty(wkb, expected_type): geom = pygeos.from_wkb(wkb) # POINT (nan nan) transforms to an empty point # Note that the dimensionality (2D/3D) is GEOS-version dependent assert pygeos.is_empty(geom) assert pygeos.get_type_id(geom) == expected_type
def test_from_wkb_empty(wkt): wkb = pygeos.to_wkb(pygeos.Geometry(wkt)) geom = pygeos.from_wkb(wkb) assert pygeos.is_geometry(geom).all() assert pygeos.is_empty(geom).all() assert pygeos.to_wkb(geom) == wkb
def find_nhd_waterbody_breaks(geometries, nhd_lines): """Some large waterbody complexes are divided by dams; these breaks need to be preserved. This is done by finding the shared edges between adjacent waterbodies that fall near NHD lines (which include dams) and buffering them by 10 meters (arbitrary, from trial and error). This should be skipped if nhd_lines is empty. Parameters ---------- df : GeoDataFrame nhd_lines : GeoDataFrame Returns ------- MultiPolygon containing all buffered lines between waterbodies that are near NHD lines. Returns None if no adjacent waterbodies meet these criteria """ # find all nhd lines that intersect waterbodies # first, buffer them slightly nhd_lines = pg.get_parts(pg.union_all(pg.buffer(nhd_lines, 0.1))) tree = pg.STRtree(geometries) left, right = tree.query_bulk(nhd_lines, predicate="intersects") # add these to the return keep_nhd_lines = nhd_lines[np.unique(left)] # find connected boundaries boundaries = pg.polygons(pg.get_exterior_ring(geometries)) tree = pg.STRtree(boundaries) left, right = tree.query_bulk(boundaries, predicate="intersects") # drop self intersections ix = left != right left = left[ix] right = right[ix] # extract unique pairs (dedup symmetric pairs) pairs = np.array([left, right]).T pairs = ( pd.DataFrame({"left": pairs.min(axis=1), "right": pairs.max(axis=1)}) .groupby(["left", "right"]) .first() .reset_index() ) # calculate geometric intersection i = pg.intersection( geometries.take(pairs.left.values), geometries.take(pairs.right.values) ) # extract individual parts (may be geom collections) parts = pg.get_parts(pg.get_parts(pg.get_parts(i))) # extract only the lines or polygons t = pg.get_type_id(parts) parts = parts[((t == 1) | (t == 3)) & (~pg.is_empty(parts))].copy() # buffer and merge split_lines = pg.get_parts(pg.union_all(pg.buffer(parts, 10))) # now find the ones that are within 100m of nhd lines nhd_lines = pg.get_parts(nhd_lines) tree = pg.STRtree(nhd_lines) left, right = tree.nearest_all(split_lines, max_distance=100) split_lines = split_lines[np.unique(left)] if len(split_lines) or len(keep_nhd_lines): return pg.union_all(np.append(split_lines, keep_nhd_lines)) return None
def test_get_point(geom): n = pygeos.get_num_points(geom) actual = pygeos.get_point(geom, [0, -n, n, -(n + 1)]) assert pygeos.equals(actual[0], actual[1]).all() assert pygeos.is_empty(actual[2:4]).all()
def test_offset_curve_empty(): actual = pygeos.offset_curve(empty_line_string, 2.0) assert pygeos.is_empty(actual)
def test_get_interior_ring_non_polygon(geom): actual = pygeos.get_interior_ring(geom, [0, 2, -1]) assert pygeos.is_empty(actual).all()