diff --git a/doc/api/index.rst b/doc/api/index.rst index 07f76aff217..6c7025fd94c 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -233,6 +233,7 @@ and store them in GMT's user data directory. datasets.load_black_marble datasets.load_blue_marble datasets.load_earth_age + datasets.load_earth_dist datasets.load_earth_free_air_anomaly datasets.load_earth_geoid datasets.load_earth_magnetic_anomaly diff --git a/pygmt/datasets/__init__.py b/pygmt/datasets/__init__.py index d70eec5a1de..c557f03c466 100644 --- a/pygmt/datasets/__init__.py +++ b/pygmt/datasets/__init__.py @@ -6,6 +6,7 @@ from pygmt.datasets.earth_age import load_earth_age from pygmt.datasets.earth_day import load_blue_marble +from pygmt.datasets.earth_dist import load_earth_dist from pygmt.datasets.earth_free_air_anomaly import load_earth_free_air_anomaly from pygmt.datasets.earth_geoid import load_earth_geoid from pygmt.datasets.earth_magnetic_anomaly import load_earth_magnetic_anomaly diff --git a/pygmt/datasets/earth_dist.py b/pygmt/datasets/earth_dist.py new file mode 100644 index 00000000000..4897c475b43 --- /dev/null +++ b/pygmt/datasets/earth_dist.py @@ -0,0 +1,105 @@ +""" +Function to download the GSHHG Earth distance to shoreline dataset from the GMT data +server, and load as :class:`xarray.DataArray`. + +The grids are available in various resolutions. +""" + +from collections.abc import Sequence +from typing import Literal + +import xarray as xr +from pygmt.datasets.load_remote_dataset import _load_remote_dataset + +__doctest_skip__ = ["load_earth_dist"] + + +def load_earth_dist( + resolution: Literal[ + "01d", "30m", "20m", "15m", "10m", "06m", "05m", "04m", "03m", "02m", "01m" + ] = "01d", + region: Sequence[float] | str | None = None, + registration: Literal["gridline", "pixel"] = "gridline", +) -> xr.DataArray: + r""" + Load the GSHHG Earth distance to shoreline dataset in various resolutions. + + .. figure:: https://www.generic-mapping-tools.org/remote-datasets/_images/GMT_earth_dist.jpg + :width: 80 % + :align: center + + GSHHG Earth distance to shoreline dataset. + + The grids are downloaded to a user data directory (usually + ``~/.gmt/server/earth/earth_dist/``) the first time you invoke this function. + Afterwards, it will load the grid from the data directory. So you'll need an + internet connection the first time around. + + These grids can also be accessed by passing in the file name + **@earth_dist**\_\ *res*\[_\ *reg*] to any grid processing function or plotting + method. *res* is the grid resolution (see below), and *reg* is the grid registration + type (**p** for pixel registration or **g** for gridline registration). + + The default color palette table (CPT) for this dataset is *@earth_dist.cpt*. It's + implicitly used when passing in the file name of the dataset to any grid plotting + method if no CPT is explicitly specified. When the dataset is loaded and plotted + as an :class:`xarray.DataArray` object, the default CPT is ignored, and GMT's + default CPT (*turbo*) is used. To use the dataset-specific CPT, you need to + explicitly set ``cmap="@earth_dist.cpt"``. + + Refer to :gmt-datasets:`earth-dist.html` for more details about available datasets, + including version information and references. + + Parameters + ---------- + resolution + The grid resolution. The suffix ``d`` and ``m`` stand for arc-degrees and + arc-minutes. + region + The subregion of the grid to load, in the form of a sequence [*xmin*, *xmax*, + *ymin*, *ymax*] or an ISO country code. Required for grids with resolutions + higher than 5 arc-minutes (i.e., ``"05m"``). + registration + Grid registration type. Either ``"pixel"`` for pixel registration or + ``"gridline"`` for gridline registration. + + Returns + ------- + grid + The GSHHG Earth distance to shoreline grid. Coordinates are latitude and + longitude in degrees. Distances are in kilometers, where positive (negative) + values mean land to coastline (ocean to coastline). + + Note + ---- + The registration and coordinate system type of the returned + :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., + ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these + properties may be lost after specific grid operations (such as slicing) and will + need to be manually set before passing the grid to any PyGMT data processing or + plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed + explanations and workarounds. + + Examples + -------- + + >>> from pygmt.datasets import load_earth_dist + >>> # load the default grid (gridline-registered 1 arc-degree grid) + >>> grid = load_earth_dist() + >>> # load the 30 arc-minutes grid with "gridline" registration + >>> grid = load_earth_dist(resolution="30m", registration="gridline") + >>> # load high-resolution (5 arc-minutes) grid for a specific region + >>> grid = load_earth_dist( + ... resolution="05m", + ... region=[120, 160, 30, 60], + ... registration="gridline", + ... ) + """ + grid = _load_remote_dataset( + name="earth_dist", + prefix="earth_dist", + resolution=resolution, + region=region, + registration=registration, + ) + return grid diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index 168a93583b2..717396c145c 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -92,6 +92,24 @@ class GMTRemoteDataset(NamedTuple): "30s": Resolution("30s", registrations=["pixel"]), }, ), + "earth_dist": GMTRemoteDataset( + description="GSHHG Earth distance to shoreline", + units="km", + extra_attributes={"horizontal_datum": "WGS84"}, + resolutions={ + "01d": Resolution("01d"), + "30m": Resolution("30m"), + "20m": Resolution("20m"), + "15m": Resolution("15m"), + "10m": Resolution("10m"), + "06m": Resolution("06m"), + "05m": Resolution("05m", tiled=True), + "04m": Resolution("04m", tiled=True), + "03m": Resolution("03m", tiled=True), + "02m": Resolution("02m", tiled=True), + "01m": Resolution("01m", registrations=["gridline"], tiled=True), + }, + ), "earth_faa": GMTRemoteDataset( description="IGPP Earth free-air anomaly", units="mGal", diff --git a/pygmt/helpers/caching.py b/pygmt/helpers/caching.py index 26648b17060..183bab97161 100644 --- a/pygmt/helpers/caching.py +++ b/pygmt/helpers/caching.py @@ -14,6 +14,7 @@ def cache_data(): # List of GMT remote datasets. "@earth_age_01d_g", "@earth_day_01d", + "@earth_dist_01d", "@earth_faa_01d_g", "@earth_gebco_01d_g", "@earth_gebcosi_01d_g", @@ -45,6 +46,7 @@ def cache_data(): "@N00W030.earth_age_01m_g.nc", "@N30E060.earth_age_01m_g.nc", "@N30E090.earth_age_01m_g.nc", + "@N00W030.earth_dist_01m_g.nc", "@N00W030.earth_faa_01m_p.nc", "@N00W030.earth_geoid_01m_g.nc", "@S30W060.earth_mag_02m_p.nc", diff --git a/pygmt/tests/test_datasets_earth_dist.py b/pygmt/tests/test_datasets_earth_dist.py new file mode 100644 index 00000000000..e0d91d77a84 --- /dev/null +++ b/pygmt/tests/test_datasets_earth_dist.py @@ -0,0 +1,53 @@ +""" +Test basic functionality for loading Earth distance to shoreline datasets. +""" + +import numpy as np +import numpy.testing as npt +from pygmt.datasets import load_earth_dist + + +def test_earth_dist_01d(): + """ + Test some properties of the Earth distance to shoreline 01d data. + """ + data = load_earth_dist(resolution="01d") + assert data.name == "z" + assert data.attrs["description"] == "GSHHG Earth distance to shoreline" + assert data.attrs["units"] == "km" + assert data.attrs["horizontal_datum"] == "WGS84" + assert data.shape == (181, 361) + assert data.gmt.registration == 0 + npt.assert_allclose(data.lat, np.arange(-90, 91, 1)) + npt.assert_allclose(data.lon, np.arange(-180, 181, 1)) + npt.assert_allclose(data.min(), -2655.7, atol=0.01) + npt.assert_allclose(data.max(), 2463.42, atol=0.01) + + +def test_earth_dist_01d_with_region(): + """ + Test loading low-resolution Earth distance to shoreline with "region". + """ + data = load_earth_dist(resolution="01d", region=[-10, 10, -5, 5]) + assert data.shape == (11, 21) + assert data.gmt.registration == 0 + npt.assert_allclose(data.lat, np.arange(-5, 6, 1)) + npt.assert_allclose(data.lon, np.arange(-10, 11, 1)) + npt.assert_allclose(data.min(), -1081.94, atol=0.01) + npt.assert_allclose(data.max(), 105.18, atol=0.01) + + +def test_earth_dist_01m_default_registration(): + """ + Test that the grid returned by default for the 1 arc-minute resolution has a + "gridline" registration. + """ + data = load_earth_dist(resolution="01m", region=[-10, -9, 3, 5]) + assert data.shape == (121, 61) + assert data.gmt.registration == 0 + assert data.coords["lat"].data.min() == 3.0 + assert data.coords["lat"].data.max() == 5.0 + assert data.coords["lon"].data.min() == -10.0 + assert data.coords["lon"].data.max() == -9.0 + npt.assert_allclose(data.min(), -243.62, atol=0.01) + npt.assert_allclose(data.max(), 2.94, atol=0.01)