From 9c740462f6c003402d09892c6d0c140eb0c9df71 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 15 Mar 2025 18:18:09 +0800 Subject: [PATCH 01/16] Extend GMTDataAccessor to support grid operations --- pygmt/accessors.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pygmt/accessors.py b/pygmt/accessors.py index d0891076d2a..54c038e1ee6 100644 --- a/pygmt/accessors.py +++ b/pygmt/accessors.py @@ -8,7 +8,7 @@ import xarray as xr from pygmt.enums import GridRegistration, GridType from pygmt.exceptions import GMTInvalidInput -from pygmt.src.grdinfo import grdinfo +from pygmt.src import grdfill, grdinfo @xr.register_dataarray_accessor("gmt") @@ -176,3 +176,11 @@ def gtype(self, value: GridType | int): ) raise GMTInvalidInput(msg) self._gtype = GridType(value) + + def fill(self, **kwargs): + """ + Interpolate across holes in the grid. + + See the :meth:`pygmt.grdfill` for available parameters. + """ + return grdfill(grid=self._obj, **kwargs) From 4853128b9a2562d6177af3ef4f3956916658d8ce Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 24 Mar 2025 16:30:10 +0800 Subject: [PATCH 02/16] Add more grid operations to GMTDataArrayAccessor --- pygmt/accessors.py | 81 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/pygmt/accessors.py b/pygmt/accessors.py index 54c038e1ee6..18b02eabe64 100644 --- a/pygmt/accessors.py +++ b/pygmt/accessors.py @@ -8,7 +8,18 @@ import xarray as xr from pygmt.enums import GridRegistration, GridType from pygmt.exceptions import GMTInvalidInput -from pygmt.src import grdfill, grdinfo +from pygmt.src import ( + dimfilter, + grdclip, + grdcut, + grdfill, + grdfilter, + grdgradient, + grdinfo, + grdproject, + grdsample, + grdtrack, +) @xr.register_dataarray_accessor("gmt") @@ -177,10 +188,74 @@ def gtype(self, value: GridType | int): raise GMTInvalidInput(msg) self._gtype = GridType(value) - def fill(self, **kwargs): + def dimfilter(self, **kwargs) -> xr.DataArray: + """ + Directional filtering of grids in the space domain. + + See the :func:`pygmt.dimfilter` function for available parameters. + """ + return dimfilter(grid=self._obj, **kwargs) + + def clip(self, **kwargs) -> xr.DataArray: + """ + Clip the range of grid values. + + See the :func:`pygmt.grdclip` function for available parameters. + """ + return grdclip(grid=self._obj, **kwargs) + + def cut(self, **kwargs) -> xr.DataArray: + """ + Extract subregion from a grid or image or a slice from a cube. + + See the :func:`pygmt.grdcut` function for available parameters. + """ + return grdcut(grid=self._obj, **kwargs) + + def fill(self, **kwargs) -> xr.DataArray: """ Interpolate across holes in the grid. - See the :meth:`pygmt.grdfill` for available parameters. + See the :func:`pygmt.grdfill` function for available parameters. """ return grdfill(grid=self._obj, **kwargs) + + def filter(self, **kwargs) -> xr.DataArray: + """ + Filter a grid in the space (or time) domain. + + See the :func:`pygmt.grdfilter` function for available parameters. + """ + return grdfilter(grid=self._obj, **kwargs) + + def gradient(self, **kwargs) -> xr.DataArray: + """ + Compute directional gradients from a grid. + + See the :func:`pygmt.grdgradient` function for available parameters. + """ + return grdgradient(grid=self._obj, **kwargs) + + def grdproject(self, **kwargs) -> xr.DataArray: + """ + Forward and inverse map transformation of grids. + + See the :func:`pygmt.grdproject` function for available parameters. + """ + return grdproject(grid=self._obj, **kwargs) + + def grdsample(self, **kwargs) -> xr.DataArray: + """ + Resample a grid onto a new lattice. + + See the :func:`pygmt.grdsample` function for available parameters. + """ + return grdsample(grid=self._obj, **kwargs) + + def grdtrack(self, **kwargs) -> xr.DataArray: + """ + Sample one or more grids at specified locations. + + See the :func:`pygmt.grdtrack` function for available parameters. + """ + return grdtrack(grid=self._obj, **kwargs) From 505c9d0fe838e23f36866097ee9aca15a69d97b0 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 28 Mar 2025 21:57:53 +0800 Subject: [PATCH 03/16] Add docstrings for the new methods --- pygmt/accessors.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/pygmt/accessors.py b/pygmt/accessors.py index 18b02eabe64..16f55085694 100644 --- a/pygmt/accessors.py +++ b/pygmt/accessors.py @@ -28,12 +28,24 @@ class GMTDataArrayAccessor: GMT accessor for :class:`xarray.DataArray`. The *gmt* accessor extends :class:`xarray.DataArray` to store GMT-specific - properties for grids, which are important for PyGMT to correctly process and plot - the grids. The *gmt* accessor contains the following properties: + properties for grids or images, which are important for PyGMT to correctly process + and plot them. The *gmt* accessor contains the following properties: - ``registration``: Grid registration type :class:`pygmt.enums.GridRegistration`. - ``gtype``: Grid coordinate system type :class:`pygmt.enums.GridType`. + It also contains a set of methods for grid operations. + + - :meth:`dimfilter`: Directional filtering of grids in the space domain. + - :meth:`clip`: Clip the range of grid values. + - :meth:`cut`: Extract subregion from a grid or image or a slice from a cube. + - :meth:`fill`: Interpolate across holes in the grid. + - :meth:`filter`: Filter a grid in the space (or time) domain. + - :meth:`gradient`: Compute directional gradients from a grid. + - :meth:`project`: Forward and inverse map transformation of grids. + - :meth:`sample`: Resample a grid onto a new lattice. + - :meth:`track`: Sample one or more grids at specified locations. + Examples -------- For GMT's built-in remote datasets, these GMT-specific properties are automatically @@ -236,7 +248,7 @@ def gradient(self, **kwargs) -> xr.DataArray: """ return grdgradient(grid=self._obj, **kwargs) - def grdproject(self, **kwargs) -> xr.DataArray: + def project(self, **kwargs) -> xr.DataArray: """ Forward and inverse map transformation of grids. @@ -244,7 +256,7 @@ def grdproject(self, **kwargs) -> xr.DataArray: """ return grdproject(grid=self._obj, **kwargs) - def grdsample(self, **kwargs) -> xr.DataArray: + def sample(self, **kwargs) -> xr.DataArray: """ Resample a grid onto a new lattice. @@ -252,7 +264,7 @@ def grdsample(self, **kwargs) -> xr.DataArray: """ return grdsample(grid=self._obj, **kwargs) - def grdtrack(self, **kwargs) -> xr.DataArray: + def track(self, **kwargs) -> xr.DataArray: """ Sample one or more grids at specified locations. From f49c3d00b1b223a891124915a1b419813a2c46aa Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 28 Mar 2025 22:09:41 +0800 Subject: [PATCH 04/16] Fix docstrings --- pygmt/accessors.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/accessors.py b/pygmt/accessors.py index 16f55085694..03bf33dd9bf 100644 --- a/pygmt/accessors.py +++ b/pygmt/accessors.py @@ -202,7 +202,7 @@ def gtype(self, value: GridType | int): def dimfilter(self, **kwargs) -> xr.DataArray: """ - Directional filtering of grids in the space domain. + Directional filtering of a grid in the space domain. See the :func:`pygmt.dimfilter` function for available parameters. """ @@ -266,7 +266,7 @@ def sample(self, **kwargs) -> xr.DataArray: def track(self, **kwargs) -> xr.DataArray: """ - Sample one or more grids at specified locations. + Sample a grid at specified locations. See the :func:`pygmt.grdtrack` function for available parameters. """ From 58ee6a1647dbb6711428f2d62278a3241dfdea6d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 28 Mar 2025 22:18:19 +0800 Subject: [PATCH 05/16] Fix docstrings --- pygmt/accessors.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/accessors.py b/pygmt/accessors.py index 03bf33dd9bf..1e0fcaf137f 100644 --- a/pygmt/accessors.py +++ b/pygmt/accessors.py @@ -34,9 +34,9 @@ class GMTDataArrayAccessor: - ``registration``: Grid registration type :class:`pygmt.enums.GridRegistration`. - ``gtype``: Grid coordinate system type :class:`pygmt.enums.GridType`. - It also contains a set of methods for grid operations. + The *gmt* accessor also provides a set of grid-operation methods: - - :meth:`dimfilter`: Directional filtering of grids in the space domain. + - :meth:`dimfilter`: Directional filtering of a grid in the space domain. - :meth:`clip`: Clip the range of grid values. - :meth:`cut`: Extract subregion from a grid or image or a slice from a cube. - :meth:`fill`: Interpolate across holes in the grid. @@ -44,7 +44,7 @@ class GMTDataArrayAccessor: - :meth:`gradient`: Compute directional gradients from a grid. - :meth:`project`: Forward and inverse map transformation of grids. - :meth:`sample`: Resample a grid onto a new lattice. - - :meth:`track`: Sample one or more grids at specified locations. + - :meth:`track`: Sample a grid at specified locations. Examples -------- From 49490d5cfe79f8e4ac45b64b18bbbbf8da9cb1f6 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 4 May 2025 16:19:18 +0800 Subject: [PATCH 06/16] Update docstrings --- pygmt/xarray/accessor.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/pygmt/xarray/accessor.py b/pygmt/xarray/accessor.py index 1e0fcaf137f..9a801722d79 100644 --- a/pygmt/xarray/accessor.py +++ b/pygmt/xarray/accessor.py @@ -34,17 +34,10 @@ class GMTDataArrayAccessor: - ``registration``: Grid registration type :class:`pygmt.enums.GridRegistration`. - ``gtype``: Grid coordinate system type :class:`pygmt.enums.GridType`. - The *gmt* accessor also provides a set of grid-operation methods: - - - :meth:`dimfilter`: Directional filtering of a grid in the space domain. - - :meth:`clip`: Clip the range of grid values. - - :meth:`cut`: Extract subregion from a grid or image or a slice from a cube. - - :meth:`fill`: Interpolate across holes in the grid. - - :meth:`filter`: Filter a grid in the space (or time) domain. - - :meth:`gradient`: Compute directional gradients from a grid. - - :meth:`project`: Forward and inverse map transformation of grids. - - :meth:`sample`: Resample a grid onto a new lattice. - - :meth:`track`: Sample a grid at specified locations. + The *gmt* accessor also provides a set of grid-operation methods that enables + applying GMT's grid processing functionalities directly to the current + :class:`xarray.DataArray` object. See the summary table below for the list of + available methods. Examples -------- @@ -90,6 +83,19 @@ class GMTDataArrayAccessor: >>> grid.gmt.gtype + Instead of calling a grid-processing function and passing the + :class:`xarray.DataArray` object as an input, you can call the corresponding method + directly on the object. For example, the following two are equivalent: + + >>> from pygmt.datasets import load_earth_relief + >>> grid = load_earth_relief(resolution="30m", region=[10, 30, 15, 25]) + >>> # Create a new grid from an input grid. Set all values below 1,000 to + >>> # 0 and all values above 1,500 to 10,000. + >>> # Option 1: + >>> new_grid = pygmt.grdclip(grid=grid, below=[1000, 0], above=[1500, 10000]) + >>> # Option 2: + >>> new_grid = grid.gmt.clip(below=[1000, 0], above=[1500, 10000]) + Notes ----- Due to the limitations of xarray accessors, the GMT accessors are created once per From db42b7ac13090f5dc768c7835ec149700d695781 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 4 May 2025 16:49:09 +0800 Subject: [PATCH 07/16] Add equalize_hist method --- pygmt/xarray/accessor.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pygmt/xarray/accessor.py b/pygmt/xarray/accessor.py index 9a801722d79..74f9e2a189a 100644 --- a/pygmt/xarray/accessor.py +++ b/pygmt/xarray/accessor.py @@ -15,6 +15,7 @@ grdfill, grdfilter, grdgradient, + grdhisteq, grdinfo, grdproject, grdsample, @@ -230,6 +231,14 @@ def cut(self, **kwargs) -> xr.DataArray: """ return grdcut(grid=self._obj, **kwargs) + def equalize_hist(self, **kwargs) -> xr.DataArray: + """ + Perform histogram equalization for a grid. + + See the :meth:`pygmt.grdhisteq.equalize_grid` method for available parameters. + """ + return grdhisteq.equalize_grid(grid=self._obj, **kwargs) + def fill(self, **kwargs) -> xr.DataArray: """ Interpolate across holes in the grid. From 397504b25552b877ec45f89aa0ac3680921d9970 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 25 Jun 2025 18:44:47 +0800 Subject: [PATCH 08/16] Use functools.wraps --- pygmt/xarray/accessor.py | 101 ++++++++++----------------------------- 1 file changed, 24 insertions(+), 77 deletions(-) diff --git a/pygmt/xarray/accessor.py b/pygmt/xarray/accessor.py index 3ed17afb41d..494cc42ae61 100644 --- a/pygmt/xarray/accessor.py +++ b/pygmt/xarray/accessor.py @@ -3,6 +3,7 @@ """ import contextlib +import functools from pathlib import Path import xarray as xr @@ -174,8 +175,8 @@ class GMTDataArrayAccessor: >>> from pygmt.datasets import load_earth_relief >>> grid = load_earth_relief(resolution="30m", region=[10, 30, 15, 25]) - >>> # Create a new grid from an input grid. Set all values below 1,000 to - >>> # 0 and all values above 1,500 to 10,000. + >>> # Create a new grid from an input grid. Set all values below 1,000 to 0 and all + >>> # values above 1,500 to 10,000. >>> # Option 1: >>> new_grid = pygmt.grdclip(grid=grid, below=[1000, 0], above=[1500, 10000]) >>> # Option 2: @@ -235,82 +236,28 @@ def gtype(self, value: GridType | int): raise GMTInvalidInput(msg) self._gtype = GridType(value) - def dimfilter(self, **kwargs) -> xr.DataArray: + @staticmethod + def _make_method(func): """ - Directional filtering of a grid in the space domain. + Create a wrapper method for PyGMT grid-processing methods. - See the :func:`pygmt.dimfilter` function for available parameters. + The :class:`xarray.DataArray` object is passed as the first argument. """ - return dimfilter(grid=self._obj, **kwargs) - def clip(self, **kwargs) -> xr.DataArray: - """ - Clip the range of grid values. - - See the :func:`pygmt.grdclip` function for available parameters. - """ - return grdclip(grid=self._obj, **kwargs) - - def cut(self, **kwargs) -> xr.DataArray: - """ - Extract subregion from a grid or image or a slice from a cube. - - See the :func:`pygmt.grdcut` function for available parameters. - """ - return grdcut(grid=self._obj, **kwargs) - - def equalize_hist(self, **kwargs) -> xr.DataArray: - """ - Perform histogram equalization for a grid. - - See the :meth:`pygmt.grdhisteq.equalize_grid` method for available parameters. - """ - return grdhisteq.equalize_grid(grid=self._obj, **kwargs) - - def fill(self, **kwargs) -> xr.DataArray: - """ - Interpolate across holes in the grid. - - See the :func:`pygmt.grdfill` function for available parameters. - """ - return grdfill(grid=self._obj, **kwargs) - - def filter(self, **kwargs) -> xr.DataArray: - """ - Filter a grid in the space (or time) domain. - - See the :func:`pygmt.grdfilter` function for available parameters. - """ - return grdfilter(grid=self._obj, **kwargs) - - def gradient(self, **kwargs) -> xr.DataArray: - """ - Compute directional gradients from a grid. - - See the :func:`pygmt.grdgradient` function for available parameters. - """ - return grdgradient(grid=self._obj, **kwargs) - - def project(self, **kwargs) -> xr.DataArray: - """ - Forward and inverse map transformation of grids. - - See the :func:`pygmt.grdproject` function for available parameters. - """ - return grdproject(grid=self._obj, **kwargs) - - def sample(self, **kwargs) -> xr.DataArray: - """ - Resample a grid onto a new lattice. - - See the :func:`pygmt.grdsample` function for available parameters. - """ - return grdsample(grid=self._obj, **kwargs) - - def track(self, **kwargs) -> xr.DataArray: - """ - Sample a grid at specified locations. - - See the :func:`pygmt.grdtrack` function for available parameters. - """ - return grdtrack(grid=self._obj, **kwargs) + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + return func(self._obj, *args, **kwargs) + + return wrapper + + # Accessor methods for grid operations + clip = _make_method(grdclip) + cut = _make_method(grdcut) + dimfilter = _make_method(dimfilter) + equalize_hist = _make_method(grdhisteq.equalize_grid) + fill = _make_method(grdfill) + filter = _make_method(grdfilter) + gradient = _make_method(grdgradient) + project = _make_method(grdproject) + sample = _make_method(grdsample) + track = _make_method(grdtrack) From c3c362c216fa26f503076c97e99b3574d8ca583e Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 25 Jun 2025 19:01:02 +0800 Subject: [PATCH 09/16] Add two tests --- pygmt/tests/test_xarray_accessor.py | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 5422f6defcb..95347b5b846 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -14,10 +14,50 @@ from pygmt.datasets import load_earth_relief from pygmt.enums import GridRegistration, GridType from pygmt.exceptions import GMTInvalidInput +from pygmt.helpers.testing import load_static_earth_relief _HAS_NETCDF4 = bool(importlib.util.find_spec("netCDF4")) +@pytest.fixture(scope="module", name="grid") +def fixture_grid(): + """ + Load the grid data from the sample earth_relief file. + """ + return load_static_earth_relief() + + +@pytest.fixture(scope="module", name="expected_clipped_grid") +def fixture_expected_clipped_grid(): + """ + Load the expected grdclip grid result. + """ + return xr.DataArray( + data=[ + [1000.0, 570.5, -1000.0, -1000.0], + [1000.0, 1000.0, 571.5, 638.5], + [555.5, 556.0, 580.0, 1000.0], + ], + coords={"lon": [-52.5, -51.5, -50.5, -49.5], "lat": [-18.5, -17.5, -16.5]}, + dims=["lat", "lon"], + ) + + +@pytest.fixture(scope="module", name="expected_equalized_grid") +def fixture_expected_equalized_grid(): + """ + Load the expected grdhisteq grid result. + """ + return xr.DataArray( + data=[[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 1], [1, 1, 1, 1]], + coords={ + "lon": [-51.5, -50.5, -49.5, -48.5], + "lat": [-21.5, -20.5, -19.5, -18.5], + }, + dims=["lat", "lon"], + ) + + def test_xarray_accessor_gridline_cartesian(): """ Check that the accessor returns the correct registration and gtype values for a @@ -169,3 +209,25 @@ def test_xarray_accessor_tiled_grid_slice_and_add(): added_grid.gmt.gtype = GridType.GEOGRAPHIC assert added_grid.gmt.registration is GridRegistration.PIXEL assert added_grid.gmt.gtype is GridType.GEOGRAPHIC + + +def test_xarray_accessor_clip(grid, expected_clipped_grid): + """ + Check that the accessor has the clip method and that it works correctly. + + This test is adapted from the `test_grdtest_grdclip_no_outgrid` test. + """ + clipped_grid = grid.gmt.clip( + below=[550, -1000], above=[700, 1000], region=[-53, -49, -19, -16] + ) + xr.testing.assert_allclose(a=clipped_grid, b=expected_clipped_grid) + + +def test_xarray_accessor_equalize(grid, expected_equalized_grid): + """ + Check that the accessor has the equalize method and that it works correctly. + + This test is adapted from the `test_equalize_grid_no_outgrid` test. + """ + equalized_grid = grid.gmt.equalize_hist(divisions=2, region=[-52, -48, -22, -18]) + xr.testing.assert_allclose(a=equalized_grid, b=expected_equalized_grid) From 3399025db20b2302d29057ed4e7475cfbe927dbc Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 25 Jun 2025 19:05:15 +0800 Subject: [PATCH 10/16] Fix --- pygmt/tests/test_xarray_accessor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 95347b5b846..ed1024204a0 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -30,7 +30,7 @@ def fixture_grid(): @pytest.fixture(scope="module", name="expected_clipped_grid") def fixture_expected_clipped_grid(): """ - Load the expected grdclip grid result. + The expected grdclip grid result. """ return xr.DataArray( data=[ @@ -46,7 +46,7 @@ def fixture_expected_clipped_grid(): @pytest.fixture(scope="module", name="expected_equalized_grid") def fixture_expected_equalized_grid(): """ - Load the expected grdhisteq grid result. + The expected grdhisteq grid result. """ return xr.DataArray( data=[[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 1], [1, 1, 1, 1]], @@ -225,7 +225,7 @@ def test_xarray_accessor_clip(grid, expected_clipped_grid): def test_xarray_accessor_equalize(grid, expected_equalized_grid): """ - Check that the accessor has the equalize method and that it works correctly. + Check that the accessor has the equalize_hist method and that it works correctly. This test is adapted from the `test_equalize_grid_no_outgrid` test. """ From 1b2aafb47898773c63dcb31f3bfe1d6fb66e6c0e Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 25 Jun 2025 19:10:07 +0800 Subject: [PATCH 11/16] Add a period --- pygmt/xarray/accessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/xarray/accessor.py b/pygmt/xarray/accessor.py index 494cc42ae61..be2dc3ec446 100644 --- a/pygmt/xarray/accessor.py +++ b/pygmt/xarray/accessor.py @@ -250,7 +250,7 @@ def wrapper(self, *args, **kwargs): return wrapper - # Accessor methods for grid operations + # Accessor methods for grid operations. clip = _make_method(grdclip) cut = _make_method(grdcut) dimfilter = _make_method(dimfilter) From e1241920b293d1929493b27dbf33d8aed2254225 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 25 Jun 2025 22:40:25 +0800 Subject: [PATCH 12/16] Fix a typo --- pygmt/tests/test_xarray_accessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index ed1024204a0..8212adc2b20 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -215,7 +215,7 @@ def test_xarray_accessor_clip(grid, expected_clipped_grid): """ Check that the accessor has the clip method and that it works correctly. - This test is adapted from the `test_grdtest_grdclip_no_outgrid` test. + This test is adapted from the `test_grdclip_no_outgrid` test. """ clipped_grid = grid.gmt.clip( below=[550, -1000], above=[700, 1000], region=[-53, -49, -19, -16] From 5a5fa165f125b5cb21a00c396011341a30b24f23 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 14 Jul 2025 11:17:46 +0800 Subject: [PATCH 13/16] Avoid two unused fixtures --- pygmt/tests/test_xarray_accessor.py | 54 +++++++++++------------------ 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 1373c7d9ee8..54f79291bbf 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -27,37 +27,6 @@ def fixture_grid(): return load_static_earth_relief() -@pytest.fixture(scope="module", name="expected_clipped_grid") -def fixture_expected_clipped_grid(): - """ - The expected grdclip grid result. - """ - return xr.DataArray( - data=[ - [1000.0, 570.5, -1000.0, -1000.0], - [1000.0, 1000.0, 571.5, 638.5], - [555.5, 556.0, 580.0, 1000.0], - ], - coords={"lon": [-52.5, -51.5, -50.5, -49.5], "lat": [-18.5, -17.5, -16.5]}, - dims=["lat", "lon"], - ) - - -@pytest.fixture(scope="module", name="expected_equalized_grid") -def fixture_expected_equalized_grid(): - """ - The expected grdhisteq grid result. - """ - return xr.DataArray( - data=[[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 1], [1, 1, 1, 1]], - coords={ - "lon": [-51.5, -50.5, -49.5, -48.5], - "lat": [-21.5, -20.5, -19.5, -18.5], - }, - dims=["lat", "lon"], - ) - - def test_xarray_accessor_gridline_cartesian(): """ Check that the accessor returns the correct registration and gtype values for a @@ -211,7 +180,7 @@ def test_xarray_accessor_tiled_grid_slice_and_add(): assert added_grid.gmt.gtype is GridType.GEOGRAPHIC -def test_xarray_accessor_clip(grid, expected_clipped_grid): +def test_xarray_accessor_clip(grid): """ Check that the accessor has the clip method and that it works correctly. @@ -220,14 +189,33 @@ def test_xarray_accessor_clip(grid, expected_clipped_grid): clipped_grid = grid.gmt.clip( below=[550, -1000], above=[700, 1000], region=[-53, -49, -19, -16] ) + + expected_clipped_grid = xr.DataArray( + data=[ + [1000.0, 570.5, -1000.0, -1000.0], + [1000.0, 1000.0, 571.5, 638.5], + [555.5, 556.0, 580.0, 1000.0], + ], + coords={"lon": [-52.5, -51.5, -50.5, -49.5], "lat": [-18.5, -17.5, -16.5]}, + dims=["lat", "lon"], + ) xr.testing.assert_allclose(a=clipped_grid, b=expected_clipped_grid) -def test_xarray_accessor_equalize(grid, expected_equalized_grid): +def test_xarray_accessor_equalize(grid): """ Check that the accessor has the equalize_hist method and that it works correctly. This test is adapted from the `test_equalize_grid_no_outgrid` test. """ equalized_grid = grid.gmt.equalize_hist(divisions=2, region=[-52, -48, -22, -18]) + + expected_equalized_grid = xr.DataArray( + data=[[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 1], [1, 1, 1, 1]], + coords={ + "lon": [-51.5, -50.5, -49.5, -48.5], + "lat": [-21.5, -20.5, -19.5, -18.5], + }, + dims=["lat", "lon"], + ) xr.testing.assert_allclose(a=equalized_grid, b=expected_equalized_grid) From 2d3c6b15007ec90f9abe053b05c882a8ecf8535b Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 19 Jul 2025 16:11:47 +0800 Subject: [PATCH 14/16] Use histeq for consistency Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/xarray/accessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/xarray/accessor.py b/pygmt/xarray/accessor.py index 8c52534ce06..05e162ed78f 100644 --- a/pygmt/xarray/accessor.py +++ b/pygmt/xarray/accessor.py @@ -250,7 +250,7 @@ def wrapper(self, *args, **kwargs): clip = _make_method(grdclip) cut = _make_method(grdcut) dimfilter = _make_method(dimfilter) - equalize_hist = _make_method(grdhisteq.equalize_grid) + histeq = _make_method(grdhisteq.equalize_grid) fill = _make_method(grdfill) filter = _make_method(grdfilter) gradient = _make_method(grdgradient) From c43ae14020e87ed255562124671c52a82e12f351 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 19 Jul 2025 16:23:30 +0800 Subject: [PATCH 15/16] Fix the name in tests --- pygmt/tests/test_xarray_accessor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 54f79291bbf..4a5fd9bca3b 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -204,11 +204,11 @@ def test_xarray_accessor_clip(grid): def test_xarray_accessor_equalize(grid): """ - Check that the accessor has the equalize_hist method and that it works correctly. + Check that the accessor has the histeq method and that it works correctly. This test is adapted from the `test_equalize_grid_no_outgrid` test. """ - equalized_grid = grid.gmt.equalize_hist(divisions=2, region=[-52, -48, -22, -18]) + equalized_grid = grid.gmt.histeq(divisions=2, region=[-52, -48, -22, -18]) expected_equalized_grid = xr.DataArray( data=[[0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 1], [1, 1, 1, 1]], From 6fd0c500719a28fd4a3e97788c20fc68d7c59c81 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 19 Jul 2025 16:25:52 +0800 Subject: [PATCH 16/16] Fix test name --- pygmt/tests/test_xarray_accessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 4a5fd9bca3b..99098836be3 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -202,7 +202,7 @@ def test_xarray_accessor_clip(grid): xr.testing.assert_allclose(a=clipped_grid, b=expected_clipped_grid) -def test_xarray_accessor_equalize(grid): +def test_xarray_accessor_histeq(grid): """ Check that the accessor has the histeq method and that it works correctly.