ssb-sgis 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sgis/__init__.py +97 -115
- sgis/exceptions.py +3 -1
- sgis/geopandas_tools/__init__.py +1 -0
- sgis/geopandas_tools/bounds.py +75 -38
- sgis/geopandas_tools/buffer_dissolve_explode.py +38 -34
- sgis/geopandas_tools/centerlines.py +53 -44
- sgis/geopandas_tools/cleaning.py +87 -104
- sgis/geopandas_tools/conversion.py +149 -101
- sgis/geopandas_tools/duplicates.py +31 -17
- sgis/geopandas_tools/general.py +76 -48
- sgis/geopandas_tools/geometry_types.py +21 -7
- sgis/geopandas_tools/neighbors.py +20 -8
- sgis/geopandas_tools/overlay.py +136 -53
- sgis/geopandas_tools/point_operations.py +9 -8
- sgis/geopandas_tools/polygon_operations.py +48 -56
- sgis/geopandas_tools/polygons_as_rings.py +121 -78
- sgis/geopandas_tools/sfilter.py +14 -14
- sgis/helpers.py +114 -56
- sgis/io/dapla_functions.py +32 -23
- sgis/io/opener.py +13 -6
- sgis/io/read_parquet.py +1 -1
- sgis/maps/examine.py +39 -26
- sgis/maps/explore.py +112 -66
- sgis/maps/httpserver.py +12 -12
- sgis/maps/legend.py +124 -65
- sgis/maps/map.py +66 -41
- sgis/maps/maps.py +31 -29
- sgis/maps/thematicmap.py +46 -33
- sgis/maps/tilesources.py +3 -8
- sgis/networkanalysis/_get_route.py +5 -4
- sgis/networkanalysis/_od_cost_matrix.py +44 -1
- sgis/networkanalysis/_points.py +10 -4
- sgis/networkanalysis/_service_area.py +5 -2
- sgis/networkanalysis/closing_network_holes.py +20 -62
- sgis/networkanalysis/cutting_lines.py +55 -43
- sgis/networkanalysis/directednetwork.py +15 -7
- sgis/networkanalysis/finding_isolated_networks.py +4 -3
- sgis/networkanalysis/network.py +15 -13
- sgis/networkanalysis/networkanalysis.py +72 -54
- sgis/networkanalysis/networkanalysisrules.py +20 -16
- sgis/networkanalysis/nodes.py +2 -3
- sgis/networkanalysis/traveling_salesman.py +5 -2
- sgis/parallel/parallel.py +337 -127
- sgis/raster/__init__.py +6 -0
- sgis/raster/base.py +9 -3
- sgis/raster/cube.py +280 -208
- sgis/raster/cubebase.py +15 -29
- sgis/raster/indices.py +3 -7
- sgis/raster/methods_as_functions.py +0 -124
- sgis/raster/raster.py +313 -127
- sgis/raster/torchgeo.py +58 -37
- sgis/raster/zonal.py +38 -13
- {ssb_sgis-1.0.1.dist-info → ssb_sgis-1.0.2.dist-info}/LICENSE +1 -1
- {ssb_sgis-1.0.1.dist-info → ssb_sgis-1.0.2.dist-info}/METADATA +87 -16
- ssb_sgis-1.0.2.dist-info/RECORD +61 -0
- {ssb_sgis-1.0.1.dist-info → ssb_sgis-1.0.2.dist-info}/WHEEL +1 -1
- sgis/raster/bands.py +0 -48
- sgis/raster/gradient.py +0 -78
- ssb_sgis-1.0.1.dist-info/RECORD +0 -63
sgis/geopandas_tools/general.py
CHANGED
|
@@ -1,30 +1,35 @@
|
|
|
1
1
|
import numbers
|
|
2
2
|
import warnings
|
|
3
|
-
from collections.abc import Hashable
|
|
3
|
+
from collections.abc import Hashable
|
|
4
|
+
from collections.abc import Iterable
|
|
4
5
|
from typing import Any
|
|
5
6
|
|
|
7
|
+
import dask_geopandas
|
|
6
8
|
import joblib
|
|
7
9
|
import numpy as np
|
|
8
10
|
import pandas as pd
|
|
9
11
|
import pyproj
|
|
10
|
-
from geopandas import GeoDataFrame
|
|
11
|
-
from geopandas
|
|
12
|
+
from geopandas import GeoDataFrame
|
|
13
|
+
from geopandas import GeoSeries
|
|
14
|
+
from geopandas.array import GeometryArray
|
|
15
|
+
from geopandas.array import GeometryDtype
|
|
12
16
|
from numpy.typing import NDArray
|
|
13
|
-
from shapely import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
make_valid,
|
|
22
|
-
)
|
|
17
|
+
from shapely import Geometry
|
|
18
|
+
from shapely import get_coordinates
|
|
19
|
+
from shapely import get_exterior_ring
|
|
20
|
+
from shapely import get_interior_ring
|
|
21
|
+
from shapely import get_num_interior_rings
|
|
22
|
+
from shapely import get_parts
|
|
23
|
+
from shapely import linestrings
|
|
24
|
+
from shapely import make_valid
|
|
23
25
|
from shapely import points as shapely_points
|
|
24
26
|
from shapely import unary_union
|
|
25
|
-
from shapely.geometry import LineString
|
|
27
|
+
from shapely.geometry import LineString
|
|
28
|
+
from shapely.geometry import Point
|
|
26
29
|
|
|
27
|
-
from .geometry_types import get_geom_type
|
|
30
|
+
from .geometry_types import get_geom_type
|
|
31
|
+
from .geometry_types import make_all_singlepart
|
|
32
|
+
from .geometry_types import to_single_geom_type
|
|
28
33
|
|
|
29
34
|
|
|
30
35
|
def split_geom_types(gdf: GeoDataFrame | GeoSeries) -> tuple[GeoDataFrame | GeoSeries]:
|
|
@@ -79,13 +84,13 @@ def get_common_crs(
|
|
|
79
84
|
actually_different.add(x)
|
|
80
85
|
|
|
81
86
|
if len(actually_different) == 1:
|
|
82
|
-
return
|
|
87
|
+
return next(iter(actually_different))
|
|
83
88
|
raise ValueError("'crs' mismatch.", truthy_crs)
|
|
84
89
|
|
|
85
90
|
return pyproj.CRS(truthy_crs[0])
|
|
86
91
|
|
|
87
92
|
|
|
88
|
-
def is_bbox_like(obj) -> bool:
|
|
93
|
+
def is_bbox_like(obj: Any) -> bool:
|
|
89
94
|
if (
|
|
90
95
|
hasattr(obj, "__iter__")
|
|
91
96
|
and len(obj) == 4
|
|
@@ -114,6 +119,7 @@ def _push_geom_col(gdf: GeoDataFrame) -> GeoDataFrame:
|
|
|
114
119
|
|
|
115
120
|
|
|
116
121
|
def drop_inactive_geometry_columns(gdf: GeoDataFrame) -> GeoDataFrame:
|
|
122
|
+
"""Removes geometry columns in a GeoDataFrame if they are not active."""
|
|
117
123
|
for col in gdf.columns:
|
|
118
124
|
if (
|
|
119
125
|
isinstance(gdf[col].dtype, GeometryDtype)
|
|
@@ -123,7 +129,7 @@ def drop_inactive_geometry_columns(gdf: GeoDataFrame) -> GeoDataFrame:
|
|
|
123
129
|
return gdf
|
|
124
130
|
|
|
125
131
|
|
|
126
|
-
def
|
|
132
|
+
def _rename_geometry_if(gdf: GeoDataFrame) -> GeoDataFrame:
|
|
127
133
|
geom_col = gdf._geometry_column_name
|
|
128
134
|
if geom_col == "geometry" and geom_col in gdf.columns:
|
|
129
135
|
return gdf
|
|
@@ -157,7 +163,7 @@ def clean_geoms(
|
|
|
157
163
|
GeoDataFrame or GeoSeries with fixed geometries and only the rows with valid,
|
|
158
164
|
non-empty and not-NaN/-None geometries.
|
|
159
165
|
|
|
160
|
-
Examples
|
|
166
|
+
Examples:
|
|
161
167
|
--------
|
|
162
168
|
>>> import sgis as sg
|
|
163
169
|
>>> import pandas as pd
|
|
@@ -231,8 +237,20 @@ def clean_geoms(
|
|
|
231
237
|
|
|
232
238
|
|
|
233
239
|
def get_grouped_centroids(
|
|
234
|
-
gdf: GeoDataFrame, groupby: str, as_string: bool = True
|
|
240
|
+
gdf: GeoDataFrame, groupby: str | list[str], as_string: bool = True
|
|
235
241
|
) -> pd.Series:
|
|
242
|
+
"""Get the centerpoint of the geometries within a group.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
gdf: GeoDataFrame.
|
|
246
|
+
groupby: column to group by.
|
|
247
|
+
as_string: If True (default), coordinates are returned in
|
|
248
|
+
the format "{x}_{y}". If False, coordinates are returned
|
|
249
|
+
as Points.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
A pandas.Series of grouped centroids with the index of 'gdf'.
|
|
253
|
+
"""
|
|
236
254
|
centerpoints = gdf.assign(geometry=lambda x: x.centroid)
|
|
237
255
|
|
|
238
256
|
grouped_centerpoints = centerpoints.dissolve(by=groupby).assign(
|
|
@@ -242,9 +260,13 @@ def get_grouped_centroids(
|
|
|
242
260
|
ys = grouped_centerpoints.geometry.y
|
|
243
261
|
|
|
244
262
|
if as_string:
|
|
245
|
-
grouped_centerpoints["wkt"] = [
|
|
263
|
+
grouped_centerpoints["wkt"] = [
|
|
264
|
+
f"{int(x)}_{int(y)}" for x, y in zip(xs, ys, strict=False)
|
|
265
|
+
]
|
|
246
266
|
else:
|
|
247
|
-
grouped_centerpoints["wkt"] = [
|
|
267
|
+
grouped_centerpoints["wkt"] = [
|
|
268
|
+
Point(x, y) for x, y in zip(xs, ys, strict=False)
|
|
269
|
+
]
|
|
248
270
|
|
|
249
271
|
return gdf[groupby].map(grouped_centerpoints["wkt"])
|
|
250
272
|
|
|
@@ -258,12 +280,20 @@ def sort_large_first(gdf: GeoDataFrame | GeoSeries) -> GeoDataFrame | GeoSeries:
|
|
|
258
280
|
Returns:
|
|
259
281
|
A GeoDataFrame or GeoSeries sorted from large to small in area.
|
|
260
282
|
|
|
261
|
-
Examples
|
|
283
|
+
Examples:
|
|
262
284
|
--------
|
|
263
285
|
Create GeoDataFrame with NaN values.
|
|
264
286
|
|
|
265
287
|
>>> import sgis as sg
|
|
266
|
-
>>> df = sg.
|
|
288
|
+
>>> df = sg.to_gdf(
|
|
289
|
+
... [
|
|
290
|
+
... (0, 1),
|
|
291
|
+
... (1, 0),
|
|
292
|
+
... (1, 1),
|
|
293
|
+
... (0, 0),
|
|
294
|
+
... (0.5, 0.5),
|
|
295
|
+
... ]
|
|
296
|
+
... )
|
|
267
297
|
>>> df.geometry = df.buffer([4, 1, 2, 3, 5])
|
|
268
298
|
>>> df["col"] = [None, 1, 2, None, 1]
|
|
269
299
|
>>> df["col2"] = [None, 1, 2, 3, None]
|
|
@@ -299,16 +329,6 @@ def sort_large_first(gdf: GeoDataFrame | GeoSeries) -> GeoDataFrame | GeoSeries:
|
|
|
299
329
|
return gdf.iloc[list(sorted_areas)]
|
|
300
330
|
|
|
301
331
|
|
|
302
|
-
def sort_df(
|
|
303
|
-
df: pd.DataFrame | GeoDataFrame, sort_col: pd.Series
|
|
304
|
-
) -> pd.DataFrame | GeoDataFrame:
|
|
305
|
-
value_mapper: dict[int, Any] = dict(enumerate(sort_col.values))
|
|
306
|
-
sorted_indices = dict(
|
|
307
|
-
reversed(sorted(value_mapper.items(), key=lambda item: item[1]))
|
|
308
|
-
)
|
|
309
|
-
return df.iloc[list(sorted_indices)]
|
|
310
|
-
|
|
311
|
-
|
|
312
332
|
def sort_long_first(gdf: GeoDataFrame | GeoSeries) -> GeoDataFrame | GeoSeries:
|
|
313
333
|
"""Sort GeoDataFrame by length in decending order.
|
|
314
334
|
|
|
@@ -402,7 +422,7 @@ def random_points(n: int, loc: float | int = 0.5) -> GeoDataFrame:
|
|
|
402
422
|
Returns:
|
|
403
423
|
A GeoDataFrame of points with n rows.
|
|
404
424
|
|
|
405
|
-
Examples
|
|
425
|
+
Examples:
|
|
406
426
|
--------
|
|
407
427
|
>>> import sgis as sg
|
|
408
428
|
>>> points = sg.random_points(10_000)
|
|
@@ -451,6 +471,16 @@ def random_points(n: int, loc: float | int = 0.5) -> GeoDataFrame:
|
|
|
451
471
|
|
|
452
472
|
|
|
453
473
|
def random_points_in_polygons(gdf: GeoDataFrame, n: int, seed=None) -> GeoDataFrame:
|
|
474
|
+
"""Creates a GeoDataFrame with n random points within the geometries of 'gdf'.
|
|
475
|
+
|
|
476
|
+
Args:
|
|
477
|
+
gdf: A GeoDataFrame.
|
|
478
|
+
n: Number of points/rows to create.
|
|
479
|
+
seed: Optional random seet.
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
A GeoDataFrame of points with n rows.
|
|
483
|
+
"""
|
|
454
484
|
all_points = []
|
|
455
485
|
|
|
456
486
|
rng = np.random.default_rng(seed)
|
|
@@ -492,7 +522,7 @@ def to_lines(*gdfs: GeoDataFrame, copy: bool = True) -> GeoDataFrame:
|
|
|
492
522
|
ignored. This is because the union overlay used if multiple GeoDataFrames
|
|
493
523
|
always ignores the index.
|
|
494
524
|
|
|
495
|
-
Examples
|
|
525
|
+
Examples:
|
|
496
526
|
--------
|
|
497
527
|
Convert single polygon to linestring.
|
|
498
528
|
|
|
@@ -525,7 +555,6 @@ def to_lines(*gdfs: GeoDataFrame, copy: bool = True) -> GeoDataFrame:
|
|
|
525
555
|
>>> lines["l"] = lines.length
|
|
526
556
|
>>> sg.qtm(lines, "l")
|
|
527
557
|
"""
|
|
528
|
-
|
|
529
558
|
if not all(isinstance(gdf, (GeoSeries, GeoDataFrame)) for gdf in gdfs):
|
|
530
559
|
raise TypeError("gdf must be GeoDataFrame or GeoSeries")
|
|
531
560
|
|
|
@@ -534,7 +563,6 @@ def to_lines(*gdfs: GeoDataFrame, copy: bool = True) -> GeoDataFrame:
|
|
|
534
563
|
|
|
535
564
|
def _shapely_geometry_to_lines(geom):
|
|
536
565
|
"""Get all lines from the exterior and interiors of a Polygon."""
|
|
537
|
-
|
|
538
566
|
# if lines (points are not allowed in this function)
|
|
539
567
|
if geom.area == 0:
|
|
540
568
|
return geom
|
|
@@ -664,11 +692,11 @@ def _determine_geom_type_args(
|
|
|
664
692
|
return gdf, geom_type, keep_geom_type
|
|
665
693
|
|
|
666
694
|
|
|
667
|
-
def
|
|
695
|
+
def _merge_geometries(geoms: GeoSeries, grid_size=None) -> Geometry:
|
|
668
696
|
return make_valid(unary_union(geoms, grid_size=grid_size))
|
|
669
697
|
|
|
670
698
|
|
|
671
|
-
def
|
|
699
|
+
def _parallel_unary_union(
|
|
672
700
|
gdf: GeoDataFrame, n_jobs: int = 1, by=None, grid_size=None, **kwargs
|
|
673
701
|
) -> list[Geometry]:
|
|
674
702
|
try:
|
|
@@ -702,7 +730,7 @@ def parallel_unary_union(
|
|
|
702
730
|
return dissolved.geometry
|
|
703
731
|
|
|
704
732
|
|
|
705
|
-
def
|
|
733
|
+
def _parallel_unary_union_geoseries(
|
|
706
734
|
ser: GeoSeries, n_jobs: int = 1, grid_size=None, **kwargs
|
|
707
735
|
) -> list[Geometry]:
|
|
708
736
|
if ser.crs is None:
|
|
@@ -725,7 +753,7 @@ def parallel_unary_union_geoseries(
|
|
|
725
753
|
return dissolved.geometry
|
|
726
754
|
|
|
727
755
|
|
|
728
|
-
def
|
|
756
|
+
def _parallel_unary_union(
|
|
729
757
|
gdf: GeoDataFrame, n_jobs: int = 1, by=None, grid_size=None, **kwargs
|
|
730
758
|
) -> list[Geometry]:
|
|
731
759
|
try:
|
|
@@ -737,13 +765,13 @@ def parallel_unary_union(
|
|
|
737
765
|
delayed_operations = []
|
|
738
766
|
for _, geoms in gdf.groupby(by, **kwargs)[geom_col]:
|
|
739
767
|
delayed_operations.append(
|
|
740
|
-
joblib.delayed(
|
|
768
|
+
joblib.delayed(_merge_geometries)(geoms, grid_size=grid_size)
|
|
741
769
|
)
|
|
742
770
|
|
|
743
771
|
return parallel(delayed_operations)
|
|
744
772
|
|
|
745
773
|
|
|
746
|
-
def
|
|
774
|
+
def _parallel_unary_union_geoseries(
|
|
747
775
|
ser: GeoSeries, n_jobs: int = 1, grid_size=None, **kwargs
|
|
748
776
|
) -> list[Geometry]:
|
|
749
777
|
|
|
@@ -756,18 +784,18 @@ def parallel_unary_union_geoseries(
|
|
|
756
784
|
delayed_operations = []
|
|
757
785
|
for _, geoms in many_hits.groupby(**kwargs):
|
|
758
786
|
delayed_operations.append(
|
|
759
|
-
joblib.delayed(
|
|
787
|
+
joblib.delayed(_merge_geometries)(geoms, grid_size=grid_size)
|
|
760
788
|
)
|
|
761
789
|
|
|
762
790
|
dissolved = pd.Series(
|
|
763
791
|
parallel(delayed_operations),
|
|
764
|
-
index=is_one_hit[lambda x: x
|
|
792
|
+
index=is_one_hit[lambda x: x is False].index.unique(),
|
|
765
793
|
)
|
|
766
794
|
|
|
767
795
|
return pd.concat([dissolved, one_hit]).sort_index().values
|
|
768
796
|
|
|
769
797
|
|
|
770
|
-
def
|
|
798
|
+
def _parallel_unary_union_geoseries(
|
|
771
799
|
ser: GeoSeries, n_jobs: int = 1, grid_size=None, **kwargs
|
|
772
800
|
) -> list[Geometry]:
|
|
773
801
|
|
|
@@ -775,7 +803,7 @@ def parallel_unary_union_geoseries(
|
|
|
775
803
|
delayed_operations = []
|
|
776
804
|
for _, geoms in ser.groupby(**kwargs):
|
|
777
805
|
delayed_operations.append(
|
|
778
|
-
joblib.delayed(
|
|
806
|
+
joblib.delayed(_merge_geometries)(geoms, grid_size=grid_size)
|
|
779
807
|
)
|
|
780
808
|
|
|
781
809
|
return parallel(delayed_operations)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Check and set geometry type."""
|
|
2
|
+
|
|
2
3
|
import numpy as np
|
|
3
4
|
import pandas as pd
|
|
4
5
|
import shapely
|
|
5
|
-
from geopandas import GeoDataFrame
|
|
6
|
+
from geopandas import GeoDataFrame
|
|
7
|
+
from geopandas import GeoSeries
|
|
6
8
|
from geopandas.array import GeometryArray
|
|
7
9
|
from shapely import Geometry
|
|
8
10
|
|
|
@@ -10,6 +12,18 @@ from shapely import Geometry
|
|
|
10
12
|
def make_all_singlepart(
|
|
11
13
|
gdf: GeoDataFrame | GeoSeries, index_parts: bool = False, ignore_index: bool = False
|
|
12
14
|
) -> GeoDataFrame | GeoSeries:
|
|
15
|
+
"""Make all geometries single part.
|
|
16
|
+
|
|
17
|
+
This means doing either 0, 1 or 2 calls to the explode method.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
gdf: GeoDataFrame
|
|
21
|
+
index_parts: Defaults to False.
|
|
22
|
+
ignore_index: Defaults to False.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
A GeoDataFrame of singlepart geometries.
|
|
26
|
+
"""
|
|
13
27
|
# only explode if nessecary
|
|
14
28
|
if (
|
|
15
29
|
index_parts or ignore_index
|
|
@@ -25,7 +39,7 @@ def make_all_singlepart(
|
|
|
25
39
|
|
|
26
40
|
|
|
27
41
|
def to_single_geom_type(
|
|
28
|
-
gdf: GeoDataFrame | GeoSeries,
|
|
42
|
+
gdf: GeoDataFrame | GeoSeries | Geometry | GeometryArray | np.ndarray,
|
|
29
43
|
geom_type: str,
|
|
30
44
|
ignore_index: bool = False,
|
|
31
45
|
) -> GeoDataFrame | GeoSeries:
|
|
@@ -49,7 +63,7 @@ def to_single_geom_type(
|
|
|
49
63
|
TypeError: If incorrect gdf type.
|
|
50
64
|
ValueError: If 'geom_type' is neither 'polygon', 'line' or 'point'.
|
|
51
65
|
|
|
52
|
-
Examples
|
|
66
|
+
Examples:
|
|
53
67
|
--------
|
|
54
68
|
First create a GeoDataFrame of mixed geometries.
|
|
55
69
|
|
|
@@ -96,7 +110,7 @@ def to_single_geom_type(
|
|
|
96
110
|
arr = np.vectorize(_shapely_to_single_geom_type)(gdf, geom_type)
|
|
97
111
|
return arr[~shapely.is_empty(arr)]
|
|
98
112
|
|
|
99
|
-
if not isinstance(gdf, (GeoDataFrame, GeoSeries)):
|
|
113
|
+
if not isinstance(gdf, (GeoDataFrame, GeoSeries)): # type: ignore [unreachable]
|
|
100
114
|
raise TypeError(f"'gdf' should be GeoDataFrame or GeoSeries, got {type(gdf)}")
|
|
101
115
|
|
|
102
116
|
# explode collections to single-typed geometries
|
|
@@ -122,7 +136,7 @@ def to_single_geom_type(
|
|
|
122
136
|
return gdf.reset_index(drop=True) if ignore_index else gdf
|
|
123
137
|
|
|
124
138
|
|
|
125
|
-
def _shapely_to_single_geom_type(geom, geom_type):
|
|
139
|
+
def _shapely_to_single_geom_type(geom: Geometry, geom_type: str) -> Geometry:
|
|
126
140
|
parts = shapely.get_parts(geom)
|
|
127
141
|
return shapely.unary_union(
|
|
128
142
|
[part for part in parts if geom_type.lower() in part.geom_type.lower()]
|
|
@@ -141,7 +155,7 @@ def get_geom_type(gdf: GeoDataFrame | GeoSeries) -> str:
|
|
|
141
155
|
Raises:
|
|
142
156
|
TypeError: If 'gdf' is not of type GeoDataFrame or GeoSeries.
|
|
143
157
|
|
|
144
|
-
Examples
|
|
158
|
+
Examples:
|
|
145
159
|
--------
|
|
146
160
|
>>> from sgis import to_gdf, get_geom_type
|
|
147
161
|
>>> gdf = to_gdf([0, 0])
|
|
@@ -189,7 +203,7 @@ def is_single_geom_type(gdf: GeoDataFrame | GeoSeries) -> bool:
|
|
|
189
203
|
Raises:
|
|
190
204
|
TypeError: If 'gdf' is not of type GeoDataFrame or GeoSeries.
|
|
191
205
|
|
|
192
|
-
Examples
|
|
206
|
+
Examples:
|
|
193
207
|
--------
|
|
194
208
|
>>> from sgis import to_gdf, get_geom_type
|
|
195
209
|
>>> gdf = to_gdf([0, 0])
|
|
@@ -10,9 +10,10 @@ types.
|
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
import shapely
|
|
13
|
-
from geopandas import GeoDataFrame
|
|
14
|
-
from
|
|
15
|
-
from
|
|
13
|
+
from geopandas import GeoDataFrame
|
|
14
|
+
from geopandas import GeoSeries
|
|
15
|
+
from pandas import DataFrame
|
|
16
|
+
from pandas import Series
|
|
16
17
|
from sklearn.neighbors import NearestNeighbors
|
|
17
18
|
|
|
18
19
|
from .conversion import coordinate_array
|
|
@@ -48,7 +49,7 @@ def get_neighbor_indices(
|
|
|
48
49
|
ValueError: If gdf and neighbors do not have the same coordinate reference
|
|
49
50
|
system.
|
|
50
51
|
|
|
51
|
-
Examples
|
|
52
|
+
Examples:
|
|
52
53
|
--------
|
|
53
54
|
>>> from sgis import get_neighbor_indices, to_gdf
|
|
54
55
|
>>> points = to_gdf([(0, 0), (0.5, 0.5)])
|
|
@@ -96,7 +97,6 @@ def get_neighbor_indices(
|
|
|
96
97
|
['a' 'a' 'b' 'b']
|
|
97
98
|
|
|
98
99
|
"""
|
|
99
|
-
|
|
100
100
|
if gdf.crs != neighbors.crs:
|
|
101
101
|
raise ValueError(f"'crs' mismatch. Got {gdf.crs} and {neighbors.crs}")
|
|
102
102
|
|
|
@@ -152,7 +152,7 @@ def get_all_distances(
|
|
|
152
152
|
ValueError: If the coordinate reference system of 'gdf' and 'neighbors' are
|
|
153
153
|
not the same.
|
|
154
154
|
|
|
155
|
-
Examples
|
|
155
|
+
Examples:
|
|
156
156
|
--------
|
|
157
157
|
>>> from sgis import get_all_distances, random_points
|
|
158
158
|
>>> points = random_points(100)
|
|
@@ -248,7 +248,6 @@ def sjoin_within_distance(
|
|
|
248
248
|
**kwargs,
|
|
249
249
|
) -> GeoDataFrame:
|
|
250
250
|
"""Sjoin with a buffer on the right GeoDataFrame and adds a distance column."""
|
|
251
|
-
|
|
252
251
|
new_neighbor_cols = {"__left_range_idx": range(len(neighbors))}
|
|
253
252
|
if distance:
|
|
254
253
|
new_neighbor_cols[neighbors._geometry_column_name] = lambda x: x.buffer(
|
|
@@ -297,7 +296,7 @@ def get_k_nearest_neighbors(
|
|
|
297
296
|
ValueError: If the coordinate reference system of 'gdf' and 'neighbors' are
|
|
298
297
|
not the same.
|
|
299
298
|
|
|
300
|
-
Examples
|
|
299
|
+
Examples:
|
|
301
300
|
--------
|
|
302
301
|
Make some random points.
|
|
303
302
|
|
|
@@ -430,6 +429,19 @@ def k_nearest_neighbors(
|
|
|
430
429
|
k: int | None = None,
|
|
431
430
|
strict: bool = False,
|
|
432
431
|
) -> tuple[np.ndarray[float], np.ndarray[int]]:
|
|
432
|
+
"""Finds nearest neighbors for an array of coordinates to another array of coordinates.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
from_array: Numpy array of coordinates.
|
|
436
|
+
to_array: Numpy array of coordinates.
|
|
437
|
+
k: Number of neighbors to find.
|
|
438
|
+
strict: If True (not default), an exception is raised
|
|
439
|
+
if k is larger than the length of 'to_array'.
|
|
440
|
+
|
|
441
|
+
Returns a tuple of arrays, one with distances and one with indices
|
|
442
|
+
of the neighbors.
|
|
443
|
+
|
|
444
|
+
"""
|
|
433
445
|
if not len(to_array) or not len(from_array):
|
|
434
446
|
return np.array([]), np.array([])
|
|
435
447
|
|