ssb-sgis 1.0.12__tar.gz → 1.0.14__tar.gz

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.
Files changed (62) hide show
  1. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/PKG-INFO +1 -1
  2. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/pyproject.toml +1 -1
  3. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/__init__.py +1 -0
  4. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/explore.py +51 -15
  5. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/maps.py +21 -0
  6. ssb_sgis-1.0.14/src/sgis/maps/norge_i_bilder.json +11517 -0
  7. ssb_sgis-1.0.14/src/sgis/maps/norge_i_bilder_wms.py +165 -0
  8. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/raster/image_collection.py +37 -47
  9. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/LICENSE +0 -0
  10. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/README.md +0 -0
  11. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/debug_config.py +0 -0
  12. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/exceptions.py +0 -0
  13. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/__init__.py +0 -0
  14. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/bounds.py +0 -0
  15. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/buffer_dissolve_explode.py +0 -0
  16. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/centerlines.py +0 -0
  17. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/cleaning.py +0 -0
  18. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/conversion.py +0 -0
  19. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/duplicates.py +0 -0
  20. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/general.py +0 -0
  21. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/geocoding.py +0 -0
  22. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/geometry_types.py +0 -0
  23. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/neighbors.py +0 -0
  24. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/overlay.py +0 -0
  25. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/point_operations.py +0 -0
  26. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/polygon_operations.py +0 -0
  27. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/polygons_as_rings.py +0 -0
  28. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/geopandas_tools/sfilter.py +0 -0
  29. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/helpers.py +0 -0
  30. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/io/_is_dapla.py +0 -0
  31. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/io/dapla_functions.py +0 -0
  32. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/io/opener.py +0 -0
  33. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/io/read_parquet.py +0 -0
  34. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/__init__.py +0 -0
  35. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/examine.py +0 -0
  36. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/httpserver.py +0 -0
  37. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/legend.py +0 -0
  38. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/map.py +0 -0
  39. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/thematicmap.py +0 -0
  40. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/maps/tilesources.py +0 -0
  41. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/__init__.py +0 -0
  42. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/_get_route.py +0 -0
  43. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/_od_cost_matrix.py +0 -0
  44. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/_points.py +0 -0
  45. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/_service_area.py +0 -0
  46. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/closing_network_holes.py +0 -0
  47. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/cutting_lines.py +0 -0
  48. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/directednetwork.py +0 -0
  49. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/finding_isolated_networks.py +0 -0
  50. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/network.py +0 -0
  51. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/networkanalysis.py +0 -0
  52. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/networkanalysisrules.py +0 -0
  53. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/nodes.py +0 -0
  54. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/networkanalysis/traveling_salesman.py +0 -0
  55. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/parallel/parallel.py +0 -0
  56. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/py.typed +0 -0
  57. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/raster/__init__.py +0 -0
  58. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/raster/base.py +0 -0
  59. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/raster/indices.py +0 -0
  60. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/raster/regex.py +0 -0
  61. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/raster/sentinel_config.py +0 -0
  62. {ssb_sgis-1.0.12 → ssb_sgis-1.0.14}/src/sgis/raster/zonal.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ssb-sgis
3
- Version: 1.0.12
3
+ Version: 1.0.14
4
4
  Summary: GIS functions used at Statistics Norway.
5
5
  Home-page: https://github.com/statisticsnorway/ssb-sgis
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "ssb-sgis"
3
- version = "1.0.12"
3
+ version = "1.0.14"
4
4
  description = "GIS functions used at Statistics Norway."
5
5
  authors = ["Morten Letnes <morten.letnes@ssb.no>"]
6
6
  license = "MIT"
@@ -96,6 +96,7 @@ from .maps.maps import explore
96
96
  from .maps.maps import explore_locals
97
97
  from .maps.maps import qtm
98
98
  from .maps.maps import samplemap
99
+ from .maps.norge_i_bilder_wms import NorgeIBilderWms
99
100
  from .maps.thematicmap import ThematicMap
100
101
  from .maps.tilesources import kartverket as kartverket_tiles
101
102
  from .maps.tilesources import xyz as xyztiles
@@ -44,6 +44,7 @@ from ..geopandas_tools.general import clean_geoms
44
44
  from ..geopandas_tools.general import make_all_singlepart
45
45
  from ..geopandas_tools.geometry_types import get_geom_type
46
46
  from ..geopandas_tools.geometry_types import to_single_geom_type
47
+ from .norge_i_bilder_wms import NorgeIBilderWms
47
48
 
48
49
  try:
49
50
  from ..raster.image_collection import Band
@@ -157,7 +158,9 @@ def to_tile(tile: str | xyzservices.TileProvider, max_zoom: int) -> folium.TileL
157
158
  except TypeError:
158
159
  name = tile
159
160
 
160
- if not isinstance(tile, str):
161
+ if isinstance(tile, folium.map.Layer) and not isinstance(tile, folium.GeoJson):
162
+ return tile
163
+ elif not isinstance(tile, str):
161
164
  try:
162
165
  return folium.TileLayer(tile, name=name, max_zoom=max_zoom)
163
166
  except TypeError:
@@ -183,7 +186,9 @@ def to_tile(tile: str | xyzservices.TileProvider, max_zoom: int) -> folium.TileL
183
186
  return folium.TileLayer(provider, name=name, attr=attr, max_zoom=max_zoom)
184
187
 
185
188
 
186
- def _single_band_to_arr(band, mask, name, raster_data_dict):
189
+ def _single_band_to_arr_is_too_much_nodata(
190
+ band, mask, name, raster_data_dict, max_nodata_percentage
191
+ ) -> bool:
187
192
  if band.has_array and mask is None:
188
193
  arr = band.values
189
194
  elif band.has_array:
@@ -191,8 +196,8 @@ def _single_band_to_arr(band, mask, name, raster_data_dict):
191
196
  else:
192
197
  arr = band.load(indexes=1, bounds=mask).values
193
198
 
194
- if _is_too_much_nodata([arr], band.nodata):
195
- return False
199
+ if _is_too_much_nodata([arr], band.nodata, max_nodata_percentage):
200
+ return True
196
201
 
197
202
  bounds: tuple = (
198
203
  _any_to_bbox_crs4326(mask, band.crs)
@@ -216,25 +221,28 @@ def _single_band_to_arr(band, mask, name, raster_data_dict):
216
221
  except Exception:
217
222
  raster_data_dict["date"] = None
218
223
 
219
- return True
224
+ return False
220
225
 
221
226
 
222
227
  def _is_too_much_nodata(
223
228
  arrays: list[np.ndarray],
224
- nodata: int | None = None,
225
- max_nodata_percentage: int = 100,
229
+ nodata: int | None,
230
+ max_nodata_percentage: int,
226
231
  ) -> bool:
227
232
  return (
228
233
  any(arr.shape[0] == 0 for arr in arrays)
229
234
  or any(
230
235
  (
231
236
  isinstance(arr, np.ma.core.MaskedArray)
232
- and np.mean((arr.mask) | (arr.data == nodata) | (np.isnan(arr.data)))
237
+ and np.mean(((arr.mask) | (arr.data == nodata) | (np.isnan(arr.data))))
233
238
  > (max_nodata_percentage / 100)
234
239
  )
235
240
  for arr in arrays
236
241
  )
237
- or any(np.mean(arr == nodata) > (max_nodata_percentage / 100) for arr in arrays)
242
+ or any(
243
+ np.mean((arr == nodata) | (np.isnan(arr))) > (max_nodata_percentage / 100)
244
+ for arr in arrays
245
+ )
238
246
  )
239
247
 
240
248
 
@@ -271,6 +279,8 @@ class Explore(Map):
271
279
  decimals: int = 6,
272
280
  max_images: int = 10,
273
281
  max_nodata_percentage: int = 100,
282
+ display: bool = True,
283
+ norge_i_bilder: bool = False,
274
284
  **kwargs,
275
285
  ) -> None:
276
286
  """Initialiser.
@@ -299,6 +309,10 @@ class Explore(Map):
299
309
  decimals: Number of decimals in the coordinates.
300
310
  max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in
301
311
  image arrays.
312
+ display: Whether to display the map interactively.
313
+ norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded
314
+ into the map. Can optionally be set to an instance of NorgeIBilderWms to filter
315
+ years and names.
302
316
  **kwargs: Additional keyword arguments. Can also be geometry-like objects
303
317
  where the key is the label.
304
318
  """
@@ -314,6 +328,8 @@ class Explore(Map):
314
328
  self.decimals = decimals
315
329
  self.max_images = max_images
316
330
  self.max_nodata_percentage = max_nodata_percentage
331
+ self.display = display
332
+ self.norge_i_bilder = norge_i_bilder
317
333
  self.legend = None
318
334
 
319
335
  self.browser = browser
@@ -457,8 +473,7 @@ class Explore(Map):
457
473
 
458
474
  if center is None:
459
475
  self.to_show = self._gdfs
460
- self._explore(**kwargs)
461
- return
476
+ return self._explore(**kwargs)
462
477
 
463
478
  size = size if size else 1000
464
479
 
@@ -622,6 +637,8 @@ class Explore(Map):
622
637
  f.write(self.map._repr_html_())
623
638
  elif self.browser:
624
639
  run_html_server(self.map._repr_html_())
640
+ elif not self.display:
641
+ return
625
642
  else:
626
643
  display(self.map)
627
644
 
@@ -751,6 +768,14 @@ class Explore(Map):
751
768
  for tile in tiles:
752
769
  to_tile(tile, max_zoom=self.max_zoom).add_to(mapobj)
753
770
 
771
+ def _add_norge_i_bilder(self, map_: folium.Map, bbox: Any) -> None:
772
+ if not isinstance(self.norge_i_bilder, NorgeIBilderWms):
773
+ self.norge_i_bilder = NorgeIBilderWms()
774
+
775
+ tiles = self.norge_i_bilder.get_tiles(bbox, max_zoom=self.max_zoom)
776
+ for tile in tiles.values():
777
+ map_.add_child(tile)
778
+
754
779
  def _create_continous_map(self):
755
780
  self._prepare_continous_map()
756
781
  if self.scheme:
@@ -957,6 +982,9 @@ class Explore(Map):
957
982
  m.get_root().add_child(style)
958
983
  # folium.LayerControl(collapsed=False).add_to(m)
959
984
 
985
+ if self.norge_i_bilder:
986
+ self._add_norge_i_bilder(m, bounds)
987
+
960
988
  return m
961
989
 
962
990
  def _make_geojson(
@@ -1103,6 +1131,7 @@ class Explore(Map):
1103
1131
  highlight_function=highlight_function,
1104
1132
  smooth_factor=self.smooth_factor,
1105
1133
  show=show,
1134
+ # on_each_feature="function(feature,layer){layer.bindTooltip(feature.properties.NAME,{permanent:true,direction:'center'});return layer;}",
1106
1135
  **kwargs,
1107
1136
  )
1108
1137
 
@@ -1132,6 +1161,8 @@ def _tooltip_popup(
1132
1161
  return folium.GeoJsonTooltip(fields, **kwargs)
1133
1162
  elif type_ == "popup":
1134
1163
  return folium.GeoJsonPopup(fields, **kwargs)
1164
+ else:
1165
+ raise ValueError(type_)
1135
1166
 
1136
1167
 
1137
1168
  def _intersects_if_not_none_or_empty(obj: Any, other: Any) -> bool:
@@ -1345,7 +1376,10 @@ def _add_one_image(
1345
1376
  if len(image) < 3:
1346
1377
  for band in image:
1347
1378
  name = _determine_label(band, band.name or name)
1348
- _single_band_to_arr(band, mask, name, raster_data_dict)
1379
+ if _single_band_to_arr_is_too_much_nodata(
1380
+ band, mask, name, raster_data_dict, max_nodata_percentage
1381
+ ):
1382
+ return
1349
1383
  return raster_data_dict
1350
1384
 
1351
1385
  def load(band_id: str) -> Band:
@@ -1428,8 +1462,10 @@ def _image_collection_to_background_map(
1428
1462
  return out
1429
1463
 
1430
1464
  raster_data_dict = {}
1431
- out.append(raster_data_dict)
1432
- _single_band_to_arr(band, mask, name, raster_data_dict)
1465
+ if not _single_band_to_arr_is_too_much_nodata(
1466
+ band, mask, name, raster_data_dict, max_nodata_percentage
1467
+ ):
1468
+ out.append(raster_data_dict)
1433
1469
  return out
1434
1470
 
1435
1471
  else:
@@ -1462,7 +1498,7 @@ def _image_collection_to_background_map(
1462
1498
  continue
1463
1499
  i = 1
1464
1500
  while x["label"] in {y["label"] for y in out}:
1465
- x["label"] = x["label"].rstrip(f"_{i}", "") + f"_{i + 1}"
1501
+ x["label"] = x["label"].rstrip(f"_{i}") + f"_{i + 1}"
1466
1502
  i += 1
1467
1503
 
1468
1504
  n_added_images += 1
@@ -31,6 +31,7 @@ from ..geopandas_tools.geocoding import address_to_gdf
31
31
  from ..geopandas_tools.geometry_types import get_geom_type
32
32
  from .explore import Explore
33
33
  from .map import Map
34
+ from .norge_i_bilder_wms import NorgeIBilderWms
34
35
  from .thematicmap import ThematicMap
35
36
 
36
37
  try:
@@ -57,6 +58,9 @@ def _get_location_mask(kwargs: dict, gdfs) -> tuple[GeoDataFrame | None, dict]:
57
58
  "akersveien": (10.7476367, 59.9222191),
58
59
  "kongsvinger": (12.0035242, 60.1875279),
59
60
  "stavanger": (5.6960601, 58.8946196),
61
+ "trondheim": (10.39677054, 63.42687816),
62
+ "trondhjem": (10.39677054, 63.42687816),
63
+ "bergen": (5.32574594, 60.39550309),
60
64
  "volda": (6.0705987, 62.146643),
61
65
  }
62
66
 
@@ -87,6 +91,7 @@ def explore(
87
91
  size: int | None = None,
88
92
  max_images: int = 10,
89
93
  max_nodata_percentage: int = 100,
94
+ norge_i_bilder: bool | NorgeIBilderWms = False,
90
95
  **kwargs,
91
96
  ) -> Explore:
92
97
  """Interactive map of GeoDataFrames with layers that can be toggled on/off.
@@ -118,6 +123,9 @@ def explore(
118
123
  map. Defaults to 10.
119
124
  max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in
120
125
  image arrays.
126
+ norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded
127
+ into the map. Can optionally be set to an instance of NorgeIBilderWms to filter
128
+ years and names.
121
129
  **kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for
122
130
  instance 'cmap' to change the colors, 'scheme' to change how the data
123
131
  is grouped. This defaults to 'fisherjenkssampled' for numeric data.
@@ -167,6 +175,7 @@ def explore(
167
175
  max_zoom=max_zoom,
168
176
  max_images=max_images,
169
177
  max_nodata_percentage=max_nodata_percentage,
178
+ norge_i_bilder=norge_i_bilder,
170
179
  **kwargs,
171
180
  )
172
181
 
@@ -224,6 +233,7 @@ def explore(
224
233
  max_zoom=max_zoom,
225
234
  max_images=max_images,
226
235
  max_nodata_percentage=max_nodata_percentage,
236
+ norge_i_bilder=norge_i_bilder,
227
237
  **kwargs,
228
238
  )
229
239
 
@@ -235,6 +245,7 @@ def explore(
235
245
  smooth_factor=smooth_factor,
236
246
  max_images=max_images,
237
247
  max_nodata_percentage=max_nodata_percentage,
248
+ norge_i_bilder=norge_i_bilder,
238
249
  **kwargs,
239
250
  )
240
251
 
@@ -260,6 +271,7 @@ def samplemap(
260
271
  browser: bool = False,
261
272
  max_images: int = 10,
262
273
  max_nodata_percentage: int = 100,
274
+ norge_i_bilder: bool | NorgeIBilderWms = False,
263
275
  **kwargs,
264
276
  ) -> Explore:
265
277
  """Shows an interactive map of a random area of GeoDataFrames.
@@ -295,6 +307,9 @@ def samplemap(
295
307
  map. Defaults to 10.
296
308
  max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in
297
309
  image arrays.
310
+ norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded
311
+ into the map. Can optionally be set to an instance of NorgeIBilderWms to filter
312
+ years and names.
298
313
  **kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for
299
314
  instance 'cmap' to change the colors, 'scheme' to change how the data
300
315
  is grouped. This defaults to 'fisherjenkssampled' for numeric data.
@@ -378,6 +393,7 @@ def samplemap(
378
393
  smooth_factor=smooth_factor,
379
394
  max_images=max_images,
380
395
  max_nodata_percentage=max_nodata_percentage,
396
+ norge_i_bilder=norge_i_bilder,
381
397
  **kwargs,
382
398
  )
383
399
 
@@ -392,6 +408,7 @@ def clipmap(
392
408
  browser: bool = False,
393
409
  max_images: int = 10,
394
410
  max_nodata_percentage: int = 100,
411
+ norge_i_bilder: bool | NorgeIBilderWms = False,
395
412
  **kwargs,
396
413
  ) -> Explore | Map:
397
414
  """Shows an interactive map of a of GeoDataFrames clipped to the mask extent.
@@ -422,6 +439,9 @@ def clipmap(
422
439
  map. Defaults to 10.
423
440
  max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in
424
441
  image arrays.
442
+ norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded
443
+ into the map. Can optionally be set to an instance of NorgeIBilderWms to filter
444
+ years and names.
425
445
  **kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for
426
446
  instance 'cmap' to change the colors, 'scheme' to change how the data
427
447
  is grouped. This defaults to 'fisherjenkssampled' for numeric data.
@@ -457,6 +477,7 @@ def clipmap(
457
477
  smooth_factor=smooth_factor,
458
478
  max_images=max_images,
459
479
  max_nodata_percentage=max_nodata_percentage,
480
+ norge_i_bilder=norge_i_bilder,
460
481
  **kwargs,
461
482
  )
462
483
  m.mask = mask