ssb-sgis 1.0.2__py3-none-any.whl → 1.0.3__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 +10 -6
- sgis/exceptions.py +2 -2
- sgis/geopandas_tools/bounds.py +17 -15
- sgis/geopandas_tools/buffer_dissolve_explode.py +24 -5
- sgis/geopandas_tools/conversion.py +15 -6
- sgis/geopandas_tools/duplicates.py +2 -2
- sgis/geopandas_tools/general.py +9 -5
- sgis/geopandas_tools/geometry_types.py +3 -3
- sgis/geopandas_tools/neighbors.py +3 -3
- sgis/geopandas_tools/point_operations.py +2 -2
- sgis/geopandas_tools/polygon_operations.py +5 -5
- sgis/geopandas_tools/sfilter.py +3 -3
- sgis/helpers.py +3 -3
- sgis/io/read_parquet.py +1 -1
- sgis/maps/examine.py +16 -2
- sgis/maps/explore.py +370 -57
- sgis/maps/legend.py +164 -72
- sgis/maps/map.py +184 -90
- sgis/maps/maps.py +92 -90
- sgis/maps/thematicmap.py +236 -83
- sgis/networkanalysis/closing_network_holes.py +2 -2
- sgis/networkanalysis/cutting_lines.py +3 -3
- sgis/networkanalysis/directednetwork.py +1 -1
- sgis/networkanalysis/finding_isolated_networks.py +2 -2
- sgis/networkanalysis/networkanalysis.py +7 -7
- sgis/networkanalysis/networkanalysisrules.py +1 -1
- sgis/networkanalysis/traveling_salesman.py +1 -1
- sgis/parallel/parallel.py +39 -19
- sgis/raster/__init__.py +0 -6
- sgis/raster/cube.py +51 -5
- sgis/raster/image_collection.py +2560 -0
- sgis/raster/indices.py +14 -5
- sgis/raster/raster.py +131 -236
- sgis/raster/sentinel_config.py +104 -0
- sgis/raster/zonal.py +0 -1
- {ssb_sgis-1.0.2.dist-info → ssb_sgis-1.0.3.dist-info}/METADATA +1 -1
- ssb_sgis-1.0.3.dist-info/RECORD +61 -0
- sgis/raster/methods_as_functions.py +0 -0
- sgis/raster/torchgeo.py +0 -171
- ssb_sgis-1.0.2.dist-info/RECORD +0 -61
- {ssb_sgis-1.0.2.dist-info → ssb_sgis-1.0.3.dist-info}/LICENSE +0 -0
- {ssb_sgis-1.0.2.dist-info → ssb_sgis-1.0.3.dist-info}/WHEEL +0 -0
sgis/parallel/parallel.py
CHANGED
|
@@ -2,6 +2,7 @@ import functools
|
|
|
2
2
|
import inspect
|
|
3
3
|
import itertools
|
|
4
4
|
import multiprocessing
|
|
5
|
+
import pickle
|
|
5
6
|
import warnings
|
|
6
7
|
from collections.abc import Callable
|
|
7
8
|
from collections.abc import Collection
|
|
@@ -132,7 +133,7 @@ class Parallel:
|
|
|
132
133
|
'iterable'.
|
|
133
134
|
|
|
134
135
|
Examples:
|
|
135
|
-
|
|
136
|
+
---------
|
|
136
137
|
Multiply each list element by 2.
|
|
137
138
|
|
|
138
139
|
>>> iterable = [1, 2, 3]
|
|
@@ -183,7 +184,7 @@ class Parallel:
|
|
|
183
184
|
func_with_kwargs = functools.partial(func, **kwargs)
|
|
184
185
|
|
|
185
186
|
if self.processes == 1:
|
|
186
|
-
return
|
|
187
|
+
return [func_with_kwargs(item) for item in iterable]
|
|
187
188
|
|
|
188
189
|
iterable = list(iterable)
|
|
189
190
|
|
|
@@ -192,23 +193,42 @@ class Parallel:
|
|
|
192
193
|
|
|
193
194
|
if not processes:
|
|
194
195
|
return []
|
|
196
|
+
elif processes == 1:
|
|
197
|
+
return [func_with_kwargs(item) for item in iterable]
|
|
195
198
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
199
|
+
try:
|
|
200
|
+
if self.backend == "multiprocessing":
|
|
201
|
+
with multiprocessing.get_context(self.context).Pool(
|
|
202
|
+
processes, maxtasksperchild=self.maxtasksperchild, **self.kwargs
|
|
203
|
+
) as pool:
|
|
204
|
+
try:
|
|
205
|
+
return pool.map(
|
|
206
|
+
func_with_kwargs, iterable, chunksize=self.chunksize
|
|
207
|
+
)
|
|
208
|
+
except Exception as e:
|
|
209
|
+
pool.terminate()
|
|
210
|
+
raise e
|
|
207
211
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
+
with joblib.Parallel(
|
|
213
|
+
n_jobs=processes, backend=self.backend, **self.kwargs
|
|
214
|
+
) as parallel:
|
|
215
|
+
return parallel(
|
|
216
|
+
joblib.delayed(func)(item, **kwargs) for item in iterable
|
|
217
|
+
)
|
|
218
|
+
except pickle.PickleError as e:
|
|
219
|
+
unpicklable = []
|
|
220
|
+
for k, v in locals().items():
|
|
221
|
+
try:
|
|
222
|
+
pickle.dumps(v)
|
|
223
|
+
except pickle.PickleError:
|
|
224
|
+
unpicklable.append(k)
|
|
225
|
+
except TypeError:
|
|
226
|
+
pass
|
|
227
|
+
if unpicklable:
|
|
228
|
+
raise pickle.PickleError(
|
|
229
|
+
f"Cannot unpickle objects: {unpicklable}"
|
|
230
|
+
) from e
|
|
231
|
+
raise e
|
|
212
232
|
|
|
213
233
|
def starmap(
|
|
214
234
|
self,
|
|
@@ -236,7 +256,7 @@ class Parallel:
|
|
|
236
256
|
'iterable'.
|
|
237
257
|
|
|
238
258
|
Examples:
|
|
239
|
-
|
|
259
|
+
---------
|
|
240
260
|
Multiply each list element by 2.
|
|
241
261
|
|
|
242
262
|
>>> iterable = [(1, 2), (2, 3), (3, 4)]
|
|
@@ -947,7 +967,7 @@ def parallel_overlay(
|
|
|
947
967
|
|
|
948
968
|
|
|
949
969
|
def _clean_intersection(
|
|
950
|
-
df1: GeoDataFrame, df2: GeoDataFrame, to_print: str
|
|
970
|
+
df1: GeoDataFrame, df2: GeoDataFrame, to_print: str = ""
|
|
951
971
|
) -> GeoDataFrame:
|
|
952
972
|
print(to_print, "- intersection chunk len:", len(df1))
|
|
953
973
|
return clean_overlay(df1, df2, how="intersection")
|
sgis/raster/__init__.py
CHANGED
sgis/raster/cube.py
CHANGED
|
@@ -2,6 +2,7 @@ import functools
|
|
|
2
2
|
import itertools
|
|
3
3
|
import multiprocessing
|
|
4
4
|
import re
|
|
5
|
+
import warnings
|
|
5
6
|
from collections.abc import Callable
|
|
6
7
|
from collections.abc import Iterable
|
|
7
8
|
from collections.abc import Iterator
|
|
@@ -140,6 +141,10 @@ class DataCube:
|
|
|
140
141
|
copy: If True, makes deep copies of Rasters provided.
|
|
141
142
|
parallelizer: sgis.Parallel instance to handle concurrent operations.
|
|
142
143
|
"""
|
|
144
|
+
warnings.warn(
|
|
145
|
+
"This class is deprecated in favor of ImageCollection", stacklevel=1
|
|
146
|
+
)
|
|
147
|
+
|
|
143
148
|
self._arrays = None
|
|
144
149
|
self._res = res
|
|
145
150
|
self.parallelizer = parallelizer
|
|
@@ -207,6 +212,7 @@ class DataCube:
|
|
|
207
212
|
check_for_df: bool = True,
|
|
208
213
|
contains: str | None = None,
|
|
209
214
|
endswith: str = ".tif",
|
|
215
|
+
bands: str | list[str] | None = None,
|
|
210
216
|
filename_regex: str | None = None,
|
|
211
217
|
parallelizer: Parallel | None = None,
|
|
212
218
|
file_system=None,
|
|
@@ -221,6 +227,7 @@ class DataCube:
|
|
|
221
227
|
that holds metadata for the files in the directory.
|
|
222
228
|
contains: Filter files containing specific substrings.
|
|
223
229
|
endswith: Filter files that end with specific substrings.
|
|
230
|
+
bands: One or more band ids to keep.
|
|
224
231
|
filename_regex: Regular expression to match file names
|
|
225
232
|
and attributes (date, band, tile, resolution).
|
|
226
233
|
parallelizer: sgis.Parallel instance for concurrent file processing.
|
|
@@ -233,6 +240,7 @@ class DataCube:
|
|
|
233
240
|
kwargs["res"] = res
|
|
234
241
|
kwargs["filename_regex"] = filename_regex
|
|
235
242
|
kwargs["contains"] = contains
|
|
243
|
+
kwargs["bands"] = bands
|
|
236
244
|
kwargs["endswith"] = endswith
|
|
237
245
|
|
|
238
246
|
if is_dapla():
|
|
@@ -283,6 +291,7 @@ class DataCube:
|
|
|
283
291
|
parallelizer: Parallel | None = None,
|
|
284
292
|
file_system=None,
|
|
285
293
|
contains: str | None = None,
|
|
294
|
+
bands: str | list[str] | None = None,
|
|
286
295
|
endswith: str = ".tif",
|
|
287
296
|
filename_regex: str | None = None,
|
|
288
297
|
**kwargs,
|
|
@@ -296,6 +305,7 @@ class DataCube:
|
|
|
296
305
|
file_system: File system to use for file operations, used in Dapla environment.
|
|
297
306
|
contains: Filter files containing specific substrings.
|
|
298
307
|
endswith: Filter files that end with specific substrings.
|
|
308
|
+
bands: One or more band ids to keep.
|
|
299
309
|
filename_regex: Regular expression to match file names.
|
|
300
310
|
**kwargs: Additional keyword arguments to pass to the raster loading function.
|
|
301
311
|
|
|
@@ -311,6 +321,10 @@ class DataCube:
|
|
|
311
321
|
if filename_regex:
|
|
312
322
|
compiled = re.compile(filename_regex, re.VERBOSE)
|
|
313
323
|
paths = [path for path in paths if re.search(compiled, Path(path).name)]
|
|
324
|
+
if bands:
|
|
325
|
+
if isinstance(bands, str):
|
|
326
|
+
bands = [bands]
|
|
327
|
+
paths = [path for path in paths if any(band in str(path) for band in bands)]
|
|
314
328
|
|
|
315
329
|
if not paths:
|
|
316
330
|
return cls(crs=crs, parallelizer=parallelizer, res=res)
|
|
@@ -544,6 +558,19 @@ class DataCube:
|
|
|
544
558
|
self.data = data
|
|
545
559
|
return self
|
|
546
560
|
|
|
561
|
+
def sample(self, n: int, copy: bool = True, **kwargs) -> Self:
|
|
562
|
+
"""Take n samples of the cube."""
|
|
563
|
+
if self.crs is None:
|
|
564
|
+
self._crs = get_common_crs(self.data)
|
|
565
|
+
|
|
566
|
+
cube = self.copy() if copy else self
|
|
567
|
+
|
|
568
|
+
cube.data = list(pd.Series(cube.data).sample(n))
|
|
569
|
+
|
|
570
|
+
cube.data = cube.run_raster_method("load", **kwargs)
|
|
571
|
+
|
|
572
|
+
return cube
|
|
573
|
+
|
|
547
574
|
def load(self, copy: bool = True, **kwargs) -> Self:
|
|
548
575
|
"""Load all images as arrays into a DataCube copy."""
|
|
549
576
|
if self.crs is None:
|
|
@@ -620,7 +647,7 @@ class DataCube:
|
|
|
620
647
|
).items()
|
|
621
648
|
if key in ALLOWED_KEYS and key not in ["array", "indexes"]
|
|
622
649
|
}
|
|
623
|
-
if raster.
|
|
650
|
+
if raster.values is None:
|
|
624
651
|
return [
|
|
625
652
|
raster.__class__.from_dict({"indexes": i} | all_meta)
|
|
626
653
|
for i in raster.indexes_as_tuple()
|
|
@@ -830,7 +857,7 @@ class DataCube:
|
|
|
830
857
|
@property
|
|
831
858
|
def arrays(self) -> list[np.ndarray]:
|
|
832
859
|
"""The arrays of the images as a list."""
|
|
833
|
-
return [raster.
|
|
860
|
+
return [raster.values for raster in self]
|
|
834
861
|
|
|
835
862
|
@arrays.setter
|
|
836
863
|
def arrays(self, new_arrays: list[np.ndarray]):
|
|
@@ -995,12 +1022,22 @@ class DataCube:
|
|
|
995
1022
|
|
|
996
1023
|
def _check_for_array(self, text: str = "") -> None:
|
|
997
1024
|
mess = "Arrays are not loaded. " + text
|
|
998
|
-
if all(raster.
|
|
1025
|
+
if all(raster.values is None for raster in self):
|
|
999
1026
|
raise ValueError(mess)
|
|
1000
1027
|
|
|
1001
1028
|
def __getitem__(
|
|
1002
1029
|
self,
|
|
1003
|
-
item:
|
|
1030
|
+
item: (
|
|
1031
|
+
str
|
|
1032
|
+
| slice
|
|
1033
|
+
| int
|
|
1034
|
+
| Series
|
|
1035
|
+
| list
|
|
1036
|
+
| tuple
|
|
1037
|
+
| Callable
|
|
1038
|
+
| Geometry
|
|
1039
|
+
| BoundingBox
|
|
1040
|
+
),
|
|
1004
1041
|
) -> Self | Raster | TORCHGEO_RETURN_TYPE:
|
|
1005
1042
|
"""Select one or more of the Rasters based on indexing or spatial or boolean predicates.
|
|
1006
1043
|
|
|
@@ -1026,6 +1063,14 @@ class DataCube:
|
|
|
1026
1063
|
|
|
1027
1064
|
"""
|
|
1028
1065
|
copy = self.copy()
|
|
1066
|
+
if isinstance(item, str) and copy.path is not None:
|
|
1067
|
+
copy.data = [raster for raster in copy if item in raster.path]
|
|
1068
|
+
if len(copy) == 1:
|
|
1069
|
+
return copy[0]
|
|
1070
|
+
elif not len(copy):
|
|
1071
|
+
return Raster()
|
|
1072
|
+
return copy
|
|
1073
|
+
|
|
1029
1074
|
if isinstance(item, slice):
|
|
1030
1075
|
copy.data = copy.data[item]
|
|
1031
1076
|
return copy
|
|
@@ -1127,7 +1172,7 @@ def _merge(
|
|
|
1127
1172
|
bounds: Any | None = None,
|
|
1128
1173
|
**kwargs,
|
|
1129
1174
|
) -> DataCube:
|
|
1130
|
-
if not all(r.
|
|
1175
|
+
if not all(r.values is None for r in cube):
|
|
1131
1176
|
raise ValueError("Arrays can't be loaded when calling merge.")
|
|
1132
1177
|
|
|
1133
1178
|
bounds = to_bbox(bounds) if bounds is not None else bounds
|
|
@@ -1185,6 +1230,7 @@ def _merge_by_bounds(
|
|
|
1185
1230
|
|
|
1186
1231
|
|
|
1187
1232
|
def _merge(cube: DataCube, **kwargs) -> DataCube:
|
|
1233
|
+
by = kwargs.pop("by")
|
|
1188
1234
|
if cube.crs is None:
|
|
1189
1235
|
cube._crs = get_common_crs(cube.data)
|
|
1190
1236
|
|