ssb-sgis 1.0.13__py3-none-any.whl → 1.0.15__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/__init__.py +1 -0
- sgis/maps/explore.py +19 -1
- sgis/maps/maps.py +15 -0
- sgis/maps/norge_i_bilder.json +11517 -0
- sgis/maps/wms.py +187 -0
- {ssb_sgis-1.0.13.dist-info → ssb_sgis-1.0.15.dist-info}/METADATA +1 -1
- {ssb_sgis-1.0.13.dist-info → ssb_sgis-1.0.15.dist-info}/RECORD +9 -7
- {ssb_sgis-1.0.13.dist-info → ssb_sgis-1.0.15.dist-info}/LICENSE +0 -0
- {ssb_sgis-1.0.13.dist-info → ssb_sgis-1.0.15.dist-info}/WHEEL +0 -0
sgis/maps/wms.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import datetime
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
from urllib.request import urlopen
|
|
10
|
+
|
|
11
|
+
import folium
|
|
12
|
+
import shapely
|
|
13
|
+
|
|
14
|
+
from ..geopandas_tools.conversion import to_shapely
|
|
15
|
+
|
|
16
|
+
JSON_PATH = Path(__file__).parent / "norge_i_bilder.json"
|
|
17
|
+
|
|
18
|
+
DEFAULT_YEARS: tuple[str] = tuple(
|
|
19
|
+
str(year)
|
|
20
|
+
for year in range(
|
|
21
|
+
int(datetime.datetime.now().year) - 8,
|
|
22
|
+
int(datetime.datetime.now().year) + 1,
|
|
23
|
+
)
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class WmsLoader(abc.ABC):
|
|
29
|
+
"""Abstract base class for wms loaders.
|
|
30
|
+
|
|
31
|
+
Child classes must implement the method 'get_tiles',
|
|
32
|
+
which should return a list of folium.WmsTileLayer.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def get_tiles(self, bbox: Any, max_zoom: int = 40) -> list[folium.WmsTileLayer]:
|
|
37
|
+
"""Get all tiles intersecting with a bbox."""
|
|
38
|
+
|
|
39
|
+
@abc.abstractmethod
|
|
40
|
+
def load_tiles(self) -> None:
|
|
41
|
+
"""Load all tiles into self.tiles.
|
|
42
|
+
|
|
43
|
+
Not needed in sgis.explore.
|
|
44
|
+
"""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class NorgeIBilderWms(WmsLoader):
|
|
50
|
+
"""Loads Norge i bilder tiles as folium.WmsTiles."""
|
|
51
|
+
|
|
52
|
+
years: Iterable[int | str] = DEFAULT_YEARS
|
|
53
|
+
contains: str | Iterable[str] | None = None
|
|
54
|
+
not_contains: str | Iterable[str] | None = None
|
|
55
|
+
|
|
56
|
+
def load_tiles(self) -> None:
|
|
57
|
+
"""Load all Norge i bilder tiles into self.tiles."""
|
|
58
|
+
url = "https://wms.geonorge.no/skwms1/wms.nib-prosjekter?SERVICE=WMS&REQUEST=GetCapabilities"
|
|
59
|
+
|
|
60
|
+
name_pattern = r"<Name>(.*?)</Name>"
|
|
61
|
+
bbox_pattern = (
|
|
62
|
+
r"<EX_GeographicBoundingBox>.*?"
|
|
63
|
+
r"<westBoundLongitude>(.*?)</westBoundLongitude>.*?"
|
|
64
|
+
r"<eastBoundLongitude>(.*?)</eastBoundLongitude>.*?"
|
|
65
|
+
r"<southBoundLatitude>(.*?)</southBoundLatitude>.*?"
|
|
66
|
+
r"<northBoundLatitude>(.*?)</northBoundLatitude>.*?</EX_GeographicBoundingBox>"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
all_tiles: list[dict] = []
|
|
70
|
+
with urlopen(url) as file:
|
|
71
|
+
xml_data: str = file.read().decode("utf-8")
|
|
72
|
+
|
|
73
|
+
for text in xml_data.split('<Layer queryable="1">')[1:]:
|
|
74
|
+
|
|
75
|
+
# Extract bounding box values
|
|
76
|
+
bbox_match = re.search(bbox_pattern, text, re.DOTALL)
|
|
77
|
+
if bbox_match:
|
|
78
|
+
minx, maxx, miny, maxy = (
|
|
79
|
+
float(bbox_match.group(i)) for i in [1, 2, 3, 4]
|
|
80
|
+
)
|
|
81
|
+
this_bbox = shapely.box(minx, miny, maxx, maxy)
|
|
82
|
+
else:
|
|
83
|
+
this_bbox = None
|
|
84
|
+
|
|
85
|
+
name_match = re.search(name_pattern, text, re.DOTALL)
|
|
86
|
+
name = name_match.group(1) if name_match else None
|
|
87
|
+
|
|
88
|
+
if (
|
|
89
|
+
not name
|
|
90
|
+
or not any(year in name for year in self.years)
|
|
91
|
+
or (
|
|
92
|
+
self.contains
|
|
93
|
+
and not any(re.search(x, name.lower()) for x in self.contains)
|
|
94
|
+
)
|
|
95
|
+
or (
|
|
96
|
+
self.not_contains
|
|
97
|
+
and any(re.search(x, name.lower()) for x in self.not_contains)
|
|
98
|
+
)
|
|
99
|
+
):
|
|
100
|
+
continue
|
|
101
|
+
|
|
102
|
+
this_tile = {}
|
|
103
|
+
this_tile["name"] = name
|
|
104
|
+
this_tile["bbox"] = this_bbox
|
|
105
|
+
year = name.split(" ")[-1]
|
|
106
|
+
if year.isnumeric() and len(year) == 4:
|
|
107
|
+
this_tile["year"] = year
|
|
108
|
+
else:
|
|
109
|
+
this_tile["year"] = "9999"
|
|
110
|
+
all_tiles.append(this_tile)
|
|
111
|
+
|
|
112
|
+
self.tiles = sorted(all_tiles, key=lambda x: x["year"])
|
|
113
|
+
|
|
114
|
+
def get_tiles(self, bbox: Any, max_zoom: int = 40) -> list[folium.WmsTileLayer]:
|
|
115
|
+
"""Get all Norge i bilder tiles intersecting with a bbox."""
|
|
116
|
+
if self.tiles is None:
|
|
117
|
+
self.load_tiles()
|
|
118
|
+
|
|
119
|
+
all_tiles = {}
|
|
120
|
+
|
|
121
|
+
bbox = to_shapely(bbox)
|
|
122
|
+
|
|
123
|
+
for tile in self.tiles:
|
|
124
|
+
if not tile["bbox"] or not tile["bbox"].intersects(bbox):
|
|
125
|
+
continue
|
|
126
|
+
|
|
127
|
+
name = tile["name"]
|
|
128
|
+
|
|
129
|
+
if (
|
|
130
|
+
not name
|
|
131
|
+
or not any(year in name for year in self.years)
|
|
132
|
+
or (
|
|
133
|
+
self.contains
|
|
134
|
+
and not any(re.search(x, name.lower()) for x in self.contains)
|
|
135
|
+
)
|
|
136
|
+
or (
|
|
137
|
+
self.not_contains
|
|
138
|
+
and any(re.search(x, name.lower()) for x in self.not_contains)
|
|
139
|
+
)
|
|
140
|
+
):
|
|
141
|
+
continue
|
|
142
|
+
|
|
143
|
+
all_tiles[name] = folium.WmsTileLayer(
|
|
144
|
+
url="https://wms.geonorge.no/skwms1/wms.nib-prosjekter",
|
|
145
|
+
name=name,
|
|
146
|
+
layers=name,
|
|
147
|
+
format="image/png", # Tile format
|
|
148
|
+
transparent=True, # Allow transparency
|
|
149
|
+
version="1.3.0", # WMS version
|
|
150
|
+
attr="© <a href='https://www.geonorge.no/'>Geonorge</a>",
|
|
151
|
+
show=False,
|
|
152
|
+
max_zoom=max_zoom,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
return all_tiles
|
|
156
|
+
|
|
157
|
+
def __post_init__(self) -> None:
|
|
158
|
+
"""Fix typings."""
|
|
159
|
+
if self.contains and isinstance(self.contains, str):
|
|
160
|
+
self.contains = [self.contains.lower()]
|
|
161
|
+
elif self.contains:
|
|
162
|
+
self.contains = [x.lower() for x in self.contains]
|
|
163
|
+
|
|
164
|
+
if self.not_contains and isinstance(self.not_contains, str):
|
|
165
|
+
self.not_contains = [self.not_contains.lower()]
|
|
166
|
+
elif self.not_contains:
|
|
167
|
+
self.not_contains = [x.lower() for x in self.not_contains]
|
|
168
|
+
|
|
169
|
+
self.years = [str(int(year)) for year in self.years]
|
|
170
|
+
|
|
171
|
+
if all(year in DEFAULT_YEARS for year in self.years):
|
|
172
|
+
try:
|
|
173
|
+
with open(JSON_PATH, encoding="utf-8") as file:
|
|
174
|
+
self.tiles = json.load(file)
|
|
175
|
+
except FileNotFoundError:
|
|
176
|
+
self.tiles = None
|
|
177
|
+
return
|
|
178
|
+
self.tiles = [
|
|
179
|
+
{
|
|
180
|
+
key: value if key != "bbox" else shapely.wkt.loads(value)
|
|
181
|
+
for key, value in tile.items()
|
|
182
|
+
}
|
|
183
|
+
for tile in self.tiles
|
|
184
|
+
if any(str(year) in tile["name"] for year in self.years)
|
|
185
|
+
]
|
|
186
|
+
else:
|
|
187
|
+
self.tiles = None
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
sgis/__init__.py,sha256=
|
|
1
|
+
sgis/__init__.py,sha256=Bh-W4cB6-1uc-xRzUxqxECwwoennpdlikZI3gwXtZ7E,7389
|
|
2
2
|
sgis/debug_config.py,sha256=Tfr19kU46hSkkspsIJcrUWvlhaL4U3-f8xEPkujSCAQ,593
|
|
3
3
|
sgis/exceptions.py,sha256=WNaEBPNNx0rmz-YDzlFX4vIE7ocJQruUTqS2RNAu2zU,660
|
|
4
4
|
sgis/geopandas_tools/__init__.py,sha256=bo8lFMcltOz7TtWAi52_ekR2gd3mjfBfKeMDV5zuqFY,28
|
|
@@ -24,13 +24,15 @@ 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=
|
|
27
|
+
sgis/maps/explore.py,sha256=JX9ZTeHVsV1KsXP2YNVBa21Edvc6EksKdbb3V6W0tKs,47051
|
|
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
|
|
31
|
-
sgis/maps/maps.py,sha256=
|
|
31
|
+
sgis/maps/maps.py,sha256=gxu0rgcVygjudRtM1dVRmsUMilMUIg3vG-UgvASM91E,23072
|
|
32
|
+
sgis/maps/norge_i_bilder.json,sha256=W_mFfte3DxugWbEudZ5fadZ2JeFYb0hyab2Quf4oJME,481311
|
|
32
33
|
sgis/maps/thematicmap.py,sha256=yAE1xEfubJcDmBlOJf-Q3SVae1ZHIEMP-YB95Wy8cRw,21691
|
|
33
34
|
sgis/maps/tilesources.py,sha256=F4mFHxPwkiPJdVKzNkScTX6xbJAMIUtlTq4mQ83oguw,1746
|
|
35
|
+
sgis/maps/wms.py,sha256=XHlCszR0raPbmUc2wYpQ_XRHnSJ6c1ic3w2dNnfMRm4,6252
|
|
34
36
|
sgis/networkanalysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
37
|
sgis/networkanalysis/_get_route.py,sha256=9I3t9pnccUPr4mozy3TJCOpGCCf3UOIojmsbifubZbA,6368
|
|
36
38
|
sgis/networkanalysis/_od_cost_matrix.py,sha256=zkyPX7ObT996ahaFJ2oI0D0SqQWbWyfy_qLtXwValPg,3434
|
|
@@ -54,7 +56,7 @@ sgis/raster/indices.py,sha256=-J1HYmnT240iozvgagvyis6K0_GHZHRuUrPOgyoeIrY,223
|
|
|
54
56
|
sgis/raster/regex.py,sha256=kYhVpRYzoXutx1dSYmqMoselWXww7MMEsTPmLZwHjbM,3759
|
|
55
57
|
sgis/raster/sentinel_config.py,sha256=nySDqn2R8M6W8jguoBeSAK_zzbAsqmaI59i32446FwY,1268
|
|
56
58
|
sgis/raster/zonal.py,sha256=D4Gyptw-yOLTCO41peIuYbY-DANsJCG19xXDlf1QAz4,2299
|
|
57
|
-
ssb_sgis-1.0.
|
|
58
|
-
ssb_sgis-1.0.
|
|
59
|
-
ssb_sgis-1.0.
|
|
60
|
-
ssb_sgis-1.0.
|
|
59
|
+
ssb_sgis-1.0.15.dist-info/LICENSE,sha256=np3IfD5m0ZUofn_kVzDZqliozuiO6wrktw3LRPjyEiI,1073
|
|
60
|
+
ssb_sgis-1.0.15.dist-info/METADATA,sha256=bRaj-9WssZ9IsI2IPEtI_uyLGhpEWd52xfMst-vI3g4,11741
|
|
61
|
+
ssb_sgis-1.0.15.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
62
|
+
ssb_sgis-1.0.15.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|