ssb-sgis 1.2.17__tar.gz → 1.3.0__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.
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/PKG-INFO +1 -1
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/pyproject.toml +1 -1
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/general.py +5 -1
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/io/dapla_functions.py +5 -5
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/wms.py +115 -69
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/LICENSE +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/README.md +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/__init__.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/conf.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/debug_config.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/exceptions.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/__init__.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/bounds.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/buffer_dissolve_explode.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/centerlines.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/cleaning.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/conversion.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/duplicates.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/geocoding.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/geometry_types.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/neighbors.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/overlay.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/point_operations.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/polygon_operations.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/polygons_as_rings.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/runners.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/sfilter.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/geopandas_tools/utils.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/helpers.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/io/__init__.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/io/_is_dapla.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/io/opener.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/io/read_parquet.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/__init__.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/examine.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/explore.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/httpserver.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/legend.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/map.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/maps.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/norge_i_bilder.json +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/thematicmap.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/maps/tilesources.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/__init__.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/_get_route.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/_od_cost_matrix.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/_points.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/_service_area.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/closing_network_holes.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/cutting_lines.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/directednetwork.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/finding_isolated_networks.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/network.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/networkanalysis.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/networkanalysisrules.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/nodes.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/networkanalysis/traveling_salesman.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/parallel/__init__.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/parallel/parallel.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/py.typed +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/raster/__init__.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/raster/base.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/raster/image_collection.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/raster/indices.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/raster/regex.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/raster/sentinel_config.py +0 -0
- {ssb_sgis-1.2.17 → ssb_sgis-1.3.0}/src/sgis/raster/zonal.py +0 -0
|
@@ -21,6 +21,7 @@ from shapely import get_coordinates
|
|
|
21
21
|
from shapely import get_parts
|
|
22
22
|
from shapely import linestrings
|
|
23
23
|
from shapely import make_valid
|
|
24
|
+
from shapely.errors import GEOSException
|
|
24
25
|
from shapely.geometry import LineString
|
|
25
26
|
from shapely.geometry import MultiPoint
|
|
26
27
|
from shapely.geometry import Point
|
|
@@ -211,7 +212,10 @@ def clean_geoms(
|
|
|
211
212
|
if isinstance(gdf, GeoDataFrame):
|
|
212
213
|
# only repair if necessary
|
|
213
214
|
if not gdf.geometry.is_valid.all():
|
|
214
|
-
|
|
215
|
+
try:
|
|
216
|
+
gdf.geometry = gdf.make_valid()
|
|
217
|
+
except GEOSException as e:
|
|
218
|
+
raise type(e)(f"{e}: {gdf.geometry}") from e
|
|
215
219
|
|
|
216
220
|
notna = gdf.geometry.notna()
|
|
217
221
|
if not notna.all():
|
|
@@ -464,7 +464,7 @@ def write_geopandas(
|
|
|
464
464
|
)
|
|
465
465
|
|
|
466
466
|
if not len(df) and get_child_paths(gcs_path, file_system):
|
|
467
|
-
# no need to write empty df for partitioned parquet
|
|
467
|
+
# no need to write empty df for partitioned parquet - if root dir exists
|
|
468
468
|
return
|
|
469
469
|
elif not len(df):
|
|
470
470
|
if pandas_fallback:
|
|
@@ -586,9 +586,6 @@ def _write_partitioned_geoparquet(
|
|
|
586
586
|
):
|
|
587
587
|
file_system = _get_file_system(file_system, kwargs)
|
|
588
588
|
|
|
589
|
-
if basename_template is None:
|
|
590
|
-
basename_template = uuid.uuid4().hex + "-{i}.parquet"
|
|
591
|
-
|
|
592
589
|
if isinstance(partition_cols, str):
|
|
593
590
|
partition_cols = [partition_cols]
|
|
594
591
|
|
|
@@ -623,7 +620,10 @@ def _write_partitioned_geoparquet(
|
|
|
623
620
|
dfs.append(rows)
|
|
624
621
|
|
|
625
622
|
def threaded_write(rows: DataFrame, path: str) -> None:
|
|
626
|
-
|
|
623
|
+
if basename_template is None:
|
|
624
|
+
this_basename = (uuid.uuid4().hex + "-{i}.parquet").replace("-{i}", "0")
|
|
625
|
+
else:
|
|
626
|
+
this_basename = basename_template
|
|
627
627
|
for i, sibling_path in enumerate(sorted(glob_func(str(Path(path) / "**")))):
|
|
628
628
|
if paths_are_equal(sibling_path, path):
|
|
629
629
|
continue
|
|
@@ -3,7 +3,6 @@ import datetime
|
|
|
3
3
|
import json
|
|
4
4
|
import re
|
|
5
5
|
from collections.abc import Iterable
|
|
6
|
-
from dataclasses import dataclass
|
|
7
6
|
from io import BytesIO
|
|
8
7
|
from pathlib import Path
|
|
9
8
|
from typing import Any
|
|
@@ -30,18 +29,17 @@ from ..raster.image_collection import Band
|
|
|
30
29
|
|
|
31
30
|
JSON_PATH = Path(__file__).parent / "norge_i_bilder.json"
|
|
32
31
|
|
|
33
|
-
JSON_YEARS =
|
|
32
|
+
# JSON_YEARS = tuple(range(1900, datetime.datetime.now().year + 1))
|
|
33
|
+
JSON_YEARS = tuple(range(2006, datetime.datetime.now().year + 1))
|
|
34
34
|
|
|
35
|
-
DEFAULT_YEARS: tuple[
|
|
36
|
-
|
|
37
|
-
for year in range(
|
|
35
|
+
DEFAULT_YEARS: tuple[int] = tuple(
|
|
36
|
+
range(
|
|
38
37
|
int(datetime.datetime.now().year) - 10,
|
|
39
38
|
int(datetime.datetime.now().year) + 1,
|
|
40
39
|
)
|
|
41
40
|
)
|
|
42
41
|
|
|
43
42
|
|
|
44
|
-
@dataclass
|
|
45
43
|
class WmsLoader(abc.ABC):
|
|
46
44
|
"""Abstract base class for wms loaders.
|
|
47
45
|
|
|
@@ -49,32 +47,82 @@ class WmsLoader(abc.ABC):
|
|
|
49
47
|
which should return a list of folium.WmsTileLayer.
|
|
50
48
|
"""
|
|
51
49
|
|
|
50
|
+
_min_year: int = 1900
|
|
51
|
+
|
|
52
|
+
@abc.abstractmethod
|
|
53
|
+
def filter_tiles(
|
|
54
|
+
self, mask: GeoDataFrame | GeoSeries | Geometry | tuple[float]
|
|
55
|
+
) -> list[str]:
|
|
56
|
+
"""Filter relevant dates with pandas and geopandas because fast."""
|
|
57
|
+
|
|
52
58
|
@abc.abstractmethod
|
|
53
59
|
def get_tiles(self, bbox: Any, max_zoom: int = 40) -> list[folium.WmsTileLayer]:
|
|
54
60
|
"""Get all tiles intersecting with a bbox."""
|
|
55
61
|
|
|
56
62
|
@abc.abstractmethod
|
|
57
63
|
def load_tiles(self) -> None:
|
|
58
|
-
"""Load all tiles into self.
|
|
64
|
+
"""Load all tiles into self._tiles.
|
|
59
65
|
|
|
60
66
|
Not needed in sgis.explore.
|
|
61
67
|
"""
|
|
62
68
|
pass
|
|
63
69
|
|
|
70
|
+
def __repr__(self) -> str:
|
|
71
|
+
"""Print representation."""
|
|
72
|
+
return str(self)
|
|
73
|
+
|
|
74
|
+
def __str__(self) -> str:
|
|
75
|
+
"""String representation."""
|
|
76
|
+
|
|
77
|
+
def maybe_to_string(value: Any):
|
|
78
|
+
if isinstance(value, str):
|
|
79
|
+
return f"'{value}'"
|
|
80
|
+
return value
|
|
81
|
+
|
|
82
|
+
txt = ", ".join(
|
|
83
|
+
f"{k}={maybe_to_string(v)}"
|
|
84
|
+
for k, v in self.__dict__.items()
|
|
85
|
+
if not k.startswith("_")
|
|
86
|
+
)
|
|
87
|
+
return f"{self.__class__.__name__}({txt})"
|
|
88
|
+
|
|
64
89
|
|
|
65
|
-
@dataclass
|
|
66
90
|
class NorgeIBilderWms(WmsLoader):
|
|
67
|
-
"""Loads Norge i bilder tiles as folium.WmsTiles.
|
|
91
|
+
"""Loads Norge i bilder tiles as folium.WmsTiles.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
years: list of years to search for images.
|
|
95
|
+
contains: substrings to include in image search.
|
|
96
|
+
not_contains: substrings to exclude in image search.
|
|
97
|
+
show: Whether to show all layers upon initialisation of the map.
|
|
98
|
+
_use_json: Whether to use pre-made json file of image names and bounds/masks
|
|
99
|
+
if all years are within range. Defaults to True (much faster).
|
|
100
|
+
"""
|
|
68
101
|
|
|
69
|
-
years: Iterable[int | str] = DEFAULT_YEARS
|
|
70
|
-
contains: str | Iterable[str] | None = None
|
|
71
|
-
not_contains: str | Iterable[str] | None = None
|
|
72
|
-
show: bool | Iterable[int] | int = False
|
|
73
|
-
_use_json: bool = True
|
|
74
102
|
url: str = "https://wms.geonorge.no/skwms1/wms.nib-prosjekter"
|
|
75
103
|
|
|
104
|
+
def __init__(
|
|
105
|
+
self,
|
|
106
|
+
years: Iterable[int | str] = DEFAULT_YEARS,
|
|
107
|
+
contains: str | Iterable[str] | None = None,
|
|
108
|
+
not_contains: str | Iterable[str] | None = None,
|
|
109
|
+
show: bool | Iterable[int] | int = False,
|
|
110
|
+
_use_json: bool = True,
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Initialiser."""
|
|
113
|
+
self.years = [int(year) for year in years]
|
|
114
|
+
self.contains = contains
|
|
115
|
+
self.not_contains = not_contains
|
|
116
|
+
self.show = show
|
|
117
|
+
self._use_json = _use_json
|
|
118
|
+
|
|
119
|
+
if self._use_json and all(year in JSON_YEARS for year in self.years):
|
|
120
|
+
self._load_from_json()
|
|
121
|
+
else:
|
|
122
|
+
self._tiles = None
|
|
123
|
+
|
|
76
124
|
def load_tiles(self, verbose: bool = False) -> None:
|
|
77
|
-
"""Load all Norge i bilder tiles into self.
|
|
125
|
+
"""Load all Norge i bilder tiles into self._tiles."""
|
|
78
126
|
name_pattern = r"<Name>(.*?)</Name>"
|
|
79
127
|
bbox_pattern = (
|
|
80
128
|
r"<EX_GeographicBoundingBox>.*?"
|
|
@@ -105,14 +153,20 @@ class NorgeIBilderWms(WmsLoader):
|
|
|
105
153
|
|
|
106
154
|
if (
|
|
107
155
|
not name
|
|
108
|
-
or not any(year in name for year in self.years)
|
|
156
|
+
or not any(str(year) in name for year in self.years)
|
|
109
157
|
or (
|
|
110
158
|
self.contains
|
|
111
|
-
and not any(
|
|
159
|
+
and not any(
|
|
160
|
+
re.search(x, name.lower())
|
|
161
|
+
for x in _string_as_list(self.contains)
|
|
162
|
+
)
|
|
112
163
|
)
|
|
113
164
|
or (
|
|
114
165
|
self.not_contains
|
|
115
|
-
and any(
|
|
166
|
+
and any(
|
|
167
|
+
re.search(x, name.lower())
|
|
168
|
+
for x in _string_as_list(self.not_contains)
|
|
169
|
+
)
|
|
116
170
|
)
|
|
117
171
|
):
|
|
118
172
|
continue
|
|
@@ -131,10 +185,10 @@ class NorgeIBilderWms(WmsLoader):
|
|
|
131
185
|
|
|
132
186
|
all_tiles.append(this_tile)
|
|
133
187
|
|
|
134
|
-
self.
|
|
188
|
+
self._tiles = sorted(all_tiles, key=lambda x: (x["year"]))
|
|
135
189
|
|
|
136
190
|
masks = self._get_norge_i_bilder_polygon_masks(verbose=verbose)
|
|
137
|
-
for tile in self.
|
|
191
|
+
for tile in self._tiles:
|
|
138
192
|
mask = masks.get(tile["name"], None)
|
|
139
193
|
tile["geometry"] = mask
|
|
140
194
|
|
|
@@ -143,7 +197,7 @@ class NorgeIBilderWms(WmsLoader):
|
|
|
143
197
|
from owslib.wms import WebMapService
|
|
144
198
|
from PIL import Image
|
|
145
199
|
|
|
146
|
-
relevant_names: dict[str, str] = {x["name"]: x["bbox"] for x in self.
|
|
200
|
+
relevant_names: dict[str, str] = {x["name"]: x["bbox"] for x in self._tiles}
|
|
147
201
|
assert len(relevant_names), relevant_names
|
|
148
202
|
|
|
149
203
|
url = "https://wms.geonorge.no/skwms1/wms.nib-mosaikk?SERVICE=WMS&REQUEST=GetCapabilities"
|
|
@@ -214,7 +268,7 @@ class NorgeIBilderWms(WmsLoader):
|
|
|
214
268
|
|
|
215
269
|
def get_tiles(self, mask: Any, max_zoom: int = 40) -> list[folium.WmsTileLayer]:
|
|
216
270
|
"""Get all Norge i bilder tiles intersecting with a mask (bbox or polygon)."""
|
|
217
|
-
if self.
|
|
271
|
+
if self._tiles is None:
|
|
218
272
|
self.load_tiles()
|
|
219
273
|
|
|
220
274
|
if not isinstance(mask, (GeoSeries | GeoDataFrame | Geometry)):
|
|
@@ -225,7 +279,7 @@ class NorgeIBilderWms(WmsLoader):
|
|
|
225
279
|
else:
|
|
226
280
|
show = False
|
|
227
281
|
|
|
228
|
-
relevant_tiles = self.
|
|
282
|
+
relevant_tiles = self.filter_tiles(mask)
|
|
229
283
|
tile_layers = {
|
|
230
284
|
name: folium.WmsTileLayer(
|
|
231
285
|
url="https://wms.geonorge.no/skwms1/wms.nib-prosjekter",
|
|
@@ -238,7 +292,7 @@ class NorgeIBilderWms(WmsLoader):
|
|
|
238
292
|
show=show,
|
|
239
293
|
max_zoom=max_zoom,
|
|
240
294
|
)
|
|
241
|
-
for name in relevant_tiles
|
|
295
|
+
for name in relevant_tiles
|
|
242
296
|
}
|
|
243
297
|
|
|
244
298
|
if not len(tile_layers):
|
|
@@ -254,59 +308,51 @@ class NorgeIBilderWms(WmsLoader):
|
|
|
254
308
|
|
|
255
309
|
return tile_layers
|
|
256
310
|
|
|
257
|
-
def
|
|
311
|
+
def filter_tiles(
|
|
312
|
+
self, mask: GeoDataFrame | GeoSeries | Geometry | tuple[float]
|
|
313
|
+
) -> list[str]:
|
|
258
314
|
"""Filter relevant dates with pandas and geopandas because fast."""
|
|
259
|
-
if not self.
|
|
260
|
-
return
|
|
261
|
-
df = pd.DataFrame(self.
|
|
262
|
-
filt = (df["name"].notna()) & (
|
|
315
|
+
if not self._tiles:
|
|
316
|
+
return []
|
|
317
|
+
df = pd.DataFrame(self._tiles)
|
|
318
|
+
filt = (df["name"].notna()) & (
|
|
319
|
+
df["year"].str.contains("|".join([str(year) for year in self.years]))
|
|
320
|
+
)
|
|
263
321
|
if self.contains:
|
|
264
|
-
for x in self.contains:
|
|
322
|
+
for x in _string_as_list(self.contains):
|
|
265
323
|
filt &= df["name"].str.contains(x)
|
|
266
324
|
if self.not_contains:
|
|
267
|
-
for x in self.not_contains:
|
|
325
|
+
for x in _string_as_list(self.not_contains):
|
|
268
326
|
filt &= ~df["name"].str.contains(x)
|
|
269
327
|
df = df[filt]
|
|
270
328
|
geoms = np.where(df["geometry"].notna(), df["geometry"], df["bbox"])
|
|
271
329
|
geoms = GeoSeries(geoms)
|
|
272
330
|
assert geoms.index.is_unique
|
|
273
|
-
return df.iloc[sfilter(geoms, mask).index]
|
|
274
|
-
|
|
275
|
-
def
|
|
276
|
-
"""
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
331
|
+
return list(df.iloc[sfilter(geoms, mask).index]["name"])
|
|
332
|
+
|
|
333
|
+
def _load_from_json(self) -> None:
|
|
334
|
+
"""Load tiles from json file."""
|
|
335
|
+
try:
|
|
336
|
+
with open(JSON_PATH, encoding="utf-8") as file:
|
|
337
|
+
self._tiles = json.load(file)
|
|
338
|
+
except FileNotFoundError:
|
|
339
|
+
self._tiles = None
|
|
340
|
+
return
|
|
341
|
+
self._tiles = [
|
|
342
|
+
{
|
|
343
|
+
key: (
|
|
344
|
+
value
|
|
345
|
+
if key not in ["bbox", "geometry"]
|
|
346
|
+
else shapely.wkt.loads(value)
|
|
347
|
+
)
|
|
348
|
+
for key, value in tile.items()
|
|
349
|
+
}
|
|
350
|
+
for tile in self._tiles
|
|
351
|
+
if any(str(year) in tile["name"] for year in self.years)
|
|
352
|
+
]
|
|
285
353
|
|
|
286
|
-
self.years = [str(int(year)) for year in self.years]
|
|
287
354
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
except FileNotFoundError:
|
|
293
|
-
self.tiles = None
|
|
294
|
-
return
|
|
295
|
-
self.tiles = [
|
|
296
|
-
{
|
|
297
|
-
key: (
|
|
298
|
-
value
|
|
299
|
-
if key not in ["bbox", "geometry"]
|
|
300
|
-
else shapely.wkt.loads(value)
|
|
301
|
-
)
|
|
302
|
-
for key, value in tile.items()
|
|
303
|
-
}
|
|
304
|
-
for tile in self.tiles
|
|
305
|
-
if any(str(year) in tile["name"] for year in self.years)
|
|
306
|
-
]
|
|
307
|
-
else:
|
|
308
|
-
self.tiles = None
|
|
309
|
-
|
|
310
|
-
def __repr__(self) -> str:
|
|
311
|
-
"""Print representation."""
|
|
312
|
-
return f"{self.__class__.__name__}({len(self.tiles or [])})"
|
|
355
|
+
def _string_as_list(x: str | list[str]) -> list[str] | None:
|
|
356
|
+
if not x:
|
|
357
|
+
return None
|
|
358
|
+
return [x] if isinstance(x, str) else list(x)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|