-
Notifications
You must be signed in to change notification settings - Fork 229
Wrap grdcut #492
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
Wrap grdcut #492
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
02c7b0e
Wrap grdcut
seisman f1e27c4
Fix the grdcut test
seisman b578f85
Rename parameter ingrid to grid
seisman 071d463
Raise a NotImplementedError
seisman 6ce0450
Fix the NotImplementedError in the test
seisman 004c40c
Force xarray to load the output grid into memory
seisman 9364469
Update pygmt/modules.py
seisman 2a58920
Update doc/api/index.rst
seisman 6ca442b
Move grdcut to gridops.py
seisman 3e8530e
Do not add a blank line in modules.py
seisman 7d5a5d0
Merge branch 'master' into wrap-grdcut
seisman 99f5d82
Fix the grdcut tests for the gridline-registered grids
seisman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,6 +70,7 @@ Operations on grids: | |
.. autosummary:: | ||
:toctree: generated | ||
|
||
grdcut | ||
grdinfo | ||
grdtrack | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
""" | ||
GMT modules for grid operations | ||
""" | ||
|
||
import xarray as xr | ||
|
||
|
||
from .clib import Session | ||
from .helpers import ( | ||
build_arg_string, | ||
fmt_docstring, | ||
kwargs_to_strings, | ||
GMTTempFile, | ||
use_alias, | ||
data_kind, | ||
dummy_context, | ||
) | ||
from .exceptions import GMTInvalidInput | ||
|
||
|
||
@fmt_docstring | ||
@use_alias( | ||
G="outgrid", | ||
R="region", | ||
J="projection", | ||
N="extend", | ||
S="circ_subregion", | ||
Z="z_subregion", | ||
) | ||
@kwargs_to_strings(R="sequence") | ||
def grdcut(grid, **kwargs): | ||
""" | ||
Extract subregion from a grid. | ||
|
||
Produce a new *outgrid* file which is a subregion of *grid*. The | ||
subregion is specified with *region*; the specified range must not exceed | ||
the range of *grid* (but see *extend*). If in doubt, run | ||
:meth:`pygmt.grdinfo` to check range. Alternatively, define the subregion | ||
indirectly via a range check on the node values or via distances from a | ||
given point. Finally, you can give *projection* for oblique projections to | ||
determine the corresponding rectangular *region* setting that will give a | ||
grid that fully covers the oblique domain. | ||
|
||
Full option list at :gmt-docs:`grdcut.html` | ||
|
||
{aliases} | ||
|
||
Parameters | ||
---------- | ||
grid : str | ||
The name of the input grid file. | ||
outgrid : str or None | ||
The name of the output netCDF file with extension .nc to store the grid | ||
in. | ||
{J} | ||
{R} | ||
extend : bool or int or float | ||
Allow grid to be extended if new *region* exceeds existing boundaries. | ||
Give a value to initialize nodes outside current region. | ||
circ_subregion : str | ||
``'lon/lat/radius[unit][+n]'``. | ||
Specify an origin (*lon* and *lat*) and *radius*; append a distance | ||
*unit* and we determine the corresponding rectangular region so that | ||
all grid nodes on or inside the circle are contained in the subset. | ||
If **+n** is appended we set all nodes outside the circle to NaN. | ||
z_subregion : str | ||
``'[min/max][+n|N|r]'``. | ||
Determine a new rectangular region so that all nodes outside this | ||
region are also outside the given z-range [-inf/+inf]. To indicate no | ||
limit on *min* or *max* only, specify a hyphen (-). Normally, any NaNs | ||
encountered are simply skipped and not considered in the | ||
range-decision. Append **+n** to consider a NaN to be outside the given | ||
z-range. This means the new subset will be NaN-free. Alternatively, | ||
append **+r** to consider NaNs to be within the data range. In this | ||
case we stop shrinking the boundaries once a NaN is found [Default | ||
simply skips NaNs when making the range decision]. Finally, if your | ||
core subset grid is surrounded by rows and/or columns that are all | ||
NaNs, append **+N** to strip off such columns before (optionally) | ||
considering the range of the core subset for further reduction of the | ||
area. | ||
|
||
Returns | ||
------- | ||
ret: xarray.DataArray or None | ||
Return type depends on whether the *outgrid* parameter is set: | ||
|
||
- xarray.DataArray if *outgrid* is not set | ||
- None if *outgrid* is set (grid output will be stored in *outgrid*) | ||
""" | ||
kind = data_kind(grid) | ||
|
||
with GMTTempFile(suffix=".nc") as tmpfile: | ||
with Session() as lib: | ||
if kind == "file": | ||
file_context = dummy_context(grid) | ||
elif kind == "grid": | ||
raise NotImplementedError( | ||
"xarray.DataArray is not supported as the input grid yet!" | ||
) | ||
# file_context = lib.virtualfile_from_grid(grid) | ||
# See https://github.com/GenericMappingTools/gmt/pull/3532 | ||
# for a feature request. | ||
else: | ||
raise GMTInvalidInput("Unrecognized data type: {}".format(type(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("grdcut", arg_str) | ||
|
||
if outgrid == tmpfile.name: # if user did not set outgrid, return DataArray | ||
with xr.open_dataarray(outgrid) as dataarray: | ||
result = dataarray.load() | ||
else: | ||
result = None # if user sets an outgrid, return None | ||
|
||
return result |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
""" | ||
Tests for grdcut | ||
""" | ||
import os | ||
import numpy as np | ||
import pytest | ||
import xarray as xr | ||
|
||
from .. import grdcut, grdinfo | ||
from ..datasets import load_earth_relief | ||
from ..exceptions import GMTInvalidInput | ||
from ..helpers import GMTTempFile | ||
|
||
|
||
def test_grdcut_file_in_file_out(): | ||
"grduct an input grid file, and output to a grid file" | ||
with GMTTempFile(suffix=".nc") as tmpfile: | ||
result = grdcut("@earth_relief_01d", outgrid=tmpfile.name, region="0/180/0/90") | ||
assert result is None # return value is None | ||
assert os.path.exists(path=tmpfile.name) # check that outgrid exists | ||
result = grdinfo(tmpfile.name, C=True) | ||
assert result == "0 180 0 90 -8592.5 5559 1 1 181 91\n" | ||
|
||
|
||
def test_grdcut_file_in_dataarray_out(): | ||
"grdcut an input grid file, and output as DataArray" | ||
outgrid = grdcut("@earth_relief_01d", region="0/180/0/90") | ||
assert isinstance(outgrid, xr.DataArray) | ||
# check information of the output grid | ||
# the '@earth_relief_01d' is in pixel registration, so the grid range is | ||
# not exactly 0/180/0/90 | ||
assert outgrid.coords["lat"].data.min() == 0.0 | ||
assert outgrid.coords["lat"].data.max() == 90.0 | ||
assert outgrid.coords["lon"].data.min() == 0.0 | ||
assert outgrid.coords["lon"].data.max() == 180.0 | ||
assert outgrid.data.min() == -8592.5 | ||
assert outgrid.data.max() == 5559 | ||
assert outgrid.sizes["lat"] == 91 | ||
assert outgrid.sizes["lon"] == 181 | ||
|
||
|
||
def test_grdcut_dataarray_in_file_out(): | ||
"grdcut an input DataArray, and output to a grid file" | ||
# Not supported yet. | ||
# See https://github.com/GenericMappingTools/gmt/pull/3532 | ||
|
||
|
||
def test_grdcut_dataarray_in_dataarray_out(): | ||
"grdcut an input DataArray, and output to a grid file" | ||
# Not supported yet. | ||
# See https://github.com/GenericMappingTools/gmt/pull/3532 | ||
|
||
|
||
def test_grdcut_dataarray_in_fail(): | ||
"Make sure that grdcut fails correctly if DataArray is the input grid" | ||
with pytest.raises(NotImplementedError): | ||
grid = load_earth_relief() | ||
grdcut(grid, region="0/180/0/90") | ||
|
||
|
||
def test_grdcut_fails(): | ||
"Check that grdcut fails correctly" | ||
with pytest.raises(GMTInvalidInput): | ||
grdcut(np.arange(10).reshape((5, 2))) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After starting #494, I'm starting to wonder if we should have a
pygmt.open
function to load NetCDF files with thenode_offset
attribute inside the xarray.DataArray, as needed if we're going to start chaining operations as you mentioned in #476 (comment).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand the GMT C API correctly, GMT has its own data types (internally) for grids, CPT and data tables. It also provides API functions
GMT_Read_Data
andGMT_Write_Data
, and two special modulesgmtread
andgmtwrite
which I presume can read and write any GMT data types. Perhaps in the future we need to wrap these GMT data types. In this case,pygmt.read()
andpygmt.write()
may make more sense.