diff --git a/pygmt/datasets/tile_map.py b/pygmt/datasets/tile_map.py index 31f1b52cb1c..7e690dfb65e 100644 --- a/pygmt/datasets/tile_map.py +++ b/pygmt/datasets/tile_map.py @@ -2,6 +2,9 @@ Function to load raster tile maps from XYZ tile providers, and load as :class:`xarray.DataArray`. """ +from __future__ import annotations + +from packaging.version import Version try: import contextily @@ -16,7 +19,15 @@ __doctest_requires__ = {("load_tile_map"): ["contextily"]} -def load_tile_map(region, zoom="auto", source=None, lonlat=True, wait=0, max_retries=2): +def load_tile_map( + region, + zoom="auto", + source=None, + lonlat=True, + wait=0, + max_retries=2, + zoom_adjust: int | None = None, +): """ Load a georeferenced raster tile map from XYZ tile providers. @@ -40,9 +51,9 @@ def load_tile_map(region, zoom="auto", source=None, lonlat=True, wait=0, max_ret ``"auto"`` to automatically determine the zoom level based on the bounding box region extent]. - **Note**: The maximum possible zoom level may be smaller than ``22``, - and depends on what is supported by the chosen web tile provider - source. + .. note:: + The maximum possible zoom level may be smaller than ``22``, and depends on + what is supported by the chosen web tile provider source. source : xyzservices.TileProvider or str Optional. The tile source: web tile provider or path to a local file. @@ -62,8 +73,8 @@ def load_tile_map(region, zoom="auto", source=None, lonlat=True, wait=0, max_ret basemap. See :doc:`contextily:working_with_local_files`. - IMPORTANT: Tiles are assumed to be in the Spherical Mercator projection - (EPSG:3857). + .. important:: + Tiles are assumed to be in the Spherical Mercator projection (EPSG:3857). lonlat : bool Optional. If ``False``, coordinates in ``region`` are assumed to be @@ -79,6 +90,13 @@ def load_tile_map(region, zoom="auto", source=None, lonlat=True, wait=0, max_ret will stop trying to fetch more tiles from a rate-limited API [Default is ``2``]. + zoom_adjust + The amount to adjust a chosen zoom level if it is chosen automatically. Values + outside of -1 to 1 are not recommended as they can lead to slow execution. + + .. note:: + The ``zoom_adjust`` parameter requires ``contextily>=1.5.0``. + Returns ------- raster : xarray.DataArray @@ -117,6 +135,15 @@ def load_tile_map(region, zoom="auto", source=None, lonlat=True, wait=0, max_ret "to install the package." ) + contextily_kwargs = {} + if zoom_adjust is not None: + contextily_kwargs["zoom_adjust"] = zoom_adjust + if Version(contextily.__version__) < Version("1.5.0"): + raise TypeError( + "The `zoom_adjust` parameter requires `contextily>=1.5.0` to work. " + "Please upgrade contextily, or manually set the `zoom` level instead." + ) + west, east, south, north = region image, extent = contextily.bounds2img( w=west, @@ -128,6 +155,7 @@ def load_tile_map(region, zoom="auto", source=None, lonlat=True, wait=0, max_ret ll=lonlat, wait=wait, max_retries=max_retries, + **contextily_kwargs, ) # Turn RGBA img from channel-last to channel-first and get 3-band RGB only @@ -139,7 +167,7 @@ def load_tile_map(region, zoom="auto", source=None, lonlat=True, wait=0, max_ret dataarray = xr.DataArray( data=rgb_image, coords={ - "band": np.uint8([0, 1, 2]), # Red, Green, Blue + "band": np.array(object=[0, 1, 2], dtype=np.uint8), # Red, Green, Blue "y": np.linspace(start=top, stop=bottom, num=rgb_image.shape[1]), "x": np.linspace(start=left, stop=right, num=rgb_image.shape[2]), }, diff --git a/pygmt/src/tilemap.py b/pygmt/src/tilemap.py index 89c0bbf468b..80fe5e44f16 100644 --- a/pygmt/src/tilemap.py +++ b/pygmt/src/tilemap.py @@ -1,6 +1,8 @@ """ tilemap - Plot XYZ tile maps. """ +from __future__ import annotations + from pygmt.clib import Session from pygmt.datasets.tile_map import load_tile_map from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias @@ -30,7 +32,15 @@ ) @kwargs_to_strings(c="sequence_comma", p="sequence") # R="sequence", def tilemap( - self, region, zoom="auto", source=None, lonlat=True, wait=0, max_retries=2, **kwargs + self, + region, + zoom="auto", + source=None, + lonlat=True, + wait=0, + max_retries=2, + zoom_adjust: int | None = None, + **kwargs, ): r""" Plots an XYZ tile map. @@ -64,9 +74,9 @@ def tilemap( ``"auto"`` to automatically determine the zoom level based on the bounding box region extent]. - **Note**: The maximum possible zoom level may be smaller than ``22``, - and depends on what is supported by the chosen web tile provider - source. + .. note:: + The maximum possible zoom level may be smaller than ``22``, and depends on + what is supported by the chosen web tile provider source. source : xyzservices.TileProvider or str Optional. The tile source: web tile provider or path to a local file. @@ -86,8 +96,8 @@ def tilemap( basemap. See :doc:`contextily:working_with_local_files`. - IMPORTANT: Tiles are assumed to be in the Spherical Mercator projection - (EPSG:3857). + .. important:: + Tiles are assumed to be in the Spherical Mercator projection (EPSG:3857). lonlat : bool Optional. If ``False``, coordinates in ``region`` are assumed to be @@ -103,6 +113,13 @@ def tilemap( will stop trying to fetch more tiles from a rate-limited API [Default is ``2``]. + zoom_adjust + The amount to adjust a chosen zoom level if it is chosen automatically. Values + outside of -1 to 1 are not recommended as they can lead to slow execution. + + .. note:: + The ``zoom_adjust`` parameter requires ``contextily>=1.5.0``. + kwargs : dict Extra keyword arguments to pass to :meth:`pygmt.Figure.grdimage`. @@ -131,6 +148,7 @@ def tilemap( lonlat=lonlat, wait=wait, max_retries=max_retries, + zoom_adjust=zoom_adjust, ) # Reproject raster from Spherical Mercator (EPSG:3857) to