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