From eb1028e2bd602fbe384c42d0c275c98462a9502f Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 23 May 2021 08:30:23 +0100 Subject: [PATCH 1/3] add xyz2grd.py --- doc/api/index.rst | 1 + pygmt/__init__.py | 1 + pygmt/src/__init__.py | 1 + pygmt/src/xyz2grd.py | 87 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 pygmt/src/xyz2grd.py diff --git a/doc/api/index.rst b/doc/api/index.rst index fc69a95d1e2..fcda91042ee 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -93,6 +93,7 @@ Operations on grids: grdfill grdfilter grdtrack + xyz2grd Crossover analysis with x2sys: diff --git a/pygmt/__init__.py b/pygmt/__init__.py index 5cbea0fc853..3041bf3f21c 100644 --- a/pygmt/__init__.py +++ b/pygmt/__init__.py @@ -45,6 +45,7 @@ which, x2sys_cross, x2sys_init, + xyz2grd, ) # Get semantic version through setuptools-scm diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index b4855a37737..6330ecb8f93 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -39,3 +39,4 @@ from pygmt.src.wiggle import wiggle from pygmt.src.x2sys_cross import x2sys_cross from pygmt.src.x2sys_init import x2sys_init +from pygmt.src.xyz2grd import xyz2grd diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py new file mode 100644 index 00000000000..2f89afd2e7d --- /dev/null +++ b/pygmt/src/xyz2grd.py @@ -0,0 +1,87 @@ +""" +xyz2grd - Create a grid file from an xyz table. +""" +import xarray as xr +from pygmt.clib import Session +from pygmt.exceptions import GMTInvalidInput +from pygmt.helpers import ( + GMTTempFile, + build_arg_string, + fmt_docstring, + kwargs_to_strings, + use_alias, +) + + +@fmt_docstring +@use_alias( + G="outgrid", + R="region", + I="increment", +) +@kwargs_to_strings(R="sequence") +def xyz2grd(table, **kwargs): + r""" + Create a grid file with set values for land and water. + Read the selected shoreline database and create a grid to specify which + nodes in the specified grid are over land or over water. The nodes defined + by the selected region and lattice spacing + will be set according to one of two criteria: (1) land vs water, or + (2) the more detailed (hierarchical) ocean vs land vs lake + vs island vs pond. + Full option list at :gmt-docs:`grdlandmask.html` + {aliases} + Parameters + ---------- + outgrid : str or None + The name of the output netCDF file with extension .nc to store the grid + in. + increment : str + *xinc*\ [**+e**\|\ **n**][/\ *yinc*\ [**+e**\|\ **n**]]. + *x_inc* [and optionally *y_inc*] is the grid spacing. **Geographical + (degrees) coordinates**: Optionally, append a increment unit. Choose + among **m** to indicate arc minutes or **s** to indicate arc seconds. + If one of the units **e**, **f**, **k**, **M**, **n** or **u** is + appended instead, the increment is assumed to be given in meter, foot, + km, mile, nautical mile or US survey foot, respectively, and will be + converted to the equivalent degrees longitude at the middle latitude + of the region. If *y_inc* is given but set to 0 it will be reset equal + to *x_inc*; otherwise it will be converted to degrees latitude. **All + coordinates**: If **+e** is appended then the corresponding max + *x* (*east*) or *y* (*north*) may be slightly adjusted to fit exactly + the given increment [by default the increment may be adjusted slightly + to fit the given domain]. Finally, instead of giving an increment you + may specify the *number of nodes* desired by appending **+n** to the + supplied integer argument; the increment is then recalculated from the + number of nodes, the *registration*, and the domain. The resulting + increment value depends on whether you have selected a + gridline-registered or pixel-registered grid. + {R} + + 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``) + """ + if "I" not in kwargs.keys() or "R" not in kwargs.keys(): + raise GMTInvalidInput("Region and increment must be specified.") + with GMTTempFile(suffix=".nc") as tmpfile: + with Session() as lib: + if "G" not in kwargs.keys(): # if outgrid is unset, output to tempfile + kwargs.update({"G": tmpfile.name}) + outgrid = kwargs["G"] + arg_str = build_arg_string(kwargs) + arg_str = " ".join([table, arg_str]) + lib.call_module("xyz2grd", 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 From 3c8195e820a32a972390b20f58404317bcba9862 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 23 May 2021 11:05:50 +0100 Subject: [PATCH 2/3] add context manager to accept virtual files --- pygmt/src/xyz2grd.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index 2f89afd2e7d..0006f196590 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -70,12 +70,14 @@ def xyz2grd(table, **kwargs): raise GMTInvalidInput("Region and increment must be specified.") with GMTTempFile(suffix=".nc") as tmpfile: with Session() as lib: + file_context = lib.virtualfile_from_data(data=table) if "G" not in kwargs.keys(): # if outgrid is unset, output to tempfile kwargs.update({"G": tmpfile.name}) outgrid = kwargs["G"] - arg_str = build_arg_string(kwargs) - arg_str = " ".join([table, arg_str]) - lib.call_module("xyz2grd", arg_str) + with file_context as infile: + arg_str = build_arg_string(kwargs) + arg_str = " ".join([infile, arg_str]) + lib.call_module("xyz2grd", arg_str) if outgrid == tmpfile.name: # if user did not set outgrid, return DataArray with xr.open_dataarray(outgrid) as dataarray: From 082d4869a2cf07a93ed8e626a9335ef07eabe692 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 23 May 2021 11:59:37 +0100 Subject: [PATCH 3/3] fix virtual file handling for numpy array --- pygmt/src/xyz2grd.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index 0006f196590..34e09faff4f 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -7,6 +7,8 @@ from pygmt.helpers import ( GMTTempFile, build_arg_string, + data_kind, + dummy_context, fmt_docstring, kwargs_to_strings, use_alias, @@ -68,13 +70,19 @@ def xyz2grd(table, **kwargs): """ if "I" not in kwargs.keys() or "R" not in kwargs.keys(): raise GMTInvalidInput("Region and increment must be specified.") + kind = data_kind(table) with GMTTempFile(suffix=".nc") as tmpfile: with Session() as lib: - file_context = lib.virtualfile_from_data(data=table) - if "G" not in kwargs.keys(): # if outgrid is unset, output to tempfile - kwargs.update({"G": tmpfile.name}) - outgrid = kwargs["G"] + if kind == "file": + file_context = dummy_context(table) + elif kind == "matrix": + file_context = lib.virtualfile_from_matrix(matrix=table) + else: + raise GMTInvalidInput("Unrecognized data type: {}".format(type(table))) 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 = build_arg_string(kwargs) arg_str = " ".join([infile, arg_str]) lib.call_module("xyz2grd", arg_str)