Skip to content
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

Wrap grdsample #1380

Merged
merged 20 commits into from
Aug 9, 2021
Merged
Show file tree
Hide file tree
Changes from 11 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 @@ -94,6 +94,7 @@ Operations on grids:
grdfilter
grdlandmask
grdgradient
grdsample
grdtrack

Crossover analysis with x2sys:
Expand Down
1 change: 1 addition & 0 deletions pygmt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
grdgradient,
grdinfo,
grdlandmask,
grdsample,
grdtrack,
info,
makecpt,
Expand Down
1 change: 1 addition & 0 deletions pygmt/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from pygmt.src.grdimage import grdimage
from pygmt.src.grdinfo import grdinfo
from pygmt.src.grdlandmask import grdlandmask
from pygmt.src.grdsample import grdsample
from pygmt.src.grdtrack import grdtrack
from pygmt.src.grdview import grdview
from pygmt.src.histogram import histogram
Expand Down
121 changes: 121 additions & 0 deletions pygmt/src/grdsample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""
grdsample - Resample a grid onto a new lattice
"""

import xarray as xr
from pygmt.clib import Session
from pygmt.helpers import (
GMTTempFile,
build_arg_string,
fmt_docstring,
kwargs_to_strings,
use_alias,
)


@fmt_docstring
@use_alias(
G="outgrid",
J="projection",
I="increment",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems other modules (e.g., grdfilter) use the alias spacing rather than increment. We should keep the alias consistent, no?

willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
R="region",
T="translate",
V="verbose",
f="coltypes",
r="registration",
n="interpolation",
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
x="cores",
)
@kwargs_to_strings(I="sequence", R="sequence")
def grdsample(grid, **kwargs):
r"""
Change the registration, spacing, or nodes in a grid file.

This reads a grid file and interpolates it to create a new grid
file. It can change the registration with ``translate`` or
``registration``, change the grid-spacing or number of nodes with
``increment``, and set a new sub-region using ``region``. A bicubic
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
[Default], bilinear, B-spline or nearest-neighbor interpolation is set
with ``interpolation``.

When ``region`` is omitted, the output grid will cover the same region as
the input grid. When ``increment`` is omitted, the grid spacing of the
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
output grid will be the same as the input grid. Either ``registration`` or
``translate`` can be used to change the grid registration. When omitted,
the output grid will have the same registration as the input grid.

{aliases}

Parameters
----------
grid : str or xarray.DataArray
The file name of the input grid or the grid loaded as a DataArray.
outgrid : str or None
The name of the output netCDF file with extension .nc to store the grid
in.
{I}
{R}
translate : bool
Translate between grid and pixel registration; if the input is
grid-registered, the output will be pixel-registered and vice-versa.
interpolation : str
[**b**\|\ **c**\|\ **l**\|\ **n**][**+a**][**+b**\ *BC*][**+c**]
[**+t**\ *threshold*].
Select interpolation mode for grids.

- **b** to use B-spline smoothing.
- **c** to use bicubic interpolation.
- **l** to use bilinear interpolation.
- **n** to use nearest-neighbor value (for example to plot
categorical data).

The following modifiers are supported:

- **+a** to switch off antialiasing (where supported) [default uses
antialiasing].
- **+b** to override boundary conditions used, by appending *g* for
geographic, *p* for periodic, or *n* for natural boundary conditions.
For the latter two you may append **x** or **y** to specify just one
direction, otherwise both are assumed.
- **+c** to clip the interpolated grid to input z-min/z-max
[default may exceed limits].
- **+t** to control how close to nodes with NaNs the interpolation
will go based on *threshold*. A *threshold* of 1.0 requires all
(4 or 16) nodes involved in interpolation to be non-NaN. For example,
0.5 will interpolate about half way from a non-NaN value and 0.1 will
go about 90% of the way [default is 0.5].
weiji14 marked this conversation as resolved.
Show resolved Hide resolved
registration : str or bool
[**g**\ |\ **p**\ ].
Set registration to **g**\ ridline or **p**\ ixel.

{V}
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
{f}
{x}

Returns
-------
ret: xarray.DataArray or None
Return type depends on whether the ``outgrid`` parameter is set:

- :class:`xarray.DataArray` if ``outgrid`` is not set
- None if ``outgrid`` is set (grid output will be stored in file set by
``outgrid``)
"""
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(check_kind="raster", data=grid)
with file_context as infile:
if "G" not in kwargs.keys(): # if outgrid is unset, output to tempfile
kwargs.update({"G": tmpfile.name})
outgrid = kwargs["G"]
arg_str = " ".join([infile, build_arg_string(kwargs)])
lib.call_module("grdsample", arg_str)

if outgrid == tmpfile.name: # if user did not set outgrid, return DataArray
with xr.open_dataarray(outgrid) as dataarray:
result = dataarray.load()
_ = result.gmt # load GMTDataArray accessor information
else:
result = None # if user sets an outgrid, return None

return result
44 changes: 44 additions & 0 deletions pygmt/tests/test_grdsample.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
Tests for grdsample.
"""
import os

import pytest
from pygmt import grdinfo, grdsample
from pygmt.datasets import load_earth_relief
from pygmt.helpers import GMTTempFile


@pytest.fixture(scope="module", name="grid")
def fixture_grid():
"""
Load the grid data from the sample earth_relief file.
"""
return load_earth_relief(
resolution="01d", region=[-5, 5, -5, 5], registration="pixel"
)


def test_grdsample_file_out(grid):
"""
grdsample with an outgrid set and the increment is changed.
"""
with GMTTempFile(suffix=".nc") as tmpfile:
result = grdsample(grid=grid, outgrid=tmpfile.name, increment=[1, 2.5])
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
assert result is None # return value is None
assert os.path.exists(path=tmpfile.name) # check that outgrid exists
result = grdinfo(tmpfile.name, per_column=True).strip().split()
print(result)
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
assert float(result[6]) == 1 # x-increment
assert float(result[7]) == 2.5 # y-increment
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved


def test_grdsample_no_outgrid(grid):
"""
Test grdsample with no set outgrid and applying registration changes.
"""
assert grid.gmt.registration == 1 # Pixel registration
translated_grid = grdsample(grid=grid, translate=True)
assert translated_grid.gmt.registration == 0 # Gridline registration
registration_grid = grdsample(grid=translated_grid, registration="p")
assert registration_grid.gmt.registration == 1 # Pixel registration