Skip to content

Commit 939a182

Browse files
Add Earth deflection dataset
1 parent e5efc91 commit 939a182

File tree

6 files changed

+269
-0
lines changed

6 files changed

+269
-0
lines changed

doc/api/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ and store them in GMT's user data directory.
235235
datasets.load_blue_marble
236236
datasets.load_earth_age
237237
datasets.load_earth_dist
238+
datasets.load_earth_east_west_deflection
238239
datasets.load_earth_free_air_anomaly
239240
datasets.load_earth_geoid
240241
datasets.load_earth_magnetic_anomaly
@@ -248,6 +249,7 @@ and store them in GMT's user data directory.
248249
datasets.load_moon_relief
249250
datasets.load_pluto_relief
250251
datasets.load_venus_relief
252+
datasets.load_earth_south_north_deflection
251253
datasets.load_sample_data
252254

253255
In addition, there is also a special function to load XYZ tile maps via

pygmt/datasets/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pygmt.datasets.earth_age import load_earth_age
88
from pygmt.datasets.earth_day import load_blue_marble
99
from pygmt.datasets.earth_dist import load_earth_dist
10+
from pygmt.datasets.earth_east_west_deflection import load_earth_east_west_deflection
1011
from pygmt.datasets.earth_free_air_anomaly import load_earth_free_air_anomaly
1112
from pygmt.datasets.earth_geoid import load_earth_geoid
1213
from pygmt.datasets.earth_magnetic_anomaly import load_earth_magnetic_anomaly
@@ -17,6 +18,9 @@
1718
from pygmt.datasets.earth_mean_sea_surface import load_earth_mean_sea_surface
1819
from pygmt.datasets.earth_night import load_black_marble
1920
from pygmt.datasets.earth_relief import load_earth_relief
21+
from pygmt.datasets.earth_south_north_deflection import (
22+
load_earth_south_north_deflection,
23+
)
2024
from pygmt.datasets.earth_vertical_gravity_gradient import (
2125
load_earth_vertical_gravity_gradient,
2226
)

pygmt/datasets/earth_deflection.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"""
2+
Function to download the IGPP Earth east-west and south-north deflection datasets from
3+
the GMT data server, and load as :class:`xarray.DataArray`.
4+
5+
The grids are available in various resolutions.
6+
"""
7+
8+
from collections.abc import Sequence
9+
from typing import Literal
10+
11+
import xarray as xr
12+
from pygmt.datasets.load_remote_dataset import _load_remote_dataset
13+
14+
__doctest_skip__ = ["load_earth_deflection"]
15+
16+
17+
def load_earth_deflection(
18+
resolution: Literal[
19+
"01d", "30m", "20m", "15m", "10m", "06m", "05m", "04m", "03m", "02m", "01m"
20+
] = "01d",
21+
region: Sequence[float] | str | None = None,
22+
registration: Literal["gridline", "pixel", None] = None,
23+
direction: Literal["edefl", "ndefl"] = "edefl",
24+
) -> xr.DataArray:
25+
r"""
26+
Load the IGPP Earth east-west and south-north deflections datasets in various
27+
resolutions.
28+
29+
.. list-table::
30+
:widths: 50 50
31+
:header-rows: 1
32+
33+
* - IGPP Earth east-west deflection
34+
- IGPP Earth south-north deflection
35+
* - .. figure:: https://www.generic-mapping-tools.org/remote-datasets/_images/GMT_earth_edefl.jpg
36+
- .. figure:: https://www.generic-mapping-tools.org/remote-datasets/_images/GMT_earth_ndefl.jpg
37+
38+
The grids are downloaded to a user data directory (usually
39+
``~/.gmt/server/earth/earth_edefl/`` and``~/.gmt/server/earth/earth_ndefl/`` the
40+
first time you invoke this function. Afterwards, it will load the grid from the
41+
data directory. So you'll need an internet connection the first time around.
42+
43+
These grids can also be accessed by passing in the file name
44+
**@**\ *earth_defl_type*\_\ *res*\[_\ *reg*] to any grid processing function or
45+
plotting method. *earth_defl_type* is the GMT name for the dataset. The available
46+
options are **earth_edefl** and **earth_ndefl**. *res* is the grid resolution (see
47+
below), and *reg* is the grid registration type (**p** for pixel registration or
48+
**g** for gridline registration).
49+
50+
The default color palette table (CPTs) for this dataset is *@earth_defl.cpt*. It's
51+
implicitly used when passing in the file name of the dataset to any grid plotting
52+
method if no CPT is explicitly specified. When the dataset is loaded and plotted as
53+
an :class:`xarray.DataArray` object, the default CPT is ignored, and GMT's default
54+
CPT (*turbo*) is used. To use the dataset-specific CPT, you need to explicitly set
55+
``cmap="@earth_defl.cpt"``.
56+
57+
Refer to :gmt-datasets:`earth-edefl.html` and :gmt-datasets:`earth-ndefl.html` for
58+
more details about available datasets, including version information and references.
59+
60+
Parameters
61+
----------
62+
resolution
63+
The grid resolution. The suffix ``d`` and ``m`` stand for arc-degrees and
64+
arc-minutes.
65+
region
66+
The subregion of the grid to load, in the form of a sequence [*xmin*, *xmax*,
67+
*ymin*, *ymax*] or an ISO country code. Required for grids with resolutions
68+
higher than 5 arc-minutes (i.e., ``"05m"``).
69+
registration
70+
Grid registration type. Either ``"pixel"`` for pixel registration or
71+
``"gridline"`` for gridline registration. Default is ``None``, means
72+
``"gridline"`` for all resolutions except ``"01m"`` which is ``"pixel"`` only.
73+
direction
74+
By default, the east-west deflection (``direction="edefl"``) is returned, set
75+
``direction="ndefl"`` to return the south-north deflection.
76+
77+
Returns
78+
-------
79+
grid
80+
The Earth east-west or south-north deflection grid. Coordinates are latitude
81+
and longitude in degrees. Units are in micro-radians.
82+
83+
Note
84+
----
85+
The registration and coordinate system type of the returned
86+
:class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e.,
87+
``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these
88+
properties may be lost after specific grid operations (such as slicing) and will
89+
need to be manually set before passing the grid to any PyGMT data processing or
90+
plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed
91+
explanations and workarounds.
92+
93+
Examples
94+
--------
95+
96+
>>> from pygmt.datasets import load_earth_deflection
97+
>>> # load the default grid for east-west deflection (gridline-registered 1
98+
>>> # arc-degree grid)
99+
>>> grid = load_earth_deflection()
100+
>>> # load the default grid for south-north deflection
101+
>>> grid = load_earth_deflection(direction="ndefl")
102+
>>> # load the 30 arc-minutes grid with "gridline" registration
103+
>>> grid = load_earth_deflection(resolution="30m", registration="gridline")
104+
>>> # load high-resolution (5 arc-minutes) grid for a specific region
105+
>>> grid = load_earth_deflection(
106+
... resolution="05m", region=[120, 160, 30, 60], registration="gridline"
107+
... )
108+
"""
109+
prefix = "earth_ndefl" if direction == "ndefl" else "earth_edefl"
110+
grid = _load_remote_dataset(
111+
name=prefix,
112+
prefix=prefix,
113+
resolution=resolution,
114+
region=region,
115+
registration=registration,
116+
)
117+
return grid

pygmt/datasets/load_remote_dataset.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,24 @@ class GMTRemoteDataset(NamedTuple):
110110
"01m": Resolution("01m", registrations=["gridline"], tiled=True),
111111
},
112112
),
113+
"earth_edefl": GMTRemoteDataset(
114+
description="IGPP Earth east-west deflections",
115+
units="micro-radians",
116+
extra_attributes={"horizontal_datum": "WGS84"},
117+
resolutions={
118+
"01d": Resolution("01d"),
119+
"30m": Resolution("30m"),
120+
"20m": Resolution("20m"),
121+
"15m": Resolution("15m"),
122+
"10m": Resolution("10m"),
123+
"06m": Resolution("06m"),
124+
"05m": Resolution("05m", tiled=True),
125+
"04m": Resolution("04m", tiled=True),
126+
"03m": Resolution("03m", tiled=True),
127+
"02m": Resolution("02m", tiled=True),
128+
"01m": Resolution("01m", registrations=["pixel"], tiled=True),
129+
},
130+
),
113131
"earth_faa": GMTRemoteDataset(
114132
description="IGPP Earth free-air anomaly",
115133
units="mGal",
@@ -277,6 +295,24 @@ class GMTRemoteDataset(NamedTuple):
277295
"07m": Resolution("07m", registrations=["gridline"]),
278296
},
279297
),
298+
"earth_ndefl": GMTRemoteDataset(
299+
description="IGPP Earth south-north deflections",
300+
units="micro-radians",
301+
extra_attributes={"horizontal_datum": "WGS84"},
302+
resolutions={
303+
"01d": Resolution("01d"),
304+
"30m": Resolution("30m"),
305+
"20m": Resolution("20m"),
306+
"15m": Resolution("15m"),
307+
"10m": Resolution("10m"),
308+
"06m": Resolution("06m"),
309+
"05m": Resolution("05m", tiled=True),
310+
"04m": Resolution("04m", tiled=True),
311+
"03m": Resolution("03m", tiled=True),
312+
"02m": Resolution("02m", tiled=True),
313+
"01m": Resolution("01m", registrations=["pixel"], tiled=True),
314+
},
315+
),
280316
"earth_vgg": GMTRemoteDataset(
281317
description="IGPP Earth vertical gravity gradient",
282318
units="Eotvos",

pygmt/helpers/caching.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def cache_data():
1515
"@earth_age_01d_g",
1616
"@earth_day_01d",
1717
"@earth_dist_01d",
18+
"@earth_edefl_01d",
1819
"@earth_faa_01d_g",
1920
"@earth_gebco_01d_g",
2021
"@earth_gebcosi_01d_g",
@@ -26,6 +27,7 @@ def cache_data():
2627
"@earth_mdt_01d_g",
2728
"@earth_mdt_07m_g",
2829
"@earth_mss_01d_g",
30+
"@earth_ndefl_01d",
2931
"@earth_night_01d",
3032
"@earth_relief_01d_g",
3133
"@earth_relief_01d_p",
@@ -50,11 +52,13 @@ def cache_data():
5052
"@N30E060.earth_age_01m_g.nc",
5153
"@N30E090.earth_age_01m_g.nc",
5254
"@N00W030.earth_dist_01m_g.nc",
55+
"@N00W030.earth_edefl_01m_p.nc",
5356
"@N00W030.earth_faa_01m_p.nc",
5457
"@N00W030.earth_geoid_01m_g.nc",
5558
"@S30W060.earth_mag_02m_p.nc",
5659
"@S30W120.earth_mag4km_02m_p.nc",
5760
"@N30E090.earth_mss_01m_g.nc",
61+
"@N30E090.earth_ndefl_01m_p.nc",
5862
"@N00W090.earth_relief_03m_p.nc",
5963
"@N00E135.earth_relief_30s_g.nc",
6064
"@N00W010.earth_relief_15s_p.nc",
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
Test basic functionality for loading IGPP Earth east-west and south-north deflection
3+
datasets.
4+
"""
5+
6+
import numpy as np
7+
import numpy.testing as npt
8+
from pygmt.datasets import load_earth_deflection
9+
10+
11+
def test_earth_edefl_01d():
12+
"""
13+
Test some properties of the Earth east-west deflection 01d data.
14+
"""
15+
data = load_earth_deflection(resolution="01d")
16+
assert data.name == "z"
17+
assert data.attrs["long_name"] == "edefl (microradians)"
18+
assert data.attrs["description"] == "IGPP Earth east-west deflections"
19+
assert data.attrs["units"] == "micro-radians"
20+
assert data.attrs["horizontal_datum"] == "WGS84"
21+
assert data.shape == (181, 361)
22+
assert data.gmt.registration == 0
23+
npt.assert_allclose(data.lat, np.arange(-90, 91, 1))
24+
npt.assert_allclose(data.lon, np.arange(-180, 181, 1))
25+
npt.assert_allclose(data.min(), -188.85, atol=0.04)
26+
npt.assert_allclose(data.max(), 161.25, atol=0.04)
27+
28+
29+
def test_earth_edefl_01d_with_region():
30+
"""
31+
Test loading low-resolution Earth east-west deflection with "region".
32+
"""
33+
data = load_earth_deflection(resolution="01d", region=[-10, 10, -5, 5])
34+
assert data.shape == (11, 21)
35+
assert data.gmt.registration == 0
36+
npt.assert_allclose(data.lat, np.arange(-5, 6, 1))
37+
npt.assert_allclose(data.lon, np.arange(-10, 11, 1))
38+
npt.assert_allclose(data.min(), -36.125, atol=0.04)
39+
npt.assert_allclose(data.max(), 45.3, atol=0.04)
40+
41+
42+
def test_earth_edefl_01m_default_registration():
43+
"""
44+
Test that the grid returned by default for the 1 arc-minute resolution has a "pixel"
45+
registration.
46+
"""
47+
data = load_earth_deflection(resolution="01m", region=[-10, -9, 3, 5])
48+
assert data.shape == (120, 60)
49+
assert data.gmt.registration == 1
50+
npt.assert_allclose(data.coords["lat"].data.min(), 3.008333333)
51+
npt.assert_allclose(data.coords["lat"].data.max(), 4.991666666)
52+
npt.assert_allclose(data.coords["lon"].data.min(), -9.99166666)
53+
npt.assert_allclose(data.coords["lon"].data.max(), -9.00833333)
54+
npt.assert_allclose(data.min(), -49.225, atol=0.04)
55+
npt.assert_allclose(data.max(), 115.0, atol=0.04)
56+
57+
58+
def test_earth_ndefl_01d():
59+
"""
60+
Test some properties of the Earth south-north deflection 01d data.
61+
"""
62+
data = load_earth_deflection(resolution="01d", direction="ndefl")
63+
assert data.name == "z"
64+
assert data.attrs["long_name"] == "ndefl (microradians)"
65+
assert data.attrs["description"] == "IGPP Earth south-north deflections"
66+
assert data.attrs["units"] == "micro-radians"
67+
assert data.attrs["horizontal_datum"] == "WGS84"
68+
assert data.shape == (181, 361)
69+
assert data.gmt.registration == 0
70+
npt.assert_allclose(data.lat, np.arange(-90, 91, 1))
71+
npt.assert_allclose(data.lon, np.arange(-180, 181, 1))
72+
npt.assert_allclose(data.min(), -188.85, atol=0.04)
73+
npt.assert_allclose(data.max(), 161.25, atol=0.04)
74+
75+
76+
def test_earth_ndefl_01d_with_region():
77+
"""
78+
Test loading low-resolution Earth south-north deflection with "region".
79+
"""
80+
data = load_earth_deflection(
81+
resolution="01d", region=[-10, 10, -5, 5], direction="ndefl"
82+
)
83+
assert data.shape == (11, 21)
84+
assert data.gmt.registration == 0
85+
npt.assert_allclose(data.lat, np.arange(-5, 6, 1))
86+
npt.assert_allclose(data.lon, np.arange(-10, 11, 1))
87+
npt.assert_allclose(data.min(), -36.125, atol=0.04)
88+
npt.assert_allclose(data.max(), 45.3, atol=0.04)
89+
90+
91+
def test_earth_ndefl_01m_default_registration():
92+
"""
93+
Test that the grid returned by default for the 1 arc-minute resolution has a "pixel"
94+
registration.
95+
"""
96+
data = load_earth_deflection(
97+
resolution="01m", region=[-10, -9, 3, 5], direction="ndefl"
98+
)
99+
assert data.shape == (120, 60)
100+
assert data.gmt.registration == 1
101+
npt.assert_allclose(data.coords["lat"].data.min(), 3.008333333)
102+
npt.assert_allclose(data.coords["lat"].data.max(), 4.991666666)
103+
npt.assert_allclose(data.coords["lon"].data.min(), -9.99166666)
104+
npt.assert_allclose(data.coords["lon"].data.max(), -9.00833333)
105+
npt.assert_allclose(data.min(), -49.225, atol=0.04)
106+
npt.assert_allclose(data.max(), 115.0, atol=0.04)

0 commit comments

Comments
 (0)