Skip to content

Commit 43badcd

Browse files
akshmakovleouieda
authored andcommitted
Add grdcontour wrapper (#225)
Implements the `BasePlotting.grdcontour` method.
1 parent c4708e0 commit 43badcd

10 files changed

+185
-4
lines changed

doc/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Plotting data and laying out the map:
2424
Figure.coast
2525
Figure.plot
2626
Figure.contour
27+
Figure.grdcontour
2728
Figure.grdimage
2829
Figure.logo
2930

gmt/base_plotting.py

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,82 @@ def coast(self, **kwargs):
126126
lib.call_module("coast", build_arg_string(kwargs))
127127

128128
@fmt_docstring
129-
@use_alias(R="region", J="projection", B="frame", I="shading", C="cmap")
129+
@use_alias(
130+
A="annotation",
131+
B="frame",
132+
C="interval",
133+
G="label_placement",
134+
J="projection",
135+
L="limit",
136+
Q="cut",
137+
R="region",
138+
S="resample",
139+
U="logo",
140+
W="pen",
141+
)
142+
@kwargs_to_strings(R="sequence", L="sequence", A="sequence_plus")
143+
def grdcontour(self, grid, **kwargs):
144+
"""
145+
Convert grids or images to contours and plot them on maps
146+
147+
Takes a grid file name or an xarray.DataArray object as input.
148+
149+
{gmt_module_docs}
150+
151+
{aliases}
152+
153+
Parameters
154+
----------
155+
grid : str or xarray.DataArray
156+
The file name of the input grid or the grid loaded as a DataArray.
157+
C : str or int
158+
Specify the contour lines to generate.
159+
160+
- The filename of a `CPT` file where the color boundaries will
161+
be used as contour levels.
162+
- The filename of a 2 (or 3) column file containing the contour
163+
levels (col 1), (C)ontour or (A)nnotate (col 2), and optional
164+
angle (col 3)
165+
- A fixed contour interval ``cont_int`` or a single contour with
166+
``+[cont_int]``
167+
A : str, int, or list
168+
Specify or disable annotated contour levels, modifies annotated
169+
contours specified in ``-C``.
170+
171+
- Specify a fixed annotation interval ``annot_int`` or a
172+
single annotation level ``+[annot_int]``
173+
- Disable all annotation with ``'-'``
174+
- Optional label modifers can be specifed as a single string
175+
``'[annot_int]+e'`` or with a list of options
176+
``([annot_int], 'e', 'f10p', 'gred')``.
177+
L : str or list of 2 ints
178+
Do no draw contours below `low` or above `high`, specify as string
179+
``'[low]/[high]'`` or list ``[low,high]``.
180+
Q : string or int
181+
Do not draw contours with less than `cut` number of points.
182+
S : string or int
183+
Resample smoothing factor.
184+
{J}
185+
{R}
186+
{B}
187+
{G}
188+
{W}
189+
"""
190+
kwargs = self._preprocess(**kwargs)
191+
kind = data_kind(grid, None, None)
192+
with Session() as lib:
193+
if kind == "file":
194+
file_context = dummy_context(grid)
195+
elif kind == "grid":
196+
file_context = lib.virtualfile_from_grid(grid)
197+
else:
198+
raise GMTInvalidInput("Unrecognized data type: {}".format(type(grid)))
199+
with file_context as fname:
200+
arg_str = " ".join([fname, build_arg_string(kwargs)])
201+
lib.call_module("grdcontour", arg_str)
202+
203+
@fmt_docstring
204+
@use_alias(R="region", J="projection", W="pen", B="frame", I="shading", C="cmap")
130205
@kwargs_to_strings(R="sequence")
131206
def grdimage(self, grid, **kwargs):
132207
"""

gmt/helpers/decorators.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ def kwargs_to_strings(convert_bools=True, **conversions):
221221
* 'sequence': transforms a sequence (list, tuple) into a ``'/'`` separated
222222
string
223223
* 'sequence_comma': transforms a sequence into a ``','`` separated string
224+
* 'sequence_plus': transforms a sequence into a ``'+'`` separated string
224225
225226
Parameters
226227
----------
@@ -262,15 +263,15 @@ def kwargs_to_strings(convert_bools=True, **conversions):
262263
args: 123
263264
264265
"""
265-
valid_conversions = ["sequence", "sequence_comma"]
266+
valid_conversions = ["sequence", "sequence_comma", "sequence_plus"]
266267

267268
for arg, fmt in conversions.items():
268269
if fmt not in valid_conversions:
269270
raise GMTInvalidInput(
270271
"Invalid conversion type '{}' for argument '{}'.".format(fmt, arg)
271272
)
272273

273-
separators = {"sequence": "/", "sequence_comma": ","}
274+
separators = {"sequence": "/", "sequence_comma": ",", "sequence_plus": "+"}
274275

275276
# Make the actual decorator function
276277
def converter(module_func):
@@ -284,7 +285,7 @@ def new_module(*args, **kwargs):
284285
for arg, fmt in conversions.items():
285286
if arg in kwargs:
286287
value = kwargs[arg]
287-
issequence = fmt in ("sequence", "sequence_comma")
288+
issequence = fmt in ("sequence", "sequence_comma", "sequence_plus")
288289
if issequence and is_nonstr_iter(value):
289290
kwargs[arg] = separators[fmt].join(
290291
"{}".format(item) for item in value
208 KB
Loading
164 KB
Loading
Loading
216 KB
Loading
90.7 KB
Loading

gmt/tests/data/contours.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-6000 C
2+
-5000 C
3+
-4000 A
4+
-3000 C
5+
-2000 C
6+
-1000 C
7+
0 A
8+
1000 C
9+
2000 A
10+
3000 C

gmt/tests/test_grdcontour.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
"""
2+
Test Figure.grdcontour
3+
"""
4+
import os
5+
6+
import pytest
7+
import numpy as np
8+
9+
from .. import Figure
10+
from ..exceptions import GMTInvalidInput
11+
from ..datasets import load_earth_relief
12+
13+
14+
TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
15+
TEST_CONTOUR_FILE = os.path.join(TEST_DATA_DIR, "contours.txt")
16+
17+
18+
@pytest.mark.mpl_image_compare
19+
def test_grdcontour():
20+
"""Plot a contour image using an xarray grid
21+
with fixed contour interval
22+
"""
23+
grid = load_earth_relief()
24+
fig = Figure()
25+
fig.grdcontour(grid, interval="1000", projection="W0/6i")
26+
return fig
27+
28+
29+
@pytest.mark.mpl_image_compare
30+
def test_grdcontour_labels():
31+
"""Plot a contour image using a xarray grid
32+
with contour labels and alternate colors
33+
"""
34+
grid = load_earth_relief()
35+
fig = Figure()
36+
fig.grdcontour(
37+
grid,
38+
interval="1000",
39+
annotation="5000",
40+
projection="W0/6i",
41+
pen=["a1p,red", "c0.5p,black"],
42+
label_placement="d3i",
43+
)
44+
return fig
45+
46+
47+
@pytest.mark.mpl_image_compare
48+
def test_grdcontour_slice():
49+
"Plot an contour image using an xarray grid that has been sliced"
50+
grid = load_earth_relief().sel(lat=slice(-30, 30))
51+
fig = Figure()
52+
fig.grdcontour(grid, interval="1000", projection="M6i")
53+
return fig
54+
55+
56+
@pytest.mark.mpl_image_compare
57+
def test_grdcontour_file():
58+
"Plot a contour image using grid file input"
59+
fig = Figure()
60+
fig.grdcontour(
61+
"@earth_relief_60m",
62+
interval="1000",
63+
limit="0",
64+
pen="0.5p,black",
65+
region=[-180, 180, -70, 70],
66+
projection="M10i",
67+
)
68+
return fig
69+
70+
71+
@pytest.mark.mpl_image_compare
72+
def test_grdcontour_interval_file_full_opts():
73+
""" Plot based on external contour level file """
74+
fig = Figure()
75+
comargs = {
76+
"region": [-161.5, -154, 18.5, 23],
77+
"interval": TEST_CONTOUR_FILE,
78+
"grid": "@earth_relief_10m",
79+
"resample": "100",
80+
"projection": "M6i",
81+
"cut": 10,
82+
}
83+
84+
fig.grdcontour(**comargs, limit=(-25000, -1), pen=["a1p,blue", "c0.5p,blue"])
85+
86+
fig.grdcontour(**comargs, limit="0", pen=["a1p,black", "c0.5p,black"])
87+
return fig
88+
89+
90+
def test_grdcontour_fails():
91+
"Should fail for unrecognized input"
92+
fig = Figure()
93+
with pytest.raises(GMTInvalidInput):
94+
fig.grdcontour(np.arange(20).reshape((4, 5)))

0 commit comments

Comments
 (0)