ssb-sgis 1.2.10__tar.gz → 1.2.11__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 (67) hide show
  1. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/PKG-INFO +1 -1
  2. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/pyproject.toml +2 -2
  3. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/bounds.py +4 -2
  4. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/neighbors.py +5 -0
  5. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/io/dapla_functions.py +9 -2
  6. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/explore.py +23 -13
  7. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/map.py +1 -1
  8. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/wms.py +5 -26
  9. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/LICENSE +0 -0
  10. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/README.md +0 -0
  11. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/__init__.py +0 -0
  12. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/conf.py +0 -0
  13. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/debug_config.py +0 -0
  14. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/exceptions.py +0 -0
  15. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/__init__.py +0 -0
  16. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/buffer_dissolve_explode.py +0 -0
  17. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/centerlines.py +0 -0
  18. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/cleaning.py +0 -0
  19. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/conversion.py +0 -0
  20. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/duplicates.py +0 -0
  21. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/general.py +0 -0
  22. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/geocoding.py +0 -0
  23. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/geometry_types.py +0 -0
  24. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/overlay.py +0 -0
  25. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/point_operations.py +0 -0
  26. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/polygon_operations.py +0 -0
  27. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/polygons_as_rings.py +0 -0
  28. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/runners.py +0 -0
  29. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/sfilter.py +0 -0
  30. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/geopandas_tools/utils.py +0 -0
  31. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/helpers.py +0 -0
  32. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/io/__init__.py +0 -0
  33. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/io/_is_dapla.py +0 -0
  34. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/io/opener.py +0 -0
  35. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/io/read_parquet.py +0 -0
  36. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/__init__.py +0 -0
  37. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/examine.py +0 -0
  38. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/httpserver.py +0 -0
  39. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/legend.py +0 -0
  40. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/maps.py +0 -0
  41. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/norge_i_bilder.json +0 -0
  42. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/thematicmap.py +0 -0
  43. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/maps/tilesources.py +0 -0
  44. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/__init__.py +0 -0
  45. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/_get_route.py +0 -0
  46. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/_od_cost_matrix.py +0 -0
  47. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/_points.py +0 -0
  48. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/_service_area.py +0 -0
  49. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/closing_network_holes.py +0 -0
  50. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/cutting_lines.py +0 -0
  51. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/directednetwork.py +0 -0
  52. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/finding_isolated_networks.py +0 -0
  53. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/network.py +0 -0
  54. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/networkanalysis.py +0 -0
  55. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/networkanalysisrules.py +0 -0
  56. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/nodes.py +0 -0
  57. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/networkanalysis/traveling_salesman.py +0 -0
  58. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/parallel/__init__.py +0 -0
  59. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/parallel/parallel.py +0 -0
  60. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/py.typed +0 -0
  61. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/raster/__init__.py +0 -0
  62. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/raster/base.py +0 -0
  63. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/raster/image_collection.py +0 -0
  64. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/raster/indices.py +0 -0
  65. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/raster/regex.py +0 -0
  66. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/src/sgis/raster/sentinel_config.py +0 -0
  67. {ssb_sgis-1.2.10 → ssb_sgis-1.2.11}/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.2.10
3
+ Version: 1.2.11
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.2.10"
3
+ version = "1.2.11"
4
4
  description = "GIS functions used at Statistics Norway."
5
5
  authors = ["Morten Letnes <morten.letnes@ssb.no>"]
6
6
  license = "MIT"
@@ -137,7 +137,7 @@ ignore_missing_imports = true
137
137
  force-exclude = true # Apply excludes to pre-commit
138
138
  show-fixes = true
139
139
  src = ["src", "tests"]
140
- target-version = "py310" # Minimum Python version supported
140
+ target-version = "py311" # Minimum Python version supported
141
141
  include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"]
142
142
  extend-exclude = [
143
143
  "__pycache__",
@@ -634,11 +634,13 @@ def bounds_to_polygon(
634
634
  1 POLYGON ((0.00000 0.00000, 0.00000 0.00000, 0....
635
635
 
636
636
  """
637
+ bounds = gdf.bounds.values
638
+ boxes = box(bounds[:, 0], bounds[:, 1], bounds[:, 2], bounds[:, 3])
637
639
  if isinstance(gdf, GeoSeries):
638
- return GeoSeries([box(*arr) for arr in gdf.bounds.values], index=gdf.index)
640
+ return GeoSeries(boxes, index=gdf.index)
639
641
  if copy:
640
642
  gdf = gdf.copy()
641
- gdf.geometry = [box(*arr) for arr in gdf.bounds.values]
643
+ gdf.geometry = boxes
642
644
  return gdf
643
645
 
644
646
 
@@ -13,6 +13,7 @@ import shapely
13
13
  from geopandas import GeoDataFrame
14
14
  from geopandas import GeoSeries
15
15
  from pandas import DataFrame
16
+ from pandas import Index
16
17
  from pandas import MultiIndex
17
18
  from pandas import Series
18
19
 
@@ -110,6 +111,8 @@ def get_neighbor_indices(
110
111
  if gdf.crs != neighbors.crs:
111
112
  raise ValueError(f"'crs' mismatch. Got {gdf.crs} and {neighbors.crs}")
112
113
 
114
+ index_name = gdf.index.name
115
+
113
116
  if rtree_runner is None:
114
117
  rtree_runner = _get_instance(config, "rtree_runner", n_jobs=n_jobs)
115
118
 
@@ -141,6 +144,8 @@ def get_neighbor_indices(
141
144
  )
142
145
  index_mapper1 = {i: x for i, x in enumerate(gdf.index)}
143
146
  left = np.array([index_mapper1[i] for i in left])
147
+ if index_name:
148
+ left = Index(left, name=index_name)
144
149
  index_mapper2 = {i: x for i, x in enumerate(neighbors.index)}
145
150
  right = np.array([index_mapper2[i] for i in right])
146
151
  return Series(right, index=left, name="neighbor_index")
@@ -385,6 +385,9 @@ def get_bounds_series(
385
385
  """
386
386
  file_system = _get_file_system(file_system, {})
387
387
 
388
+ if isinstance(paths, (str | Path)):
389
+ paths = [paths]
390
+
388
391
  threads = (
389
392
  min(len(paths), int(multiprocessing.cpu_count())) or 1 if use_threads else 1
390
393
  )
@@ -457,7 +460,7 @@ def write_geopandas(
457
460
  )
458
461
 
459
462
  if not len(df) and get_child_paths(gcs_path, file_system):
460
- # no need to write empty df
463
+ # no need to write empty df for partitioned parquet
461
464
  return
462
465
  elif not len(df):
463
466
  if pandas_fallback:
@@ -465,8 +468,12 @@ def write_geopandas(
465
468
  df.geometry = df.geometry.astype(str)
466
469
  df.geometry = None
467
470
  try:
471
+ file_format: str = Path(gcs_path).suffix.lstrip(".")
472
+ write_method: Callable = getattr(df, f"to_{file_format}")
473
+ if file_format == "parquet":
474
+ kwargs["engine"] = "pyarrow"
468
475
  with file_system.open(gcs_path, "wb") as file:
469
- _to_geopandas(df, file, **kwargs)
476
+ write_method(file, **kwargs)
470
477
 
471
478
  except Exception as e:
472
479
  more_txt = PANDAS_FALLBACK_INFO if not pandas_fallback else ""
@@ -14,7 +14,6 @@ from statistics import mean
14
14
  from typing import Any
15
15
  from typing import ClassVar
16
16
 
17
- import branca as bc
18
17
  import folium
19
18
  import geopandas as gpd
20
19
  import joblib
@@ -723,9 +722,9 @@ class Explore(Map):
723
722
 
724
723
  bounds = self._get_bounds(gdf)
725
724
 
726
- if bounds is None:
727
- self.map = None
728
- return
725
+ if bounds is None and self.mask is not None:
726
+ bounds = self._get_bounds(_to_or_set_crs(to_gdf(self.mask), 4326))
727
+
729
728
  self.map = self._make_folium_map(
730
729
  bounds=bounds,
731
730
  max_zoom=self.max_zoom,
@@ -790,6 +789,8 @@ class Explore(Map):
790
789
  map_.add_child(tile)
791
790
 
792
791
  def _create_continous_map(self):
792
+ import branca as bc
793
+
793
794
  self._prepare_continous_map()
794
795
  if self.scheme:
795
796
  classified = self._classify_from_bins(self._gdf, bins=self.bins)
@@ -804,9 +805,8 @@ class Explore(Map):
804
805
 
805
806
  gdf = self._prepare_gdf_for_map(self._gdf)
806
807
  bounds = self._get_bounds(gdf)
807
- if bounds is None:
808
- self.map = None
809
- return
808
+ if bounds is None and self.mask is not None:
809
+ bounds = self._get_bounds(_to_or_set_crs(to_gdf(self.mask), 4326))
810
810
  self.map = self._make_folium_map(
811
811
  bounds=bounds,
812
812
  max_zoom=self.max_zoom,
@@ -899,6 +899,8 @@ class Explore(Map):
899
899
  map_kwds: dict | None = None,
900
900
  **kwargs,
901
901
  ):
902
+ import branca as bc
903
+
902
904
  if not map_kwds:
903
905
  map_kwds = {}
904
906
 
@@ -908,7 +910,7 @@ class Explore(Map):
908
910
  # create folium.Map object
909
911
  # Get bounds to specify location and map extent
910
912
  location = kwargs.pop("location", None)
911
- if location is None:
913
+ if location is None and bounds is not None:
912
914
  x = mean([bounds[0], bounds[2]])
913
915
  y = mean([bounds[1], bounds[3]])
914
916
  location = (y, x)
@@ -1130,8 +1132,9 @@ class Explore(Map):
1130
1132
  if gdf.index.name is not None:
1131
1133
  gdf = gdf.reset_index()
1132
1134
  # specify fields to show in the tooltip
1133
- tooltip = _tooltip_popup("tooltip", tooltip, gdf, **tooltip_kwds)
1134
- popup = _tooltip_popup("popup", popup, gdf, **popup_kwds)
1135
+ cols = list(gdf.columns.difference({df.geometry.name}))
1136
+ tooltip = _tooltip_popup("tooltip", tooltip, cols, **tooltip_kwds)
1137
+ popup = _tooltip_popup("popup", popup, cols, **popup_kwds)
1135
1138
  else:
1136
1139
  tooltip = None
1137
1140
  popup = None
@@ -1153,7 +1156,7 @@ class Explore(Map):
1153
1156
 
1154
1157
 
1155
1158
  def _tooltip_popup(
1156
- type_: str, fields: Any, gdf: GeoDataFrame, **kwargs
1159
+ type_: str, fields: Any, columns: list[str], **kwargs
1157
1160
  ) -> folium.GeoJsonTooltip | folium.GeoJsonPopup:
1158
1161
  """Get tooltip or popup."""
1159
1162
  # specify fields to show in the tooltip
@@ -1161,9 +1164,9 @@ def _tooltip_popup(
1161
1164
  return None
1162
1165
  else:
1163
1166
  if fields is True:
1164
- fields = gdf.columns.drop(gdf.geometry.name).to_list()
1167
+ fields = columns
1165
1168
  elif isinstance(fields, int):
1166
- fields = gdf.columns.drop(gdf.geometry.name).to_list()[:fields]
1169
+ fields = columns[:fields]
1167
1170
  elif isinstance(fields, str):
1168
1171
  fields = [fields]
1169
1172
 
@@ -1526,3 +1529,10 @@ def _image_collection_to_background_map(
1526
1529
  out = sorted(out, key=lambda x: x["label"])
1527
1530
 
1528
1531
  return out
1532
+
1533
+
1534
+ def _to_or_set_crs(df, crs):
1535
+ try:
1536
+ return df.to_crs(crs)
1537
+ except Exception:
1538
+ return df.set_crs(crs)
@@ -721,7 +721,7 @@ class Map:
721
721
 
722
722
  assert gdf.index.is_unique
723
723
 
724
- # if equal lenght, convert to integer and check for equality
724
+ # if equal length, convert to integer and check for equality
725
725
  if len(bins) == len(self._unique_values):
726
726
  if gdf[self._column].isna().all():
727
727
  return np.repeat(len(bins), len(gdf))
@@ -71,11 +71,10 @@ class NorgeIBilderWms(WmsLoader):
71
71
  not_contains: str | Iterable[str] | None = None
72
72
  show: bool | Iterable[int] | int = False
73
73
  _use_json: bool = True
74
+ url: str = "https://wms.geonorge.no/skwms1/wms.nib-prosjekter"
74
75
 
75
76
  def load_tiles(self, verbose: bool = False) -> None:
76
77
  """Load all Norge i bilder tiles into self.tiles."""
77
- url = "https://wms.geonorge.no/skwms1/wms.nib-prosjekter?SERVICE=WMS&REQUEST=GetCapabilities"
78
-
79
78
  name_pattern = r"<Name>(.*?)</Name>"
80
79
  bbox_pattern = (
81
80
  r"<EX_GeographicBoundingBox>.*?"
@@ -86,7 +85,7 @@ class NorgeIBilderWms(WmsLoader):
86
85
  )
87
86
 
88
87
  all_tiles: list[dict] = []
89
- with urlopen(url) as file:
88
+ with urlopen(self.url) as file:
90
89
  xml_data: str = file.read().decode("utf-8")
91
90
 
92
91
  for text in xml_data.split('<Layer queryable="1">')[1:]:
@@ -150,28 +149,6 @@ class NorgeIBilderWms(WmsLoader):
150
149
  url = "https://wms.geonorge.no/skwms1/wms.nib-mosaikk?SERVICE=WMS&REQUEST=GetCapabilities"
151
150
  wms = WebMapService(url, version="1.3.0")
152
151
  out = {}
153
- # ttiles = {wms[layer].title: [] for layer in list(wms.contents)}
154
- # for layer in list(wms.contents):
155
- # if wms[layer].title not in relevant_names:
156
- # continue
157
- # ttiles[wms[layer].title].append(layer)
158
- # import pandas as pd
159
-
160
- # df = pd.Series(ttiles).to_frame("title")
161
- # df["n"] = df["title"].str.len()
162
- # df = df.sort_values("n")
163
- # for x in df["title"]:
164
- # if len(x) == 1:
165
- # continue
166
- # bounds = {tuple(wms[layer].boundingBoxWGS84) for layer in x}
167
- # if len(bounds) <= 1:
168
- # continue
169
- # print()
170
- # for layer in x:
171
- # print(layer)
172
- # print(wms[layer].title)
173
- # bbox = wms[layer].boundingBoxWGS84
174
- # print(bbox)
175
152
 
176
153
  for layer in list(wms.contents):
177
154
  title = wms[layer].title
@@ -267,7 +244,7 @@ class NorgeIBilderWms(WmsLoader):
267
244
  if not len(tile_layers):
268
245
  return tile_layers
269
246
 
270
- if isinstance(self.show, int):
247
+ if isinstance(self.show, int) and not isinstance(self.show, bool):
271
248
  tile = tile_layers[list(tile_layers)[self.show]]
272
249
  tile.show = True
273
250
  elif isinstance(self.show, Iterable):
@@ -279,6 +256,8 @@ class NorgeIBilderWms(WmsLoader):
279
256
 
280
257
  def _filter_tiles(self, mask):
281
258
  """Filter relevant dates with pandas and geopandas because fast."""
259
+ if not self.tiles:
260
+ return pd.DataFrame(columns=["name", "year", "geometry", "bbox"])
282
261
  df = pd.DataFrame(self.tiles)
283
262
  filt = (df["name"].notna()) & (df["year"].str.contains("|".join(self.years)))
284
263
  if self.contains:
File without changes
File without changes
File without changes
File without changes
File without changes