@@ -116,3 +116,144 @@ def grdcut(grid, **kwargs):
116116 result = None # if user sets an outgrid, return None
117117
118118 return result
119+
120+
121+ @fmt_docstring
122+ @use_alias (
123+ D = "distance" ,
124+ F = "filter" ,
125+ G = "outgrid" ,
126+ I = "spacing" ,
127+ N = "nans" ,
128+ R = "region" ,
129+ T = "toggle" ,
130+ V = "verbose" ,
131+ )
132+ @kwargs_to_strings (R = "sequence" )
133+ def grdfilter (grid , ** kwargs ):
134+ """
135+ Filter a grid in the space (or time) domain.
136+
137+ Filter a grid file in the time domain using one of the selected convolution
138+ or non-convolution isotropic or rectangular filters and compute distances
139+ using Cartesian or Spherical geometries. The output grid file can
140+ optionally be generated as a sub-region of the input (via *region*) and/or
141+ with new increment (via *spacing*) or registration (via *toggle*). In this
142+ way, one may have "extra space" in the input data so that the edges will
143+ not be used and the output can be within one half-width of the input edges.
144+ If the filter is low-pass, then the output may be less frequently sampled
145+ than the input.
146+
147+ Full option list at :gmt-docs:`grdfilter.html`
148+
149+ {aliases}
150+
151+ Parameters
152+ ----------
153+ grid : str or xarray.DataArray
154+ The file name of the input grid or the grid loaded as a DataArray.
155+ outgrid : str or None
156+ The name of the output netCDF file with extension .nc to store the grid
157+ in.
158+ filter : str
159+ ``xwidth[/width2][modifiers]``.
160+ Name of filter type you which to apply, followed by the width
161+ b: Box Car; c: Cosine Arch; g: Gaussian; o: Operator; m: Median;
162+ p: Maximum Likelihood probability; h: histogram
163+ Example: F='m600' for a median filter with width of 600
164+ distance : str
165+ Distance *flag* tells how grid (x,y) relates to filter width as
166+ follows:
167+
168+ p: grid (px,py) with *width* an odd number of pixels; Cartesian
169+ distances.
170+
171+ 0: grid (x,y) same units as *width*, Cartesian distances.
172+
173+ 1: grid (x,y) in degrees, *width* in kilometers, Cartesian distances.
174+
175+ 2: grid (x,y) in degrees, *width* in km, dx scaled by cos(middle y),
176+ Cartesian distances.
177+
178+ The above options are fastest because they allow weight matrix to be
179+ computed only once. The next three options are slower because they
180+ recompute weights for each latitude.
181+
182+ 3: grid (x,y) in degrees, *width* in km, dx scaled by cosine(y),
183+ Cartesian distance calculation.
184+
185+ 4: grid (x,y) in degrees, *width* in km, Spherical distance
186+ calculation.
187+
188+ 5: grid (x,y) in Mercator ``projection='m1'`` img units, *width* in km,
189+ Spherical distance calculation.
190+
191+ spacing : str
192+ ``xinc[+e|n][/yinc[+e|n]]``.
193+ x_inc [and optionally y_inc] is the grid spacing.
194+ nans : str or float
195+ ``i|p|r``.
196+ Determine how NaN-values in the input grid affects the filtered output.
197+ {R}
198+ toggle : bool
199+ Toggle the node registration for the output grid so as to become the
200+ opposite of the input grid. [Default gives the same registration as the
201+ input grid].
202+ {V}
203+
204+ Returns
205+ -------
206+ ret: xarray.DataArray or None
207+ Return type depends on whether the *outgrid* parameter is set:
208+ - xarray.DataArray if *outgrid* is not set
209+ - None if *outgrid* is set (grid output will be stored in *outgrid*)
210+
211+ Examples
212+ --------
213+ >>> import os
214+ >>> import pygmt
215+
216+ >>> # Apply a filter of 600km (full width) to the @earth_relief_30m file
217+ >>> # and return a filtered field (saved as netcdf)
218+ >>> pygmt.grdfilter(
219+ ... grid="@earth_relief_30m",
220+ ... filter="m600",
221+ ... distance="4",
222+ ... region=[150, 250, 10, 40],
223+ ... spacing=0.5,
224+ ... outgrid="filtered_pacific.nc",
225+ ... )
226+ >>> os.remove("filtered_pacific.nc") # cleanup file
227+
228+ >>> # Apply a gaussian smoothing filter of 600 km in the input data array,
229+ >>> # and returns a filtered data array with the smoothed field.
230+ >>> grid = pygmt.datasets.load_earth_relief()
231+ >>> smooth_field = pygmt.grdfilter(grid=grid, filter="g600", distance="4")
232+
233+ """
234+ kind = data_kind (grid )
235+
236+ with GMTTempFile (suffix = ".nc" ) as tmpfile :
237+ with Session () as lib :
238+ if kind == "file" :
239+ file_context = dummy_context (grid )
240+ elif kind == "grid" :
241+ file_context = lib .virtualfile_from_grid (grid )
242+ else :
243+ raise GMTInvalidInput ("Unrecognized data type: {}" .format (type (grid )))
244+
245+ with file_context as infile :
246+ if "G" not in kwargs .keys (): # if outgrid is unset, output to tempfile
247+ kwargs .update ({"G" : tmpfile .name })
248+ outgrid = kwargs ["G" ]
249+ arg_str = " " .join ([infile , build_arg_string (kwargs )])
250+ lib .call_module ("grdfilter" , arg_str )
251+
252+ if outgrid == tmpfile .name : # if user did not set outgrid, return DataArray
253+ with xr .open_dataarray (outgrid ) as dataarray :
254+ result = dataarray .load ()
255+ _ = result .gmt # load GMTDataArray accessor information
256+ else :
257+ result = None # if user sets an outgrid, return None
258+
259+ return result
0 commit comments