Skip to content

Commit 70e3764

Browse files
committed
pygmt.grdfill: Add new parameter 'inquire' to inquire the bounds of holes
1 parent c6aeadf commit 70e3764

File tree

2 files changed

+70
-24
lines changed

2 files changed

+70
-24
lines changed

pygmt/src/grdfill.py

+51-23
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import warnings
66

7+
import numpy as np
78
import xarray as xr
89
from pygmt.clib import Session
910
from pygmt.exceptions import GMTInvalidInput
@@ -76,8 +77,9 @@ def grdfill(
7677
gridfill: str | xr.DataArray | None = None,
7778
neighborfill: float | bool | None = None,
7879
splinefill: float | bool | None = None,
80+
inquire: bool = False,
7981
**kwargs,
80-
) -> xr.DataArray | None:
82+
) -> xr.DataArray | np.ndarray | None:
8183
r"""
8284
Interpolate across holes in a grid.
8385
@@ -111,6 +113,9 @@ def grdfill(
111113
hole : float
112114
Set the node value used to identify a point as a member of a hole [Default is
113115
NaN].
116+
inquire
117+
Output the bounds of each hole. The bounds are 2-D numpy arrays in the form of
118+
(west, east, south, north). No grid fill takes place and ``outgrid`` is ignored.
114119
mode : str
115120
Specify the hole-filling algorithm to use. Choose from **c** for constant fill
116121
and append the constant value, **n** for nearest neighbor (and optionally append
@@ -136,42 +141,65 @@ def grdfill(
136141
137142
Example
138143
-------
144+
Fill holes in a bathymetric grid with a constant value of 20.
139145
>>> import pygmt
140146
>>> # Load a bathymetric grid with missing data
141147
>>> earth_relief_holes = pygmt.datasets.load_sample_data(name="earth_relief_holes")
142148
>>> # Fill the holes with a constant value of 20
143149
>>> filled_grid = pygmt.grdfill(grid=earth_relief_holes, constantfill=20)
150+
151+
Inquire the bounds of each hole.
152+
>>> pygmt.grdfill(grid=earth_relief_holes, inquire=True)
153+
array([[1.83333333, 6.16666667, 3.83333333, 8.16666667],
154+
[6.16666667, 7.83333333, 0.5 , 2.5 ]])
144155
"""
156+
_fill_pars = "'constantfill'/'gridfill'/'neighborfill'/'splinefill'"
145157
# TODO(PyGMT>=0.19.0): Remove the deprecated 'mode' parameter.
146158
if kwargs.get("A") is not None: # The deprecated 'mode' parameter is given.
147-
warnings.warn(
159+
msg = (
148160
"The 'mode' parameter is deprecated since v0.15.0 and will be removed in "
149-
"v0.19.0. Use 'constantfill'/'gridfill'/'neighborfill'/'splinefill' "
150-
"instead.",
151-
FutureWarning,
152-
stacklevel=1,
161+
f"v0.19.0. Use {_fill_pars} instead."
153162
)
163+
warnings.warn(msg, FutureWarning, stacklevel=1)
154164
else:
155165
# Determine the -A option from the fill parameters.
156166
kwargs["A"] = _parse_fill_mode(constantfill, gridfill, neighborfill, splinefill)
157167

158-
if kwargs.get("A") is None and kwargs.get("L") is None:
159-
msg = "At least parameter 'mode' or 'L' must be specified."
168+
if kwargs.get("A") and inquire:
169+
msg = f"Parameters {_fill_pars} and 'inquire' are mutually exclusive."
170+
raise GMTInvalidInput(msg)
171+
if not (kwargs.get("A") or inquire):
172+
msg = (
173+
f"Need to specify parameter {_fill_pars} for filling holes or 'inquire' "
174+
"for inquiring the bounds of each hole."
175+
)
160176
raise GMTInvalidInput(msg)
161177

162178
with Session() as lib:
163-
with (
164-
lib.virtualfile_in(check_kind="raster", data=grid) as vingrd,
165-
lib.virtualfile_in(
166-
check_kind="raster", data=gridfill, required_data=False
167-
) as vbggrd,
168-
lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd,
169-
):
170-
if gridfill is not None:
171-
# Fill by a grid. Append the actual or virtual grid file name.
172-
kwargs["A"] = f"g{vbggrd}"
173-
kwargs["G"] = voutgrd
174-
lib.call_module(
175-
module="grdfill", args=build_arg_list(kwargs, infile=vingrd)
176-
)
177-
return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid)
179+
with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd:
180+
if inquire: # Inquire mode.
181+
kwargs["L"] = True
182+
with lib.virtualfile_out(kind="dataset") as vouttbl:
183+
lib.call_module(
184+
module="grdfill",
185+
args=build_arg_list(kwargs, infile=vingrd, outfile=vouttbl),
186+
)
187+
return lib.virtualfile_to_dataset(
188+
vfname=vouttbl, output_type="numpy"
189+
)
190+
191+
# Fill mode.
192+
with (
193+
lib.virtualfile_in(
194+
check_kind="raster", data=gridfill, required_data=False
195+
) as vbggrd,
196+
lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd,
197+
):
198+
if gridfill is not None:
199+
# Fill by a grid. Append the actual or virtual grid file name.
200+
kwargs["A"] = f"g{vbggrd}"
201+
kwargs["G"] = voutgrd
202+
lib.call_module(
203+
module="grdfill", args=build_arg_list(kwargs, infile=vingrd)
204+
)
205+
return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid)

pygmt/tests/test_grdfill.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,32 @@ def test_grdfill_gridfill_dataarray(grid):
114114
npt.assert_array_equal(result[3:6, 3:5], bggrid[3:6, 3:5])
115115

116116

117+
def test_grdfill_inquire(grid):
118+
"""
119+
Test grdfill with inquire mode.
120+
"""
121+
bounds = grdfill(grid=grid, inquire=True)
122+
assert isinstance(bounds, np.ndarray)
123+
assert bounds.shape == (1, 4)
124+
npt.assert_allclose(bounds, [[-52.0, -50.0, -21.0, -18.0]])
125+
126+
117127
def test_grdfill_required_args(grid):
118128
"""
119-
Test that grdfill fails without arguments for `mode` and `L`.
129+
Test that grdfill fails without filling parameters or 'inquire'.
120130
"""
121131
with pytest.raises(GMTInvalidInput):
122132
grdfill(grid=grid)
123133

124134

135+
def test_grdfill_inquire_and_fill(grid):
136+
"""
137+
Grdfill fails if both inquire and fill parameters are given.
138+
"""
139+
with pytest.raises(GMTInvalidInput):
140+
grdfill(grid=grid, inquire=True, constantfill=20)
141+
142+
125143
# TODO(PyGMT>=0.19.0): Remove this test.
126144
def test_grdfill_deprecated_mode(grid, expected_grid):
127145
"""

0 commit comments

Comments
 (0)