22grdclip - Clip the range of grid values.
33"""
44
5+ from collections .abc import Sequence
6+
57import xarray as xr
68from pygmt .clib import Session
7- from pygmt .helpers import build_arg_list , fmt_docstring , kwargs_to_strings , use_alias
9+ from pygmt .exceptions import GMTInvalidInput
10+ from pygmt .helpers import (
11+ build_arg_list ,
12+ fmt_docstring ,
13+ is_nonstr_iter ,
14+ kwargs_to_strings ,
15+ use_alias ,
16+ )
817
918__doctest_skip__ = ["grdclip" ]
1019
1120
21+ def _parse_sequence (name , value , separator = "/" , size = 2 , ndim = 1 ):
22+ """
23+ Parse a sequence of values from a string or a list.
24+
25+ >>> _parse_sequence("above", [1000, 0], size=2, ndim=1)
26+ '1000/0'
27+ >>> _parse_sequence("below", [1000, 0], size=2, ndim=1)
28+ '1000/0'
29+ >>> _parse_sequence("between", [1000, 1500, 10000], size=3, ndim=2)
30+ '1000/1500/10000'
31+ >>> _parse_sequence("between", [[1000, 1500, 10000]], size=3, ndim=2)
32+ ['1000/1500/10000']
33+ >>> _parse_sequence(
34+ ... "between", [[1000, 1500, 10000], [1500, 2000, 20000]], size=3, ndim=2
35+ ... )
36+ ['1000/1500/10000', '1500/2000/20000']
37+ >>> _parse_sequence("replace", [1000, 0], size=2, ndim=1)
38+ '1000/0'
39+ >>> _parse_sequence("replace", [[1000, 0], [1500, 10000]], size=2, ndim=2)
40+ ['1000/0', '1500/10000']
41+ """
42+ if not is_nonstr_iter (value ): # Not a sequence. Likely str or None.
43+ return value
44+
45+ # A sequence of sequences.
46+ if len (value ) == 0 :
47+ return None
48+ if is_nonstr_iter (value [0 ]): # 2-D sequence
49+ if ndim == 1 :
50+ msg = f"Parameter '{ name } ' must be a 1-D sequence, not a 2-D sequence."
51+ raise GMTInvalidInput (msg )
52+
53+ actual_sizes = {len (i ) for i in value }
54+ if len (actual_sizes ) != 1 or actual_sizes != {size }:
55+ msg = f"Parameter '{ name } ' must be a 1-D or 2D sequence with { size } values."
56+ raise GMTInvalidInput (msg )
57+ return [separator .join (str (j ) for j in value [i ]) for i in range (len (value ))]
58+
59+ # A sequence.
60+ if len (value ) != size :
61+ msg = f"Parameter '{ name } ' must be a 1-D sequence of { size } values, but got { len (value )} ."
62+ raise GMTInvalidInput (msg )
63+ return separator .join (str (i ) for i in value )
64+
65+
1266@fmt_docstring
13- @use_alias (
14- R = "region" ,
15- Sa = "above" ,
16- Sb = "below" ,
17- Si = "between" ,
18- Sr = "new" ,
19- V = "verbose" ,
20- )
21- @kwargs_to_strings (
22- R = "sequence" ,
23- Sa = "sequence" ,
24- Sb = "sequence" ,
25- Si = "sequence" ,
26- Sr = "sequence" ,
27- )
28- def grdclip (grid , outgrid : str | None = None , ** kwargs ) -> xr .DataArray | None :
67+ @use_alias (R = "region" , V = "verbose" )
68+ @kwargs_to_strings (R = "sequence" )
69+ def grdclip (
70+ grid ,
71+ outgrid : str | None = None ,
72+ above : Sequence [float ] | None = None ,
73+ below : Sequence [float ] | None = None ,
74+ between : Sequence [float ] | Sequence [Sequence [float ]] | None = None ,
75+ new : Sequence [float ] | Sequence [Sequence [float ]] | None = None ,
76+ ** kwargs ,
77+ ) -> xr .DataArray | None :
2978 r"""
3079 Clip the range of grid values.
3180
32- Produce a clipped ``outgrid`` or :class:`xarray.DataArray` version of the
33- input ``grid`` file.
81+ This function operates on the values of a grid. It can:
82+
83+ - Set values smaller than a threshold to a new value
84+ - Set values larger than a threshold to a new value
85+ - Set values within a range to a new value
86+ - Replace individual values with a new value
3487
35- The parameters ``above`` and ``below`` allow for a given value to be set
36- for values above or below a set amount, respectively. This allows for
37- extreme values in a grid, such as points below a certain depth when
38- plotting Earth relief, to all be set to the same value .
88+ Such operations are useful when you want all of a continent or an ocean to fall into
89+ one color or gray shade in image processing, when clipping of the range of data
90+ values is required, or for reclassification of data values. The values can be any
91+ number or even NaN (Not a Number) .
3992
4093 Full option list at :gmt-docs:`grdclip.html`
4194
@@ -46,19 +99,23 @@ def grdclip(grid, outgrid: str | None = None, **kwargs) -> xr.DataArray | None:
4699 {grid}
47100 {outgrid}
48101 {region}
49- above : str or list
50- [*high*, *above*].
51- Set all data[i] > *high* to *above*.
52- below : str or list
53- [*low*, *below*].
54- Set all data[i] < *low* to *below*.
55- between : str or list
56- [*low*, *high*, *between*].
57- Set all data[i] >= *low* and <= *high* to *between*.
58- new : str or list
59- [*old*, *new*].
60- Set all data[i] == *old* to *new*. This is mostly useful when
61- your data are known to be integer values.
102+ above
103+ Pass a sequence of two values in the form of (*high*, *above*), to set all node
104+ values greater than *high* to *above*.
105+ below
106+ Pass a sequence of two values in the form of (*low*, *below*) to set all node
107+ values less than *low* to *below*.
108+ between
109+ Pass a sequence of three values in the form of (*low*, *high*, *between*) to set
110+ all node values between *low* and *high* to *between*. It can also accept a
111+ sequence of sequences (e.g., list of lists or 2-D numpy array) to set different
112+ values for different ranges.
113+ new
114+ Pass a sequence of two values in the form of (*old*, *new*) to replace all node
115+ values equal to *old* with *new*. It can also accept a sequence of sequences
116+ (e.g., list of lists or 2-D numpy array) to replace different old values with
117+ different new values. This is mostly useful when your data are known to be
118+ integer values.
62119 {verbose}
63120
64121 Returns
@@ -88,6 +145,19 @@ def grdclip(grid, outgrid: str | None = None, **kwargs) -> xr.DataArray | None:
88145 >>> [new_grid.data.min(), new_grid.data.max()]
89146 [0.0, 10000.0]
90147 """
148+ if all (v is None for v in (above , below , between , new )):
149+ msg = (
150+ "Must specify at least one of the following parameters: " ,
151+ "'above', 'below', 'between', or 'new'." ,
152+ )
153+ raise GMTInvalidInput (msg )
154+
155+ # Parse the -S option.
156+ kwargs ["Sa" ] = _parse_sequence ("above" , above , size = 2 )
157+ kwargs ["Sb" ] = _parse_sequence ("below" , below , size = 2 )
158+ kwargs ["Si" ] = _parse_sequence ("between" , between , size = 3 , ndim = 2 )
159+ kwargs ["Sr" ] = _parse_sequence ("new" , new , size = 2 , ndim = 2 )
160+
91161 with Session () as lib :
92162 with (
93163 lib .virtualfile_in (check_kind = "raster" , data = grid ) as vingrd ,
0 commit comments