diff --git a/doc/api/index.rst b/doc/api/index.rst index 035f1df87d9..68b8aed08ae 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -222,6 +222,7 @@ and store them in GMT's user data directory. datasets.list_sample_data datasets.load_earth_age + datasets.load_earth_magnetic_anomaly datasets.load_earth_relief datasets.load_sample_data diff --git a/pygmt/datasets/__init__.py b/pygmt/datasets/__init__.py index 93b7210a73e..25f29b67af5 100644 --- a/pygmt/datasets/__init__.py +++ b/pygmt/datasets/__init__.py @@ -3,6 +3,7 @@ # Load sample data included with GMT (downloaded from the GMT cache server). from pygmt.datasets.earth_age import load_earth_age +from pygmt.datasets.earth_magnetic_anomaly import load_earth_magnetic_anomaly from pygmt.datasets.earth_relief import load_earth_relief from pygmt.datasets.samples import ( list_sample_data, diff --git a/pygmt/datasets/earth_magnetic_anomaly.py b/pygmt/datasets/earth_magnetic_anomaly.py new file mode 100644 index 00000000000..117682f5f32 --- /dev/null +++ b/pygmt/datasets/earth_magnetic_anomaly.py @@ -0,0 +1,69 @@ +""" +Function to download the Earth magnetic anomaly datasets from the GMT data +server, and load as :class:`xarray.DataArray`. + +The grids are available in various resolutions. +""" +from pygmt.datasets.load_remote_dataset import _load_remote_dataset +from pygmt.helpers import kwargs_to_strings + + +@kwargs_to_strings(region="sequence") +def load_earth_magnetic_anomaly(resolution="01d", region=None, registration=None): + r""" + Load an Earth magnetic anomaly grid in various resolutions. + + The grids are downloaded to a user data directory + (usually ``~/.gmt/server/earth/earth_mag/``) 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_mag**\_\ *res*\[_\ *reg*] to any grid plotting/processing + function. *res* is the grid resolution (see below), and *reg* is grid + registration type (**p** for pixel registration or **g** for gridline + registration). + + Refer to :gmt-datasets:`earth-mag.html` for more details. + + Parameters + ---------- + resolution : str + The grid resolution. The suffix ``d`` and ``m`` stand for + arc-degree and arc-minute. It can be ``"01d"``, ``"30m"``, + ``"20m"``, ``"15m"``, ``"10m"``, ``"06m"``, ``"05m"``, ``"04m"``, + ``"03m"``, or ``"02m"``. + + region : str or list + The subregion of the grid to load, in the forms of a list + [*xmin*, *xmax*, *ymin*, *ymax*] or a string *xmin/xmax/ymin/ymax*. + Required for grids with resolutions higher than 5 + arc-minute (i.e., ``"05m"``). + + registration : str + Grid registration type. Either ``"pixel"`` for pixel registration or + ``"gridline"`` for gridline registration. Default is ``None``, where + a pixel-registered grid is returned unless only the + gridline-registered grid is available. + + Returns + ------- + grid : :class:`xarray.DataArray` + The Earth magnetic anomaly grid. Coordinates are latitude and + longitude in degrees. Units are in nano Teslas (nT). + + Note + ---- + The :class:`xarray.DataArray` grid doesn't support slice operation, for + Earth magnetic anomaly with resolutions of 5 arc-minutes or higher, + which are stored as smaller tiles. + """ + dataset_prefix = "earth_mag_" + grid = _load_remote_dataset( + dataset_name="earth_magnetic_anomaly", + dataset_prefix=dataset_prefix, + 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 a60ccb85423..309bc324542 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -108,6 +108,25 @@ class GMTRemoteDataset(NamedTuple): "01m": Resolution(["gridline"], True), }, ), + "earth_magnetic_anomaly": GMTRemoteDataset( + title="Earth magnetic anomaly", + name="magnetic_anomaly", + long_name="Earth magnetic anomaly", + units="nT", + extra_attributes={"horizontal_datum": "WGS84"}, + resolutions={ + "01d": Resolution(["pixel", "gridline"], False), + "30m": Resolution(["pixel", "gridline"], False), + "20m": Resolution(["pixel", "gridline"], False), + "15m": Resolution(["pixel", "gridline"], False), + "10m": Resolution(["pixel", "gridline"], False), + "06m": Resolution(["pixel", "gridline"], False), + "05m": Resolution(["pixel", "gridline"], True), + "04m": Resolution(["pixel", "gridline"], True), + "03m": Resolution(["pixel", "gridline"], True), + "02m": Resolution(["pixel"], True), + }, + ), } diff --git a/pygmt/helpers/testing.py b/pygmt/helpers/testing.py index 57c916f5f83..29d1e5f1f8b 100644 --- a/pygmt/helpers/testing.py +++ b/pygmt/helpers/testing.py @@ -180,6 +180,9 @@ def download_test_data(): # Earth seafloor age grids "@earth_age_01d_g", "@S90W180.earth_age_05m_g.nc", # Specific grid for 05m test + # Earth magnetic anomaly grids + "@earth_mag_01d_g.grd" + "@S90W180.earth_mag_05m_g.nc" # Specific grid for 05m test # Other cache files "@capitals.gmt", "@earth_relief_20m_holes.grd", diff --git a/pygmt/tests/test_datasets_earth_magnetic_anomaly.py b/pygmt/tests/test_datasets_earth_magnetic_anomaly.py new file mode 100644 index 00000000000..8a2d35567d3 --- /dev/null +++ b/pygmt/tests/test_datasets_earth_magnetic_anomaly.py @@ -0,0 +1,82 @@ +""" +Test basic functionality for loading Earth magnetic anomaly datasets. +""" +import numpy as np +import numpy.testing as npt +import pytest +from pygmt.datasets import load_earth_magnetic_anomaly +from pygmt.exceptions import GMTInvalidInput + + +def test_earth_mag_fails(): + """ + Make sure earth_magnetic_anomaly fails for invalid resolutions. + """ + resolutions = "1m 1d bla 60d 001m 03".split() + resolutions.append(60) + for resolution in resolutions: + with pytest.raises(GMTInvalidInput): + load_earth_magnetic_anomaly(resolution=resolution) + + +def test_earth_mag_incorrect_registration(): + """ + Test loading earth_magnetic_anomaly with incorrect registration type. + """ + with pytest.raises(GMTInvalidInput): + load_earth_magnetic_anomaly(registration="improper_type") + + +def test_earth_mag_01d(): + """ + Test some properties of the magnetic anomaly 01d data. + """ + data = load_earth_magnetic_anomaly(resolution="01d", registration="gridline") + assert data.name == "magnetic_anomaly" + assert data.attrs["long_name"] == "Earth magnetic anomaly" + assert data.attrs["units"] == "nT" + assert data.attrs["horizontal_datum"] == "WGS84" + assert data.shape == (181, 361) + 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(), -384) + npt.assert_allclose(data.max(), 1057.2) + + +def test_earth_mag_01d_with_region(): + """ + Test loading low-resolution earth magnetic anomaly with 'region'. + """ + data = load_earth_magnetic_anomaly( + resolution="01d", region=[-10, 10, -5, 5], registration="gridline" + ) + assert data.shape == (11, 21) + 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(), -180.40002) + npt.assert_allclose(data.max(), 127.39996) + + +def test_earth_mag_05m_with_region(): + """ + Test loading a subregion of high-resolution earth magnetic anomaly data. + """ + data = load_earth_magnetic_anomaly( + resolution="05m", region=[-115, -112, 4, 6], registration="gridline" + ) + assert data.shape == (25, 37) + assert data.lat.min() == 4 + assert data.lat.max() == 6 + assert data.lon.min() == -115 + assert data.lon.max() == -112 + npt.assert_allclose(data.min(), -189.20001) + npt.assert_allclose(data.max(), 107) + + +def test_earth_mag_05m_without_region(): + """ + Test loading high-resolution earth magnetic anomaly without passing + 'region'. + """ + with pytest.raises(GMTInvalidInput): + load_earth_magnetic_anomaly("05m")