Skip to content

grdcontour Implementation #225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Plotting data and laying out the map:
Figure.coast
Figure.plot
Figure.contour
Figure.grdcontour
Figure.grdimage
Figure.logo

Expand Down
77 changes: 76 additions & 1 deletion gmt/base_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,82 @@ def coast(self, **kwargs):
lib.call_module("coast", build_arg_string(kwargs))

@fmt_docstring
@use_alias(R="region", J="projection", B="frame", I="shading", C="cmap")
@use_alias(
A="annotation",
B="frame",
C="interval",
G="label_placement",
J="projection",
L="limit",
Q="cut",
R="region",
S="resample",
U="logo",
W="pen",
)
@kwargs_to_strings(R="sequence", L="sequence", A="sequence_plus")
def grdcontour(self, grid, **kwargs):
"""
Convert grids or images to contours and plot them on maps

Takes a grid file name or an xarray.DataArray object as input.

{gmt_module_docs}

{aliases}

Parameters
----------
grid : str or xarray.DataArray
The file name of the input grid or the grid loaded as a DataArray.
C : str or int
Specify the contour lines to generate.

- The filename of a `CPT` file where the color boundaries will
be used as contour levels.
- The filename of a 2 (or 3) column file containing the contour
levels (col 1), (C)ontour or (A)nnotate (col 2), and optional
angle (col 3)
- A fixed contour interval ``cont_int`` or a single contour with
``+[cont_int]``
A : str, int, or list
Specify or disable annotated contour levels, modifies annotated
contours specified in ``-C``.

- Specify a fixed annotation interval ``annot_int`` or a
single annotation level ``+[annot_int]``
- Disable all annotation with ``'-'``
- Optional label modifers can be specifed as a single string
``'[annot_int]+e'`` or with a list of options
``([annot_int], 'e', 'f10p', 'gred')``.
L : str or list of 2 ints
Do no draw contours below `low` or above `high`, specify as string
``'[low]/[high]'`` or list ``[low,high]``.
Q : string or int
Do not draw contours with less than `cut` number of points.
S : string or int
Resample smoothing factor.
{J}
{R}
{B}
{G}
{W}
"""
kwargs = self._preprocess(**kwargs)
kind = data_kind(grid, None, None)
with Session() as lib:
if kind == "file":
file_context = dummy_context(grid)
elif kind == "grid":
file_context = lib.virtualfile_from_grid(grid)
else:
raise GMTInvalidInput("Unrecognized data type: {}".format(type(grid)))
with file_context as fname:
arg_str = " ".join([fname, build_arg_string(kwargs)])
lib.call_module("grdcontour", arg_str)

@fmt_docstring
@use_alias(R="region", J="projection", W="pen", B="frame", I="shading", C="cmap")
@kwargs_to_strings(R="sequence")
def grdimage(self, grid, **kwargs):
"""
Expand Down
7 changes: 4 additions & 3 deletions gmt/helpers/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ def kwargs_to_strings(convert_bools=True, **conversions):
* 'sequence': transforms a sequence (list, tuple) into a ``'/'`` separated
string
* 'sequence_comma': transforms a sequence into a ``','`` separated string
* 'sequence_plus': transforms a sequence into a ``'+'`` separated string

Parameters
----------
Expand Down Expand Up @@ -262,15 +263,15 @@ def kwargs_to_strings(convert_bools=True, **conversions):
args: 123

"""
valid_conversions = ["sequence", "sequence_comma"]
valid_conversions = ["sequence", "sequence_comma", "sequence_plus"]

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

separators = {"sequence": "/", "sequence_comma": ","}
separators = {"sequence": "/", "sequence_comma": ",", "sequence_plus": "+"}

# Make the actual decorator function
def converter(module_func):
Expand All @@ -284,7 +285,7 @@ def new_module(*args, **kwargs):
for arg, fmt in conversions.items():
if arg in kwargs:
value = kwargs[arg]
issequence = fmt in ("sequence", "sequence_comma")
issequence = fmt in ("sequence", "sequence_comma", "sequence_plus")
if issequence and is_nonstr_iter(value):
kwargs[arg] = separators[fmt].join(
"{}".format(item) for item in value
Expand Down
Binary file added gmt/tests/baseline/test_grdcontour.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gmt/tests/baseline/test_grdcontour_file.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gmt/tests/baseline/test_grdcontour_labels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gmt/tests/baseline/test_grdcontour_slice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions gmt/tests/data/contours.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-6000 C
-5000 C
-4000 A
-3000 C
-2000 C
-1000 C
0 A
1000 C
2000 A
3000 C
94 changes: 94 additions & 0 deletions gmt/tests/test_grdcontour.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""
Test Figure.grdcontour
"""
import os

import pytest
import numpy as np

from .. import Figure
from ..exceptions import GMTInvalidInput
from ..datasets import load_earth_relief


TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
TEST_CONTOUR_FILE = os.path.join(TEST_DATA_DIR, "contours.txt")


@pytest.mark.mpl_image_compare
def test_grdcontour():
"""Plot a contour image using an xarray grid
with fixed contour interval
"""
grid = load_earth_relief()
fig = Figure()
fig.grdcontour(grid, interval="1000", projection="W0/6i")
return fig


@pytest.mark.mpl_image_compare
def test_grdcontour_labels():
"""Plot a contour image using a xarray grid
with contour labels and alternate colors
"""
grid = load_earth_relief()
fig = Figure()
fig.grdcontour(
grid,
interval="1000",
annotation="5000",
projection="W0/6i",
pen=["a1p,red", "c0.5p,black"],
label_placement="d3i",
)
return fig


@pytest.mark.mpl_image_compare
def test_grdcontour_slice():
"Plot an contour image using an xarray grid that has been sliced"
grid = load_earth_relief().sel(lat=slice(-30, 30))
fig = Figure()
fig.grdcontour(grid, interval="1000", projection="M6i")
return fig


@pytest.mark.mpl_image_compare
def test_grdcontour_file():
"Plot a contour image using grid file input"
fig = Figure()
fig.grdcontour(
"@earth_relief_60m",
interval="1000",
limit="0",
pen="0.5p,black",
region=[-180, 180, -70, 70],
projection="M10i",
)
return fig


@pytest.mark.mpl_image_compare
def test_grdcontour_interval_file_full_opts():
""" Plot based on external contour level file """
fig = Figure()
comargs = {
"region": [-161.5, -154, 18.5, 23],
"interval": TEST_CONTOUR_FILE,
"grid": "@earth_relief_10m",
"resample": "100",
"projection": "M6i",
"cut": 10,
}

fig.grdcontour(**comargs, limit=(-25000, -1), pen=["a1p,blue", "c0.5p,blue"])

fig.grdcontour(**comargs, limit="0", pen=["a1p,black", "c0.5p,black"])
return fig


def test_grdcontour_fails():
"Should fail for unrecognized input"
fig = Figure()
with pytest.raises(GMTInvalidInput):
fig.grdcontour(np.arange(20).reshape((4, 5)))