ssb-sgis 1.0.11__py3-none-any.whl → 1.0.13__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/maps/explore.py CHANGED
@@ -183,7 +183,9 @@ def to_tile(tile: str | xyzservices.TileProvider, max_zoom: int) -> folium.TileL
183
183
  return folium.TileLayer(provider, name=name, attr=attr, max_zoom=max_zoom)
184
184
 
185
185
 
186
- def _single_band_to_arr(band, mask, name, raster_data_dict):
186
+ def _single_band_to_arr_is_too_much_nodata(
187
+ band, mask, name, raster_data_dict, max_nodata_percentage
188
+ ) -> bool:
187
189
  if band.has_array and mask is None:
188
190
  arr = band.values
189
191
  elif band.has_array:
@@ -191,8 +193,8 @@ def _single_band_to_arr(band, mask, name, raster_data_dict):
191
193
  else:
192
194
  arr = band.load(indexes=1, bounds=mask).values
193
195
 
194
- if _is_too_much_nodata([arr], band.nodata):
195
- return False
196
+ if _is_too_much_nodata([arr], band.nodata, max_nodata_percentage):
197
+ return True
196
198
 
197
199
  bounds: tuple = (
198
200
  _any_to_bbox_crs4326(mask, band.crs)
@@ -211,26 +213,33 @@ def _single_band_to_arr(band, mask, name, raster_data_dict):
211
213
  raster_data_dict["arr"] = arr
212
214
  raster_data_dict["bounds"] = bounds
213
215
  raster_data_dict["label"] = band.name or name
214
- raster_data_dict["date"] = band.date
215
- return True
216
+ try:
217
+ raster_data_dict["date"] = band.date
218
+ except Exception:
219
+ raster_data_dict["date"] = None
220
+
221
+ return False
216
222
 
217
223
 
218
224
  def _is_too_much_nodata(
219
225
  arrays: list[np.ndarray],
220
- nodata: int | None = None,
221
- max_nodata_percentage: int = 100,
226
+ nodata: int | None,
227
+ max_nodata_percentage: int,
222
228
  ) -> bool:
223
229
  return (
224
230
  any(arr.shape[0] == 0 for arr in arrays)
225
231
  or any(
226
232
  (
227
233
  isinstance(arr, np.ma.core.MaskedArray)
228
- and np.mean((arr.mask) | (arr.data == nodata) | (np.isnan(arr.data)))
234
+ and np.mean(((arr.mask) | (arr.data == nodata) | (np.isnan(arr.data))))
229
235
  > (max_nodata_percentage / 100)
230
236
  )
231
237
  for arr in arrays
232
238
  )
233
- or any(np.mean(arr == nodata) > (max_nodata_percentage / 100) for arr in arrays)
239
+ or any(
240
+ np.mean((arr == nodata) | (np.isnan(arr))) > (max_nodata_percentage / 100)
241
+ for arr in arrays
242
+ )
234
243
  )
235
244
 
236
245
 
@@ -267,6 +276,7 @@ class Explore(Map):
267
276
  decimals: int = 6,
268
277
  max_images: int = 10,
269
278
  max_nodata_percentage: int = 100,
279
+ display: bool = True,
270
280
  **kwargs,
271
281
  ) -> None:
272
282
  """Initialiser.
@@ -295,6 +305,7 @@ class Explore(Map):
295
305
  decimals: Number of decimals in the coordinates.
296
306
  max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in
297
307
  image arrays.
308
+ display: Whether to display the map interactively.
298
309
  **kwargs: Additional keyword arguments. Can also be geometry-like objects
299
310
  where the key is the label.
300
311
  """
@@ -310,6 +321,7 @@ class Explore(Map):
310
321
  self.decimals = decimals
311
322
  self.max_images = max_images
312
323
  self.max_nodata_percentage = max_nodata_percentage
324
+ self.display = display
313
325
  self.legend = None
314
326
 
315
327
  self.browser = browser
@@ -453,8 +465,7 @@ class Explore(Map):
453
465
 
454
466
  if center is None:
455
467
  self.to_show = self._gdfs
456
- self._explore(**kwargs)
457
- return
468
+ return self._explore(**kwargs)
458
469
 
459
470
  size = size if size else 1000
460
471
 
@@ -618,6 +629,8 @@ class Explore(Map):
618
629
  f.write(self.map._repr_html_())
619
630
  elif self.browser:
620
631
  run_html_server(self.map._repr_html_())
632
+ elif not self.display:
633
+ return
621
634
  else:
622
635
  display(self.map)
623
636
 
@@ -1341,7 +1354,10 @@ def _add_one_image(
1341
1354
  if len(image) < 3:
1342
1355
  for band in image:
1343
1356
  name = _determine_label(band, band.name or name)
1344
- _single_band_to_arr(band, mask, name, raster_data_dict)
1357
+ if _single_band_to_arr_is_too_much_nodata(
1358
+ band, mask, name, raster_data_dict, max_nodata_percentage
1359
+ ):
1360
+ return
1345
1361
  return raster_data_dict
1346
1362
 
1347
1363
  def load(band_id: str) -> Band:
@@ -1386,7 +1402,10 @@ def _add_one_image(
1386
1402
  raster_data_dict["bounds"] = bounds
1387
1403
  raster_data_dict["cmap"] = None
1388
1404
  raster_data_dict["label"] = _determine_label(image, image.name or name)
1389
- raster_data_dict["date"] = image.date
1405
+ try:
1406
+ raster_data_dict["date"] = image.date
1407
+ except Exception:
1408
+ raster_data_dict["date"] = None
1390
1409
 
1391
1410
  return raster_data_dict
1392
1411
 
@@ -1421,8 +1440,10 @@ def _image_collection_to_background_map(
1421
1440
  return out
1422
1441
 
1423
1442
  raster_data_dict = {}
1424
- out.append(raster_data_dict)
1425
- _single_band_to_arr(band, mask, name, raster_data_dict)
1443
+ if not _single_band_to_arr_is_too_much_nodata(
1444
+ band, mask, name, raster_data_dict, max_nodata_percentage
1445
+ ):
1446
+ out.append(raster_data_dict)
1426
1447
  return out
1427
1448
 
1428
1449
  else:
@@ -1455,7 +1476,7 @@ def _image_collection_to_background_map(
1455
1476
  continue
1456
1477
  i = 1
1457
1478
  while x["label"] in {y["label"] for y in out}:
1458
- x["label"] = x["label"].rstrip(f"_{i}", "") + f"_{i + 1}"
1479
+ x["label"] = x["label"].rstrip(f"_{i}") + f"_{i + 1}"
1459
1480
  i += 1
1460
1481
 
1461
1482
  n_added_images += 1
@@ -499,6 +499,14 @@ class _ImageBase:
499
499
  "metadata": self.metadata,
500
500
  }
501
501
 
502
+ @property
503
+ def _common_init_kwargs_after_load(self) -> dict:
504
+ return {
505
+ k: v
506
+ for k, v in self._common_init_kwargs.items()
507
+ if k not in {"res", "metadata"}
508
+ }
509
+
502
510
  @property
503
511
  def path(self) -> str:
504
512
  try:
@@ -1136,8 +1144,8 @@ class Band(_ImageBandBase):
1136
1144
  if self.nodata is None or np.isnan(self.nodata):
1137
1145
  self.nodata = src.nodata
1138
1146
  else:
1139
- dtype_min_value = _get_dtype_min(src.dtypes[0])
1140
- dtype_max_value = _get_dtype_max(src.dtypes[0])
1147
+ dtype_min_value = _get_dtype_min_value(src.dtypes[0])
1148
+ dtype_max_value = _get_dtype_max_value(src.dtypes[0])
1141
1149
  if self.nodata > dtype_max_value or self.nodata < dtype_min_value:
1142
1150
  src._dtypes = tuple(
1143
1151
  rasterio.dtypes.get_minimum_dtype(self.nodata)
@@ -1240,17 +1248,17 @@ class Band(_ImageBandBase):
1240
1248
  if self.crs is None:
1241
1249
  raise ValueError("Cannot write None crs to image.")
1242
1250
 
1243
- if self.nodata:
1244
- # TODO take out .data if masked?
1245
- values_with_nodata = np.concatenate(
1246
- [self.values.flatten(), np.array([self.nodata])]
1247
- )
1248
- else:
1249
- values_with_nodata = self.values
1251
+ try:
1252
+ data = self.values.data
1253
+ except AttributeError:
1254
+ data = self.values
1255
+ data = np.array([np.min(data), np.max(data), self.nodata or 0])
1256
+ min_dtype = rasterio.dtypes.get_minimum_dtype(data)
1257
+
1250
1258
  profile = {
1251
1259
  "driver": driver,
1252
1260
  "compress": compress,
1253
- "dtype": rasterio.dtypes.get_minimum_dtype(values_with_nodata),
1261
+ "dtype": min_dtype,
1254
1262
  "crs": self.crs,
1255
1263
  "transform": self.transform,
1256
1264
  "nodata": self.nodata,
@@ -1263,7 +1271,7 @@ class Band(_ImageBandBase):
1263
1271
  with rasterio.open(f, "w", **profile) as dst:
1264
1272
 
1265
1273
  if dst.nodata is None:
1266
- dst.nodata = _get_dtype_min(dst.dtypes[0])
1274
+ dst.nodata = _get_dtype_min_value(dst.dtypes[0])
1267
1275
 
1268
1276
  if (
1269
1277
  isinstance(self.values, np.ma.core.MaskedArray)
@@ -1515,12 +1523,6 @@ class NDVIBand(Band):
1515
1523
  cmap: str = "Greens"
1516
1524
 
1517
1525
 
1518
- def median_as_int_and_minimum_dtype(arr: np.ndarray) -> np.ndarray:
1519
- arr = np.median(arr, axis=0).astype(int)
1520
- min_dtype = rasterio.dtypes.get_minimum_dtype(arr)
1521
- return arr.astype(min_dtype)
1522
-
1523
-
1524
1526
  class Image(_ImageBandBase):
1525
1527
  """Image consisting of one or more Bands."""
1526
1528
 
@@ -1742,7 +1744,7 @@ class Image(_ImageBandBase):
1742
1744
  arr,
1743
1745
  bounds=red.bounds,
1744
1746
  crs=red.crs,
1745
- **{k: v for k, v in red._common_init_kwargs.items() if k != "res"},
1747
+ **red._common_init_kwargs_after_load,
1746
1748
  )
1747
1749
 
1748
1750
  def get_brightness(
@@ -1773,7 +1775,7 @@ class Image(_ImageBandBase):
1773
1775
  brightness,
1774
1776
  bounds=red.bounds,
1775
1777
  crs=self.crs,
1776
- **{k: v for k, v in self._common_init_kwargs.items() if k != "res"},
1778
+ **self._common_init_kwargs_after_load,
1777
1779
  )
1778
1780
 
1779
1781
  def to_xarray(self) -> DataArray:
@@ -2102,7 +2104,7 @@ class ImageCollection(_ImageBase):
2102
2104
 
2103
2105
  for attr in by:
2104
2106
  if attr == "bounds":
2105
- # need integers to check equality when grouping
2107
+ # need integers to properly check equality when grouping
2106
2108
  df[attr] = [
2107
2109
  tuple(int(x) for x in band.bounds) for img in self for band in img
2108
2110
  ]
@@ -2322,9 +2324,8 @@ class ImageCollection(_ImageBase):
2322
2324
  arr,
2323
2325
  bounds=bounds,
2324
2326
  crs=crs,
2325
- **{k: v for k, v in self._common_init_kwargs.items() if k != "res"},
2327
+ **self._common_init_kwargs_after_load,
2326
2328
  )
2327
-
2328
2329
  band._merged = True
2329
2330
  return band
2330
2331
 
@@ -2390,19 +2391,20 @@ class ImageCollection(_ImageBase):
2390
2391
 
2391
2392
  arrs.append(arr)
2392
2393
  bands.append(
2393
- self.band_class(
2394
+ # self.band_class(
2395
+ Band(
2394
2396
  arr,
2395
2397
  bounds=out_bounds,
2396
2398
  crs=crs,
2397
2399
  band_id=band_id,
2398
- **{k: v for k, v in self._common_init_kwargs.items() if k != "res"},
2400
+ **self._common_init_kwargs_after_load,
2399
2401
  )
2400
2402
  )
2401
2403
 
2402
2404
  # return self.image_class( # TODO
2403
2405
  image = Image(
2404
2406
  bands,
2405
- band_class=self.band_class,
2407
+ # band_class=self.band_class,
2406
2408
  **self._common_init_kwargs,
2407
2409
  )
2408
2410
 
@@ -2431,25 +2433,17 @@ class ImageCollection(_ImageBase):
2431
2433
  continue
2432
2434
 
2433
2435
  _bounds = to_bbox(_bounds)
2434
- arr = np.array(
2435
- [
2436
- (
2437
- # band.load(
2438
- # bounds=(_bounds if _bounds is not None else None),
2439
- # **kwargs,
2440
- # )
2441
- # if not band.has_array
2442
- # else
2443
- band
2444
- ).values
2445
- for img in collection
2446
- for band in img
2447
- ]
2448
- )
2436
+ collection.load(bounds=(_bounds if _bounds is not None else None), **kwargs)
2437
+ arr = np.array([band.values for img in collection for band in img])
2449
2438
  arr = numpy_func(arr, axis=0)
2450
2439
  if as_int:
2451
2440
  arr = arr.astype(int)
2452
- min_dtype = rasterio.dtypes.get_minimum_dtype(arr)
2441
+ try:
2442
+ data = arr.data
2443
+ except AttributeError:
2444
+ data = arr
2445
+ data = np.array([np.min(data), np.max(data), self.nodata or 0])
2446
+ min_dtype = rasterio.dtypes.get_minimum_dtype(data)
2453
2447
  arr = arr.astype(min_dtype)
2454
2448
 
2455
2449
  if len(arr.shape) == 2:
@@ -3429,24 +3423,20 @@ def _date_is_within(
3429
3423
  return False
3430
3424
 
3431
3425
 
3432
- def _get_dtype_min(dtype: str | type) -> int | float:
3426
+ def _get_dtype_min_value(dtype: str | type) -> int | float:
3433
3427
  try:
3434
3428
  return np.iinfo(dtype).min
3435
3429
  except ValueError:
3436
3430
  return np.finfo(dtype).min
3437
3431
 
3438
3432
 
3439
- def _get_dtype_max(dtype: str | type) -> int | float:
3433
+ def _get_dtype_max_value(dtype: str | type) -> int | float:
3440
3434
  try:
3441
3435
  return np.iinfo(dtype).max
3442
3436
  except ValueError:
3443
3437
  return np.finfo(dtype).max
3444
3438
 
3445
3439
 
3446
- def _intesects(x, other) -> bool:
3447
- return box(*x.bounds).intersects(other)
3448
-
3449
-
3450
3440
  def _copy_and_add_df_parallel(
3451
3441
  group_values: tuple[Any, ...],
3452
3442
  group_df: pd.DataFrame,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ssb-sgis
3
- Version: 1.0.11
3
+ Version: 1.0.13
4
4
  Summary: GIS functions used at Statistics Norway.
5
5
  Home-page: https://github.com/statisticsnorway/ssb-sgis
6
6
  License: MIT
@@ -24,7 +24,7 @@ sgis/io/opener.py,sha256=HWO3G1NB6bpXKM94JadCD513vjat1o1TFjWGWzyVasg,898
24
24
  sgis/io/read_parquet.py,sha256=FvZYv1rLkUlrSaUY6QW6E1yntmntTeQuZ9ZRgCDO4IM,3776
25
25
  sgis/maps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  sgis/maps/examine.py,sha256=Pb0dH8JazU5E2svfQrzHO1Bi-sjy5SeyY6zoeMO34jE,9369
27
- sgis/maps/explore.py,sha256=h6_E-NRohMkVw1ThUm-50Nl3O-UYtWQZ1glmS9cdlTY,45631
27
+ sgis/maps/explore.py,sha256=dHwQmD_8U9dLaBJHs2VKJvqK-yNUhH6yZoInF0iFrAE,46237
28
28
  sgis/maps/httpserver.py,sha256=7Od9JMCtntcIQKk_TchetojMHzFHT9sPw7GANahI97c,1982
29
29
  sgis/maps/legend.py,sha256=lVRVCkhPmJRjGK23obFJZAO3qp6du1LYnobkkN7DPkc,26279
30
30
  sgis/maps/map.py,sha256=smaf9i53EoRZWmZjn9UuqlhzUvVs1XKo2ItIpHxyuik,29592
@@ -49,12 +49,12 @@ sgis/parallel/parallel.py,sha256=SlC_mOwvSSyWTKUcxLMGkuWHUkEC6dXTlN0Jn5cAtxA,396
49
49
  sgis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
50
  sgis/raster/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  sgis/raster/base.py,sha256=tiZEuMcVK6hOm_aIjWhQ1WGshcjsxT1fFkuBSLFiMC0,7785
52
- sgis/raster/image_collection.py,sha256=C_w_18vOP1Z7-EHzGYJSYDwnWA7tg5OlRzGlLJam0pc,122878
52
+ sgis/raster/image_collection.py,sha256=STPh8m2WRAkuQfuJC1VNA2XLZ6FHT8I7qjcAntVWi2o,122573
53
53
  sgis/raster/indices.py,sha256=-J1HYmnT240iozvgagvyis6K0_GHZHRuUrPOgyoeIrY,223
54
54
  sgis/raster/regex.py,sha256=kYhVpRYzoXutx1dSYmqMoselWXww7MMEsTPmLZwHjbM,3759
55
55
  sgis/raster/sentinel_config.py,sha256=nySDqn2R8M6W8jguoBeSAK_zzbAsqmaI59i32446FwY,1268
56
56
  sgis/raster/zonal.py,sha256=D4Gyptw-yOLTCO41peIuYbY-DANsJCG19xXDlf1QAz4,2299
57
- ssb_sgis-1.0.11.dist-info/LICENSE,sha256=np3IfD5m0ZUofn_kVzDZqliozuiO6wrktw3LRPjyEiI,1073
58
- ssb_sgis-1.0.11.dist-info/METADATA,sha256=ndFvrKxnD572cBE2VqGpjeONaHQTEl6xy3l_JGw5IsA,11741
59
- ssb_sgis-1.0.11.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
60
- ssb_sgis-1.0.11.dist-info/RECORD,,
57
+ ssb_sgis-1.0.13.dist-info/LICENSE,sha256=np3IfD5m0ZUofn_kVzDZqliozuiO6wrktw3LRPjyEiI,1073
58
+ ssb_sgis-1.0.13.dist-info/METADATA,sha256=H0AhyHQ3_Va2WmbAkd5IgycphRpYVw0GyctqeIAqQt0,11741
59
+ ssb_sgis-1.0.13.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
60
+ ssb_sgis-1.0.13.dist-info/RECORD,,