diff --git a/pyproject.toml b/pyproject.toml index 42a1caff..0a48ca5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ssb-sgis" -version = "1.0.14" +version = "1.0.15" description = "GIS functions used at Statistics Norway." authors = ["Morten Letnes "] license = "MIT" diff --git a/src/sgis/__init__.py b/src/sgis/__init__.py index fd10bc0f..e6cd6ad0 100644 --- a/src/sgis/__init__.py +++ b/src/sgis/__init__.py @@ -96,10 +96,10 @@ from .maps.maps import explore_locals from .maps.maps import qtm from .maps.maps import samplemap -from .maps.norge_i_bilder_wms import NorgeIBilderWms from .maps.thematicmap import ThematicMap from .maps.tilesources import kartverket as kartverket_tiles from .maps.tilesources import xyz as xyztiles +from .maps.wms import NorgeIBilderWms from .networkanalysis.closing_network_holes import close_network_holes from .networkanalysis.closing_network_holes import close_network_holes_to_deadends from .networkanalysis.closing_network_holes import get_k_nearest_points_for_deadends diff --git a/src/sgis/maps/explore.py b/src/sgis/maps/explore.py index cc848699..0b71bedd 100644 --- a/src/sgis/maps/explore.py +++ b/src/sgis/maps/explore.py @@ -44,7 +44,7 @@ from ..geopandas_tools.general import make_all_singlepart from ..geopandas_tools.geometry_types import get_geom_type from ..geopandas_tools.geometry_types import to_single_geom_type -from .norge_i_bilder_wms import NorgeIBilderWms +from .wms import WmsLoader try: from ..raster.image_collection import Band @@ -280,7 +280,7 @@ def __init__( max_images: int = 10, max_nodata_percentage: int = 100, display: bool = True, - norge_i_bilder: bool = False, + wms: WmsLoader | None = None, **kwargs, ) -> None: """Initialiser. @@ -310,9 +310,7 @@ def __init__( max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in image arrays. display: Whether to display the map interactively. - norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded - into the map. Can optionally be set to an instance of NorgeIBilderWms to filter - years and names. + wms: A WmsLoader instance for loading image tiles as layers. E.g. NorgeIBilderWms. **kwargs: Additional keyword arguments. Can also be geometry-like objects where the key is the label. """ @@ -329,7 +327,7 @@ def __init__( self.max_images = max_images self.max_nodata_percentage = max_nodata_percentage self.display = display - self.norge_i_bilder = norge_i_bilder + self.wms = [wms] if isinstance(wms, WmsLoader) else wms self.legend = None self.browser = browser @@ -768,13 +766,11 @@ def _add_tiles( for tile in tiles: to_tile(tile, max_zoom=self.max_zoom).add_to(mapobj) - def _add_norge_i_bilder(self, map_: folium.Map, bbox: Any) -> None: - if not isinstance(self.norge_i_bilder, NorgeIBilderWms): - self.norge_i_bilder = NorgeIBilderWms() - - tiles = self.norge_i_bilder.get_tiles(bbox, max_zoom=self.max_zoom) - for tile in tiles.values(): - map_.add_child(tile) + def _add_wms(self, map_: folium.Map, bbox: Any) -> None: + for wms in self.wms: + tiles = wms.get_tiles(bbox, max_zoom=self.max_zoom) + for tile in tiles.values(): + map_.add_child(tile) def _create_continous_map(self): self._prepare_continous_map() @@ -982,8 +978,8 @@ def _make_folium_map( m.get_root().add_child(style) # folium.LayerControl(collapsed=False).add_to(m) - if self.norge_i_bilder: - self._add_norge_i_bilder(m, bounds) + if self.wms: + self._add_wms(m, bounds) return m diff --git a/src/sgis/maps/maps.py b/src/sgis/maps/maps.py index db352d51..a6502c50 100644 --- a/src/sgis/maps/maps.py +++ b/src/sgis/maps/maps.py @@ -31,8 +31,8 @@ from ..geopandas_tools.geometry_types import get_geom_type from .explore import Explore from .map import Map -from .norge_i_bilder_wms import NorgeIBilderWms from .thematicmap import ThematicMap +from .wms import WmsLoader try: from torchgeo.datasets.geo import RasterDataset @@ -91,7 +91,7 @@ def explore( size: int | None = None, max_images: int = 10, max_nodata_percentage: int = 100, - norge_i_bilder: bool | NorgeIBilderWms = False, + wms: WmsLoader | None = None, **kwargs, ) -> Explore: """Interactive map of GeoDataFrames with layers that can be toggled on/off. @@ -123,9 +123,7 @@ def explore( map. Defaults to 10. max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in image arrays. - norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded - into the map. Can optionally be set to an instance of NorgeIBilderWms to filter - years and names. + wms: A WmsLoader instance for loading image tiles as layers. E.g. NorgeIBilderWms. **kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for instance 'cmap' to change the colors, 'scheme' to change how the data is grouped. This defaults to 'fisherjenkssampled' for numeric data. @@ -175,7 +173,7 @@ def explore( max_zoom=max_zoom, max_images=max_images, max_nodata_percentage=max_nodata_percentage, - norge_i_bilder=norge_i_bilder, + wms=wms, **kwargs, ) @@ -233,7 +231,7 @@ def explore( max_zoom=max_zoom, max_images=max_images, max_nodata_percentage=max_nodata_percentage, - norge_i_bilder=norge_i_bilder, + wms=wms, **kwargs, ) @@ -245,7 +243,7 @@ def explore( smooth_factor=smooth_factor, max_images=max_images, max_nodata_percentage=max_nodata_percentage, - norge_i_bilder=norge_i_bilder, + wms=wms, **kwargs, ) @@ -271,7 +269,7 @@ def samplemap( browser: bool = False, max_images: int = 10, max_nodata_percentage: int = 100, - norge_i_bilder: bool | NorgeIBilderWms = False, + wms: WmsLoader | None = None, **kwargs, ) -> Explore: """Shows an interactive map of a random area of GeoDataFrames. @@ -307,9 +305,7 @@ def samplemap( map. Defaults to 10. max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in image arrays. - norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded - into the map. Can optionally be set to an instance of NorgeIBilderWms to filter - years and names. + wms: A WmsLoader instance for loading image tiles as layers. E.g. NorgeIBilderWms. **kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for instance 'cmap' to change the colors, 'scheme' to change how the data is grouped. This defaults to 'fisherjenkssampled' for numeric data. @@ -393,7 +389,7 @@ def samplemap( smooth_factor=smooth_factor, max_images=max_images, max_nodata_percentage=max_nodata_percentage, - norge_i_bilder=norge_i_bilder, + wms=wms, **kwargs, ) @@ -408,7 +404,7 @@ def clipmap( browser: bool = False, max_images: int = 10, max_nodata_percentage: int = 100, - norge_i_bilder: bool | NorgeIBilderWms = False, + wms: WmsLoader | None = None, **kwargs, ) -> Explore | Map: """Shows an interactive map of a of GeoDataFrames clipped to the mask extent. @@ -439,9 +435,7 @@ def clipmap( map. Defaults to 10. max_nodata_percentage: Maximum percentage nodata values (e.g. clouds) ro allow in image arrays. - norge_i_bilder: If True, all Norge i bilder images in bounds will be loaded - into the map. Can optionally be set to an instance of NorgeIBilderWms to filter - years and names. + wms: A WmsLoader instance for loading image tiles as layers. E.g. NorgeIBilderWms. **kwargs: Keyword arguments to pass to geopandas.GeoDataFrame.explore, for instance 'cmap' to change the colors, 'scheme' to change how the data is grouped. This defaults to 'fisherjenkssampled' for numeric data. @@ -477,7 +471,7 @@ def clipmap( smooth_factor=smooth_factor, max_images=max_images, max_nodata_percentage=max_nodata_percentage, - norge_i_bilder=norge_i_bilder, + wms=wms, **kwargs, ) m.mask = mask diff --git a/src/sgis/maps/norge_i_bilder_wms.py b/src/sgis/maps/wms.py similarity index 90% rename from src/sgis/maps/norge_i_bilder_wms.py rename to src/sgis/maps/wms.py index 3c4aa736..9833ae9f 100644 --- a/src/sgis/maps/norge_i_bilder_wms.py +++ b/src/sgis/maps/wms.py @@ -1,3 +1,4 @@ +import abc import datetime import json import re @@ -24,7 +25,28 @@ @dataclass -class NorgeIBilderWms: +class WmsLoader(abc.ABC): + """Abstract base class for wms loaders. + + Child classes must implement the method 'get_tiles', + which should return a list of folium.WmsTileLayer. + """ + + @abc.abstractmethod + def get_tiles(self, bbox: Any, max_zoom: int = 40) -> list[folium.WmsTileLayer]: + """Get all tiles intersecting with a bbox.""" + + @abc.abstractmethod + def load_tiles(self) -> None: + """Load all tiles into self.tiles. + + Not needed in sgis.explore. + """ + pass + + +@dataclass +class NorgeIBilderWms(WmsLoader): """Loads Norge i bilder tiles as folium.WmsTiles.""" years: Iterable[int | str] = DEFAULT_YEARS diff --git a/tests/test_explore.py b/tests/test_explore.py index 5c1b1a93..46d0a90d 100644 --- a/tests/test_explore.py +++ b/tests/test_explore.py @@ -126,20 +126,9 @@ def test_explore(points_oslo, roads_oslo): "meters", r100, bygdoy=7000, - norge_i_bilder=True, - tiles=["openstreetmap"], + wms=sg.NorgeIBilderWms(years=[2022, 2023, 2024], not_contains="sentinel"), ) - assert isinstance(e.norge_i_bilder, sg.NorgeIBilderWms) - e = sg.explore( - r300, - "meters", - r100, - bygdoy=7000, - norge_i_bilder=sg.NorgeIBilderWms( - years=[2022, 2023, 2024], not_contains="sentinel" - ), - ) - assert isinstance(e.norge_i_bilder, sg.NorgeIBilderWms) + assert isinstance(next(iter(e.wms)), sg.NorgeIBilderWms) inner_test_center(r300, r200, r100, p)