ssb-sgis 1.2.10__py3-none-any.whl → 1.2.12__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.
@@ -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 ""
sgis/maps/examine.py CHANGED
@@ -99,11 +99,7 @@ class Examine:
99
99
 
100
100
  m = Explore(*gdfs, column=column, **kwargs)
101
101
 
102
- # m = Map(*gdfs, column=column, **kwargs)
103
- self._gdfs: dict[str, gpd.GeoDataFrame] = dict(
104
- zip(m.labels, m.gdfs, strict=False)
105
- )
106
-
102
+ self._gdfs = m._gdfs
107
103
  self.rasters: dict[str, ImageCollection | Image | Band] = m.rasters
108
104
 
109
105
  self.indices = list(range(len(self.mask_gdf)))
sgis/maps/explore.py CHANGED
@@ -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)
sgis/maps/map.py CHANGED
@@ -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))
sgis/maps/wms.py CHANGED
@@ -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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ssb-sgis
3
- Version: 1.2.10
3
+ Version: 1.2.12
4
4
  Summary: GIS functions used at Statistics Norway.
5
5
  Home-page: https://github.com/statisticsnorway/ssb-sgis
6
6
  License: MIT
@@ -3,7 +3,7 @@ sgis/conf.py,sha256=pLqmvIKoKmXoW8chja3iQpbDUp9Z39vzl97MGH8ZHW0,2614
3
3
  sgis/debug_config.py,sha256=Tfr19kU46hSkkspsIJcrUWvlhaL4U3-f8xEPkujSCAQ,593
4
4
  sgis/exceptions.py,sha256=WNaEBPNNx0rmz-YDzlFX4vIE7ocJQruUTqS2RNAu2zU,660
5
5
  sgis/geopandas_tools/__init__.py,sha256=bo8lFMcltOz7TtWAi52_ekR2gd3mjfBfKeMDV5zuqFY,28
6
- sgis/geopandas_tools/bounds.py,sha256=YJyF0gp78hFAjLLZmDquRKCBAtbt7QouG3snTcJeNQs,23822
6
+ sgis/geopandas_tools/bounds.py,sha256=PsA_rPEDIS0CopLtolWCB01UEdxc8gtsNbUqMd5AOLY,23855
7
7
  sgis/geopandas_tools/buffer_dissolve_explode.py,sha256=z9HvakazR_prXH862e8-gEe7UFbeI4rRTbUaBgPeMBk,19552
8
8
  sgis/geopandas_tools/centerlines.py,sha256=Q65Sx01SeAlulBEd9oaZkB2maBBNdLcJwAbTILg4SPU,11848
9
9
  sgis/geopandas_tools/cleaning.py,sha256=fST0xFztmyn-QUOAfvjZmu7aO_zPiolWK7gd7TR6ffI,24393
@@ -12,7 +12,7 @@ sgis/geopandas_tools/duplicates.py,sha256=TDDM4u1n7SIkyJrOfl1Lno92AmUPqtXBHsj1IU
12
12
  sgis/geopandas_tools/general.py,sha256=YRpNEdwTHyFdQOdAfbCmYXS7PxoDjXxoagwpteXkYdI,43937
13
13
  sgis/geopandas_tools/geocoding.py,sha256=sZjUW52ULhQWDLmU51C9_itBePkDuWkp8swvYaiYmJk,679
14
14
  sgis/geopandas_tools/geometry_types.py,sha256=ijQDbQaZPqPGjBl707H4yooNXpk21RXyatI7itnvqLk,7603
15
- sgis/geopandas_tools/neighbors.py,sha256=qTvnOyQyrcWQd0BDrmOvFQd8csMh005e_idJGmB4g7k,17485
15
+ sgis/geopandas_tools/neighbors.py,sha256=VZGOwwC3-C6KpwLQ3j0K5cOVInmckxIXoGMqPGkemk4,17606
16
16
  sgis/geopandas_tools/overlay.py,sha256=5i9u8GgFuU0fCqzELsbIaoUPhw-E7eZHl_yKB0wEcGM,23464
17
17
  sgis/geopandas_tools/point_operations.py,sha256=JM4hvfIVxZaZdGNlGzcCurrKzkgC_b9hzbFYN42f9WY,6972
18
18
  sgis/geopandas_tools/polygon_operations.py,sha256=v-B9IgbFfm4dVHKPyzvmnNiqVCdtl9ddpCsQpZZ-9sU,49284
@@ -23,20 +23,20 @@ sgis/geopandas_tools/utils.py,sha256=X0pRvB1tWgV_0BCrRS1HU9LtLGnZCpvVPxyqM9JGb0Y
23
23
  sgis/helpers.py,sha256=4N6vFWQ3TYVzRHNcWY_fNa_GkFuaZB3vtCkkFND-qs0,9628
24
24
  sgis/io/__init__.py,sha256=uyBr20YDqB2bQttrd5q1JuGOvX32A-MSvS7Wmw5f5qg,177
25
25
  sgis/io/_is_dapla.py,sha256=wmfkSe98IrLhUg3dtXZusV6OVC8VlY1kbc5EQDf3P-Q,358
26
- sgis/io/dapla_functions.py,sha256=k7q4QPbHARUOhtayV59vkuhLfFVqcUXcM8WZwcuTgu0,31125
26
+ sgis/io/dapla_functions.py,sha256=9NqkL67WdJJHczIWNdChHZp8T5hlXhcYucX7GWN1mCA,31430
27
27
  sgis/io/opener.py,sha256=HWO3G1NB6bpXKM94JadCD513vjat1o1TFjWGWzyVasg,898
28
28
  sgis/io/read_parquet.py,sha256=FvZYv1rLkUlrSaUY6QW6E1yntmntTeQuZ9ZRgCDO4IM,3776
29
29
  sgis/maps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- sgis/maps/examine.py,sha256=Pb0dH8JazU5E2svfQrzHO1Bi-sjy5SeyY6zoeMO34jE,9369
31
- sgis/maps/explore.py,sha256=azfNNcEEiNp2lJxWN1Emf7kcmG60WL_ok_ilMw0-IL8,47914
30
+ sgis/maps/examine.py,sha256=69nPtMChKmso7Yy8X--UoTWJjKmjMF1VHsdLpPKFbA0,9233
31
+ sgis/maps/explore.py,sha256=ANbhScthhwznLEUDDjRUBmniGmkdF9zftbzp9dYHu-U,48210
32
32
  sgis/maps/httpserver.py,sha256=TETSGOgLjKl3TquPGoIP0tCJCz7BIwmXrrzSCT7jhXE,2550
33
33
  sgis/maps/legend.py,sha256=qq2RkebuaNAdFztlXrDOWbN0voeK5w5VycmRKyx0NdM,26512
34
- sgis/maps/map.py,sha256=XWf3QJ6a4gZno2NziK1dKLRktJGGr-vn6eHudBlW9Uc,30758
34
+ sgis/maps/map.py,sha256=07YK_oHa2z_yw_es06pd-80dV8YTI5mkTyJxyud707Y,30758
35
35
  sgis/maps/maps.py,sha256=fLK5WUlQ2YTm7t-8260lYxCFvpZN6j0Y-bVYCyv8NAY,23249
36
36
  sgis/maps/norge_i_bilder.json,sha256=G9DIN_2vyn-18UF5wUC-koZxFCbiNxMu0BbCJhMFJUk,15050340
37
37
  sgis/maps/thematicmap.py,sha256=Z3o_Bca0oty5Cn35pZfX5Qy52sXDVIMVSFD6IlZrovo,25111
38
38
  sgis/maps/tilesources.py,sha256=F4mFHxPwkiPJdVKzNkScTX6xbJAMIUtlTq4mQ83oguw,1746
39
- sgis/maps/wms.py,sha256=jQGF7na-IruG7FF3nHzvZB0BkdkhiWRRwfhkkx4aWkU,11970
39
+ sgis/maps/wms.py,sha256=3ZPf-H3sirvHeLQdXGwE3j6w1sFQCkExsEWkvHl7a4g,11233
40
40
  sgis/networkanalysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  sgis/networkanalysis/_get_route.py,sha256=dMX4Vm6O90ISIZPjQWuZMVMuEubkeSdC2osMCbFvrRU,7750
42
42
  sgis/networkanalysis/_od_cost_matrix.py,sha256=zkyPX7ObT996ahaFJ2oI0D0SqQWbWyfy_qLtXwValPg,3434
@@ -61,7 +61,7 @@ sgis/raster/indices.py,sha256=efJmgfPg_VuSzXFosXV661IendF8CwPFWtMhyP4TMUg,222
61
61
  sgis/raster/regex.py,sha256=4idTJ9vFtsGtbxcjJrx2VrpJJuDMP3bLdqF93Vc_cmY,3752
62
62
  sgis/raster/sentinel_config.py,sha256=nySDqn2R8M6W8jguoBeSAK_zzbAsqmaI59i32446FwY,1268
63
63
  sgis/raster/zonal.py,sha256=D4Gyptw-yOLTCO41peIuYbY-DANsJCG19xXDlf1QAz4,2299
64
- ssb_sgis-1.2.10.dist-info/LICENSE,sha256=np3IfD5m0ZUofn_kVzDZqliozuiO6wrktw3LRPjyEiI,1073
65
- ssb_sgis-1.2.10.dist-info/METADATA,sha256=s_sJK6_o3yyoeiZeHsPXwdvYf4F3R0wlWFPupfx_J2o,11741
66
- ssb_sgis-1.2.10.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
67
- ssb_sgis-1.2.10.dist-info/RECORD,,
64
+ ssb_sgis-1.2.12.dist-info/LICENSE,sha256=np3IfD5m0ZUofn_kVzDZqliozuiO6wrktw3LRPjyEiI,1073
65
+ ssb_sgis-1.2.12.dist-info/METADATA,sha256=4d1K-kdnGD3uu3zopoxzmxTQDsziS9W3RxbFNItpddQ,11741
66
+ ssb_sgis-1.2.12.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
67
+ ssb_sgis-1.2.12.dist-info/RECORD,,