From 351b96f4a6f3c4f53bca9e7a2a90b3e9d3e3cc83 Mon Sep 17 00:00:00 2001 From: yvonnefroelich Date: Wed, 25 Dec 2024 12:56:50 +0100 Subject: [PATCH 1/8] Add Earth mean sea surface dataset --- doc/api/index.rst | 1 + pygmt/datasets/__init__.py | 1 + pygmt/datasets/load_remote_dataset.py | 18 ++++++++++++++++++ pygmt/helpers/caching.py | 2 ++ 4 files changed, 22 insertions(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 07f76aff217..9089bfe4499 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -237,6 +237,7 @@ and store them in GMT's user data directory. datasets.load_earth_geoid datasets.load_earth_magnetic_anomaly datasets.load_earth_mask + datasets.load_earth_mean_sea_surface datasets.load_earth_relief datasets.load_earth_vertical_gravity_gradient datasets.load_mars_relief diff --git a/pygmt/datasets/__init__.py b/pygmt/datasets/__init__.py index d70eec5a1de..8a297de334d 100644 --- a/pygmt/datasets/__init__.py +++ b/pygmt/datasets/__init__.py @@ -10,6 +10,7 @@ from pygmt.datasets.earth_geoid import load_earth_geoid from pygmt.datasets.earth_magnetic_anomaly import load_earth_magnetic_anomaly from pygmt.datasets.earth_mask import load_earth_mask +from pygmt.datasets.earth_mean_sea_surface import load_earth_mean_sea_surface from pygmt.datasets.earth_night import load_black_marble from pygmt.datasets.earth_relief import load_earth_relief from pygmt.datasets.earth_vertical_gravity_gradient import ( diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index 168a93583b2..e6eb504e8c2 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -209,6 +209,24 @@ class GMTRemoteDataset(NamedTuple): "15s": Resolution("15s"), }, ), + "earth_mss": GMTRemoteDataset( + description="CNES Earth Mean Sea Surface", + units="m", + 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"), + "04m": Resolution("04m"), + "03m": Resolution("03m"), + "02m": Resolution("02m"), + "01m": Resolution("01m", registrations=["gridline"]), + }, + ), "earth_night": GMTRemoteDataset( description="NASA Night Images", units=None, diff --git a/pygmt/helpers/caching.py b/pygmt/helpers/caching.py index 26648b17060..7bc9cc67da4 100644 --- a/pygmt/helpers/caching.py +++ b/pygmt/helpers/caching.py @@ -22,6 +22,7 @@ def cache_data(): "@earth_mag_01d_g", "@earth_mag4km_01d_g", "@earth_mask_01d_g", + "@earth_mss_01_g", "@earth_night_01d", "@earth_relief_01d_g", "@earth_relief_01d_p", @@ -49,6 +50,7 @@ def cache_data(): "@N00W030.earth_geoid_01m_g.nc", "@S30W060.earth_mag_02m_p.nc", "@S30W120.earth_mag4km_02m_p.nc", + "@N30E090.earth_mss_01m_g.nc", "@N00W090.earth_relief_03m_p.nc", "@N00E135.earth_relief_30s_g.nc", "@N00W010.earth_relief_15s_p.nc", From 3b8da79c1d5eea19472408b019ecd8c177f208f5 Mon Sep 17 00:00:00 2001 From: yvonnefroelich Date: Wed, 25 Dec 2024 13:23:19 +0100 Subject: [PATCH 2/8] Add function 'earth_mean_sea_surface.py' --- pygmt/datasets/earth_mean_sea_surface.py | 104 +++++++++++++++++++++++ pygmt/datasets/load_remote_dataset.py | 4 +- 2 files changed, 106 insertions(+), 2 deletions(-) create mode 100755 pygmt/datasets/earth_mean_sea_surface.py diff --git a/pygmt/datasets/earth_mean_sea_surface.py b/pygmt/datasets/earth_mean_sea_surface.py new file mode 100755 index 00000000000..1edc7513c42 --- /dev/null +++ b/pygmt/datasets/earth_mean_sea_surface.py @@ -0,0 +1,104 @@ +""" +Function to download the CNES Earth mean sea surface 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_mean_sea_surface"] + + +def load_earth_mean_sea_surface( + 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 CNES Earth mean sea surface dataset in various resolutions. + + .. figure:: https://www.generic-mapping-tools.org/remote-datasets/_images/GMT_earth_mss.jpg + :width: 80 % + :align: center + + CNES Earth mean sea surface dataset. + + The grids are downloaded to a user data directory (usually + ``~/.gmt/server/earth/earth_mss/``) 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_mss**\_\ *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_mss.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_mss.cpt"``. + + Refer to :gmt-datasets:`earth-mss.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 CNES Earth mean sea surface grid. Coordinates are latitude and + longitude in degrees. Values are in meters. + + 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_mean_sea_surface + >>> # load the default grid (gridline-registered 1 arc-degree grid) + >>> grid = load_earth_mean_sea_surface() + >>> # load the 30 arc-minutes grid with "gridline" registration + >>> grid = load_earth_mean_sea_surface(resolution="30m", registration="gridline") + >>> # load high-resolution (5 arc-minutes) grid for a specific region + >>> grid = load_earth_mean_sea_surface( + ... resolution="05m", + ... region=[120, 160, 30, 60], + ... registration="gridline", + ... ) + """ + grid = _load_remote_dataset( + name="earth_mean_sea_surface", + prefix="earth_mean_sea_surface", + 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 e6eb504e8c2..74d23e8acda 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -210,8 +210,8 @@ class GMTRemoteDataset(NamedTuple): }, ), "earth_mss": GMTRemoteDataset( - description="CNES Earth Mean Sea Surface", - units="m", + description="CNES Earth mean sea surface", + units="meters", extra_attributes={"horizontal_datum": "WGS84"}, resolutions={ "01d": Resolution("01d"), From a7f4e533a2c8b142fe19df55deb6a925129a3f79 Mon Sep 17 00:00:00 2001 From: yvonnefroelich Date: Wed, 25 Dec 2024 13:45:15 +0100 Subject: [PATCH 3/8] Add tests 'test_datasets_earth_mean_sea_surface.py' --- pygmt/datasets/earth_mean_sea_surface.py | 4 +- pygmt/datasets/load_remote_dataset.py | 2 +- .../test_datasets_earth_mean_sea_surface.py | 53 +++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100755 pygmt/tests/test_datasets_earth_mean_sea_surface.py diff --git a/pygmt/datasets/earth_mean_sea_surface.py b/pygmt/datasets/earth_mean_sea_surface.py index 1edc7513c42..f4856d98626 100755 --- a/pygmt/datasets/earth_mean_sea_surface.py +++ b/pygmt/datasets/earth_mean_sea_surface.py @@ -95,8 +95,8 @@ def load_earth_mean_sea_surface( ... ) """ grid = _load_remote_dataset( - name="earth_mean_sea_surface", - prefix="earth_mean_sea_surface", + name="earth_mss", + prefix="earth_mss", resolution=resolution, region=region, registration=registration, diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index 74d23e8acda..b552b2bdfc7 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -211,7 +211,7 @@ class GMTRemoteDataset(NamedTuple): ), "earth_mss": GMTRemoteDataset( description="CNES Earth mean sea surface", - units="meters", + units="m", extra_attributes={"horizontal_datum": "WGS84"}, resolutions={ "01d": Resolution("01d"), diff --git a/pygmt/tests/test_datasets_earth_mean_sea_surface.py b/pygmt/tests/test_datasets_earth_mean_sea_surface.py new file mode 100755 index 00000000000..bf00711658b --- /dev/null +++ b/pygmt/tests/test_datasets_earth_mean_sea_surface.py @@ -0,0 +1,53 @@ +""" +Test basic functionality for loading Earth mean sea surface datasets. +""" + +import numpy as np +import numpy.testing as npt +from pygmt.datasets import load_earth_mean_sea_surface + + +def test_earth_mss_01d(): + """ + Test some properties of the Earth mean sea surface 01d data. + """ + data = load_earth_mean_sea_surface(resolution="01d") + assert data.name == "z" + assert data.attrs["description"] == "CNES Earth mean sea surface" + assert data.attrs["units"] == "m" + 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_mss_01d_with_region(): + """ + Test loading low-resolution Earth mean sea surface with "region". + """ + data = load_earth_mean_sea_surface(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_mss_01m_default_registration(): + """ + Test that the grid returned by default for the 1 arc-minute resolution has a + "gridline" registration. + """ + data = load_earth_mean_sea_surface(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) From 14c34ce7b3098e141dc10e06b9b276ce992a80b5 Mon Sep 17 00:00:00 2001 From: yvonnefroelich Date: Wed, 25 Dec 2024 14:22:47 +0100 Subject: [PATCH 4/8] Adjust minimum values for tests | Remove execution persmission | Use 'meters' as unit --- pygmt/datasets/load_remote_dataset.py | 2 +- pygmt/tests/test_datasets_earth_mean_sea_surface.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) mode change 100755 => 100644 pygmt/tests/test_datasets_earth_mean_sea_surface.py diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index b552b2bdfc7..74d23e8acda 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -211,7 +211,7 @@ class GMTRemoteDataset(NamedTuple): ), "earth_mss": GMTRemoteDataset( description="CNES Earth mean sea surface", - units="m", + units="meters", extra_attributes={"horizontal_datum": "WGS84"}, resolutions={ "01d": Resolution("01d"), diff --git a/pygmt/tests/test_datasets_earth_mean_sea_surface.py b/pygmt/tests/test_datasets_earth_mean_sea_surface.py old mode 100755 new mode 100644 index bf00711658b..8d1b6388983 --- a/pygmt/tests/test_datasets_earth_mean_sea_surface.py +++ b/pygmt/tests/test_datasets_earth_mean_sea_surface.py @@ -14,13 +14,13 @@ def test_earth_mss_01d(): data = load_earth_mean_sea_surface(resolution="01d") assert data.name == "z" assert data.attrs["description"] == "CNES Earth mean sea surface" - assert data.attrs["units"] == "m" + assert data.attrs["units"] == "meters" 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.min(), -104.71, atol=0.01) npt.assert_allclose(data.max(), 2463.42, atol=0.01) @@ -33,7 +33,7 @@ def test_earth_mss_01d_with_region(): 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.min(), 6.53, atol=0.01) npt.assert_allclose(data.max(), 105.18, atol=0.01) @@ -49,5 +49,5 @@ def test_earth_mss_01m_default_registration(): 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.min(), 21.27, atol=0.01) npt.assert_allclose(data.max(), 2.94, atol=0.01) From efcc6c81d513183078e83b5e63445aab1f409101 Mon Sep 17 00:00:00 2001 From: yvonnefroelich Date: Wed, 25 Dec 2024 14:32:56 +0100 Subject: [PATCH 5/8] Adjust maximum values for tests | Remove execution persmission --- pygmt/datasets/earth_mean_sea_surface.py | 0 pygmt/tests/test_datasets_earth_mean_sea_surface.py | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) mode change 100755 => 100644 pygmt/datasets/earth_mean_sea_surface.py diff --git a/pygmt/datasets/earth_mean_sea_surface.py b/pygmt/datasets/earth_mean_sea_surface.py old mode 100755 new mode 100644 diff --git a/pygmt/tests/test_datasets_earth_mean_sea_surface.py b/pygmt/tests/test_datasets_earth_mean_sea_surface.py index 8d1b6388983..425bece85c8 100644 --- a/pygmt/tests/test_datasets_earth_mean_sea_surface.py +++ b/pygmt/tests/test_datasets_earth_mean_sea_surface.py @@ -21,7 +21,7 @@ def test_earth_mss_01d(): 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(), -104.71, atol=0.01) - npt.assert_allclose(data.max(), 2463.42, atol=0.01) + npt.assert_allclose(data.max(), 82.38, atol=0.01) def test_earth_mss_01d_with_region(): @@ -34,7 +34,7 @@ def test_earth_mss_01d_with_region(): 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(), 6.53, atol=0.01) - npt.assert_allclose(data.max(), 105.18, atol=0.01) + npt.assert_allclose(data.max(), 29.31, atol=0.01) def test_earth_mss_01m_default_registration(): @@ -50,4 +50,4 @@ def test_earth_mss_01m_default_registration(): assert data.coords["lon"].data.min() == -10.0 assert data.coords["lon"].data.max() == -9.0 npt.assert_allclose(data.min(), 21.27, atol=0.01) - npt.assert_allclose(data.max(), 2.94, atol=0.01) + npt.assert_allclose(data.max(), 31.109999, atol=0.01) From 71bfe2d5634c0e3a3f545a603069c0882409ce71 Mon Sep 17 00:00:00 2001 From: yvonnefroelich Date: Wed, 25 Dec 2024 14:44:52 +0100 Subject: [PATCH 6/8] Round values for tests --- pygmt/tests/test_datasets_earth_mean_sea_surface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_datasets_earth_mean_sea_surface.py b/pygmt/tests/test_datasets_earth_mean_sea_surface.py index 425bece85c8..84b2b7123cc 100644 --- a/pygmt/tests/test_datasets_earth_mean_sea_surface.py +++ b/pygmt/tests/test_datasets_earth_mean_sea_surface.py @@ -50,4 +50,4 @@ def test_earth_mss_01m_default_registration(): assert data.coords["lon"].data.min() == -10.0 assert data.coords["lon"].data.max() == -9.0 npt.assert_allclose(data.min(), 21.27, atol=0.01) - npt.assert_allclose(data.max(), 31.109999, atol=0.01) + npt.assert_allclose(data.max(), 31.11, atol=0.01) From e7180078ee018020d76a3819f4b360601f1b635c Mon Sep 17 00:00:00 2001 From: yvonnefroelich Date: Wed, 25 Dec 2024 17:18:34 +0100 Subject: [PATCH 7/8] Fix typo in caching --- pygmt/helpers/caching.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/helpers/caching.py b/pygmt/helpers/caching.py index 7bc9cc67da4..b5703e1b006 100644 --- a/pygmt/helpers/caching.py +++ b/pygmt/helpers/caching.py @@ -22,7 +22,7 @@ def cache_data(): "@earth_mag_01d_g", "@earth_mag4km_01d_g", "@earth_mask_01d_g", - "@earth_mss_01_g", + "@earth_mss_01d_g", "@earth_night_01d", "@earth_relief_01d_g", "@earth_relief_01d_p", From 4bb47f83e389e61e3ac51002a6e5f9e8f2060fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= <94163266+yvonnefroehlich@users.noreply.github.com> Date: Thu, 26 Dec 2024 09:36:06 +0100 Subject: [PATCH 8/8] Set "tiled=True" for resolution large or equal "05m" Co-authored-by: Dongdong Tian --- pygmt/datasets/load_remote_dataset.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index 74d23e8acda..04278635233 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -220,11 +220,11 @@ class GMTRemoteDataset(NamedTuple): "15m": Resolution("15m"), "10m": Resolution("10m"), "06m": Resolution("06m"), - "05m": Resolution("05m"), - "04m": Resolution("04m"), - "03m": Resolution("03m"), - "02m": Resolution("02m"), - "01m": Resolution("01m", registrations=["gridline"]), + "05m": Resolution("05m", tiled=True), + "04m": Resolution("04m", tiled=True), + "03m": Resolution("03m", tiled=True), + "02m": Resolution("02m", tiled=True), + "01m": Resolution("01m", tiled=True, registrations=["gridline"]), }, ), "earth_night": GMTRemoteDataset(