From 4d37512e4974846e7afa85b3f3e842173d62646f Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 11 Jul 2021 14:33:26 +0100 Subject: [PATCH 01/13] add sphdistance.py and import statements --- pygmt/__init__.py | 1 + pygmt/src/__init__.py | 1 + pygmt/src/sphdistance.py | 69 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 pygmt/src/sphdistance.py diff --git a/pygmt/__init__.py b/pygmt/__init__.py index 972f6474286..f1f12e2cf99 100644 --- a/pygmt/__init__.py +++ b/pygmt/__init__.py @@ -43,6 +43,7 @@ grdtrack, info, makecpt, + sphdistance, surface, which, x2sys_cross, diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index f8bae667f02..69d757c77e3 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -32,6 +32,7 @@ from pygmt.src.plot import plot from pygmt.src.plot3d import plot3d from pygmt.src.rose import rose +from pygmt.src.sphdistance import sphdistance from pygmt.src.solar import solar from pygmt.src.subplot import set_panel, subplot from pygmt.src.surface import surface diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py new file mode 100644 index 00000000000..3409fee27b9 --- /dev/null +++ b/pygmt/src/sphdistance.py @@ -0,0 +1,69 @@ +""" +sphdistance - Create Voronoi distance, node, +or natural nearest-neighbor grid on a sphere +""" +import xarray as xr +from pygmt.clib import Session +from pygmt.exceptions import GMTInvalidInput +from pygmt.helpers import ( + GMTTempFile, + build_arg_string, + data_kind, + dummy_context, + fmt_docstring, + kwargs_to_strings, + use_alias, +) + + +@fmt_docstring +@use_alias( + G="outgrid", + R="region", + I="increment", +) +@kwargs_to_strings(R="sequence") +def sphdistance(table, **kwargs): + r""" + {aliases} + Parameters + ---------- + outgrid : str or None + The name of the output netCDF file with extension .nc to store the grid + in. + {I} + {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``) + """ + kind = data_kind(table) + with GMTTempFile(suffix=".nc") as tmpfile: + with Session() as lib: + 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("sphdistance", 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 \ No newline at end of file From 5b829b191e39600ea85ac3a53d89832e43c142d9 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 11 Jul 2021 14:54:54 +0100 Subject: [PATCH 02/13] add sphdistance to index.rst --- doc/api/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 40ab49ac430..507eae60ea9 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -95,6 +95,7 @@ Operations on grids: grdlandmask grdgradient grdtrack + sphdistance Crossover analysis with x2sys: From 41491db0f5873863d4b829c1576332f08f70103c Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 11 Jul 2021 14:57:52 +0100 Subject: [PATCH 03/13] add if statement for required arguments --- pygmt/src/__init__.py | 2 +- pygmt/src/sphdistance.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index 69d757c77e3..d920b4e5158 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -32,8 +32,8 @@ from pygmt.src.plot import plot from pygmt.src.plot3d import plot3d from pygmt.src.rose import rose -from pygmt.src.sphdistance import sphdistance from pygmt.src.solar import solar +from pygmt.src.sphdistance import sphdistance from pygmt.src.subplot import set_panel, subplot from pygmt.src.surface import surface from pygmt.src.text import text_ as text # "text" is an argument within "text_" diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index 3409fee27b9..b5a7bbb666d 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -42,6 +42,8 @@ def sphdistance(table, **kwargs): - 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("Both 'region' and 'increment' must be specified.") kind = data_kind(table) with GMTTempFile(suffix=".nc") as tmpfile: with Session() as lib: @@ -66,4 +68,4 @@ def sphdistance(table, **kwargs): else: result = None # if user sets an outgrid, return None - return result \ No newline at end of file + return result From 6a5801440b51f79473b480b47cf6272a81bf398e Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 11 Jul 2021 15:17:51 +0100 Subject: [PATCH 04/13] add sequence for increment in sphdistance.py --- pygmt/src/sphdistance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index b5a7bbb666d..26775d1c378 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -22,7 +22,7 @@ R="region", I="increment", ) -@kwargs_to_strings(R="sequence") +@kwargs_to_strings(I="sequence", R="sequence") def sphdistance(table, **kwargs): r""" {aliases} From 164d414ff81cb289b0923055c785f8a1d9a22c8b Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sun, 11 Jul 2021 15:24:37 +0100 Subject: [PATCH 05/13] add test_sphdistance.py --- pygmt/tests/test_sphdistance.py | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 pygmt/tests/test_sphdistance.py diff --git a/pygmt/tests/test_sphdistance.py b/pygmt/tests/test_sphdistance.py new file mode 100644 index 00000000000..f4d18546883 --- /dev/null +++ b/pygmt/tests/test_sphdistance.py @@ -0,0 +1,57 @@ +""" +Tests for sphdistance. +""" +import os + +import numpy as np +import pytest +from pygmt import grdinfo, sphdistance +from pygmt.exceptions import GMTInvalidInput +from pygmt.helpers import GMTTempFile + + +@pytest.fixture(scope="module", name="array") +def fixture_table(): + """ + Load the table data. + """ + coords_list = [[85.5, 22.3], [82.3, 22.6], [85.8, 22.4], [86.5, 23.3]] + return np.array(coords_list) + + +def test_sphdistance_outgrid(array): + """ + Test sphdistance with a set outgrid. + """ + with GMTTempFile(suffix=".nc") as tmpfile: + result = sphdistance( + table=array, outgrid=tmpfile.name, increment=1, region=[82, 87, 22, 24] + ) + assert result is None # return value is None + assert os.path.exists(path=tmpfile.name) # check that outgrid exists + + +def test_sphdistance_no_outgrid(array): + """ + Test sphdistance with no set outgrid. + """ + temp_grid = sphdistance(table=array, increment=[1, 2], region=[82, 87, 22, 24]) + assert temp_grid.dims == ("lat", "lon") + assert temp_grid.gmt.gtype == 1 # Geographic grid + assert temp_grid.gmt.registration == 0 # Gridline registration + result = grdinfo(grid=temp_grid, force_scan="a", per_column="n").strip().split() + assert int(result[0]) == 82 # x minimum + assert int(result[1]) == 87 # x maximum + assert int(result[2]) == 22 # y minimum + assert int(result[3]) == 24 # y maximum + assert int(result[6]) == 1 # x increment + assert int(result[7]) == 2 # y increment + + +def test_sphdistance_fails(array): + """ + Check that sphdistance fails correctly when neither increment nor region is + given. + """ + with pytest.raises(GMTInvalidInput): + sphdistance(table=array) From ae2afcf303095281895319c9b8bc99cf04b5dad6 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Mon, 12 Jul 2021 17:40:26 +0100 Subject: [PATCH 06/13] add sphdistance docstring to sphdistance.py --- pygmt/src/sphdistance.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index 26775d1c378..f4c31b0065c 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -19,13 +19,21 @@ @fmt_docstring @use_alias( G="outgrid", - R="region", I="increment", + R="region", ) @kwargs_to_strings(I="sequence", R="sequence") def sphdistance(table, **kwargs): r""" + Create Voroni polygons from lat/long coordinates. + + Reads one or more ASCII [or binary] files (or standard + input) containing lon, lat and performs the construction of Voronoi + polygons. These polygons are then processed to calculate the nearest + distance to each node of the lattice and written to the specified grid. + {aliases} + Parameters ---------- outgrid : str or None From 66748ebc7f5ac9a6165e9746caea870307d54ade Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sat, 7 Aug 2021 08:01:34 +0100 Subject: [PATCH 07/13] add verbose parameter --- pygmt/src/sphdistance.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index f4c31b0065c..f0611d84a8d 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -21,6 +21,7 @@ G="outgrid", I="increment", R="region", + V="verbose", ) @kwargs_to_strings(I="sequence", R="sequence") def sphdistance(table, **kwargs): @@ -41,6 +42,7 @@ def sphdistance(table, **kwargs): in. {I} {R} + {V} Returns ------- From 76dfd9a644870756c22599884d239e0ecd047d86 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 10 Aug 2021 21:04:26 +0100 Subject: [PATCH 08/13] update loading table from virtualfile --- pygmt/src/sphdistance.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index f0611d84a8d..ffb3034259d 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -8,8 +8,6 @@ from pygmt.helpers import ( GMTTempFile, build_arg_string, - data_kind, - dummy_context, fmt_docstring, kwargs_to_strings, use_alias, @@ -54,15 +52,9 @@ def sphdistance(table, **kwargs): """ if "I" not in kwargs.keys() or "R" not in kwargs.keys(): raise GMTInvalidInput("Both 'region' and 'increment' must be specified.") - kind = data_kind(table) with GMTTempFile(suffix=".nc") as tmpfile: with Session() as lib: - 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))) + file_context = lib.virtualfile_from_data(check_kind="vector", data=table) with file_context as infile: if "G" not in kwargs.keys(): # if outgrid is unset, output to tempfile kwargs.update({"G": tmpfile.name}) From d75ada01ce1562b8e0adf656b719402c0e0e0d15 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 2 Sep 2021 12:41:31 +0100 Subject: [PATCH 09/13] Apply suggestions from code review Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/src/sphdistance.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index ffb3034259d..11e7f5c8f15 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -2,7 +2,6 @@ sphdistance - Create Voronoi distance, node, or natural nearest-neighbor grid on a sphere """ -import xarray as xr from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( @@ -12,6 +11,7 @@ kwargs_to_strings, use_alias, ) +from pygmt.io import load_dataarray @fmt_docstring @@ -24,7 +24,7 @@ @kwargs_to_strings(I="sequence", R="sequence") def sphdistance(table, **kwargs): r""" - Create Voroni polygons from lat/long coordinates. + Create Voroni polygons from lat/lon coordinates. Reads one or more ASCII [or binary] files (or standard input) containing lon, lat and performs the construction of Voronoi @@ -63,11 +63,4 @@ def sphdistance(table, **kwargs): arg_str = " ".join([infile, arg_str]) lib.call_module("sphdistance", 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 + return load_dataarray(outgrid) if outgrid == tmpfile.name else None From cef091bf3582a8e6a0c9c217756e68aaaa87c5d7 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 7 Sep 2021 10:42:02 +0100 Subject: [PATCH 10/13] change test format to avoid using grdinfo --- pygmt/tests/test_sphdistance.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pygmt/tests/test_sphdistance.py b/pygmt/tests/test_sphdistance.py index f4d18546883..d232913a39f 100644 --- a/pygmt/tests/test_sphdistance.py +++ b/pygmt/tests/test_sphdistance.py @@ -4,6 +4,7 @@ import os import numpy as np +import numpy.testing as npt import pytest from pygmt import grdinfo, sphdistance from pygmt.exceptions import GMTInvalidInput @@ -39,13 +40,10 @@ def test_sphdistance_no_outgrid(array): assert temp_grid.dims == ("lat", "lon") assert temp_grid.gmt.gtype == 1 # Geographic grid assert temp_grid.gmt.registration == 0 # Gridline registration - result = grdinfo(grid=temp_grid, force_scan="a", per_column="n").strip().split() - assert int(result[0]) == 82 # x minimum - assert int(result[1]) == 87 # x maximum - assert int(result[2]) == 22 # y minimum - assert int(result[3]) == 24 # y maximum - assert int(result[6]) == 1 # x increment - assert int(result[7]) == 2 # y increment + npt.assert_allclose(temp_grid.max(), 232977.546875) + npt.assert_allclose(temp_grid.min(), 0) + npt.assert_allclose(temp_grid.median(), 0) + npt.assert_allclose(temp_grid.mean(), 62469.17) def test_sphdistance_fails(array): From 16d8c060e1b2a2fd4a8f00a290e612d8b2570299 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 7 Sep 2021 10:42:19 +0100 Subject: [PATCH 11/13] remove unused import --- pygmt/tests/test_sphdistance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_sphdistance.py b/pygmt/tests/test_sphdistance.py index d232913a39f..05bde8b9300 100644 --- a/pygmt/tests/test_sphdistance.py +++ b/pygmt/tests/test_sphdistance.py @@ -6,7 +6,7 @@ import numpy as np import numpy.testing as npt import pytest -from pygmt import grdinfo, sphdistance +from pygmt import sphdistance from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import GMTTempFile From b247dc444ec0cc524aa63a69992ab445c5871067 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 9 Sep 2021 05:51:03 -0400 Subject: [PATCH 12/13] Apply suggestions from code review Co-authored-by: Dongdong Tian --- pygmt/src/sphdistance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index 11e7f5c8f15..7ffb781507a 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -17,7 +17,7 @@ @fmt_docstring @use_alias( G="outgrid", - I="increment", + I="spacing", R="region", V="verbose", ) From 5f35b08ae382191d74a28c572031d90b1a9b838a Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 9 Sep 2021 07:25:52 -0400 Subject: [PATCH 13/13] Apply suggestions from code review Co-authored-by: Dongdong Tian --- pygmt/src/sphdistance.py | 2 +- pygmt/tests/test_sphdistance.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index 7ffb781507a..14883e57ce0 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -51,7 +51,7 @@ def sphdistance(table, **kwargs): ``outgrid``) """ if "I" not in kwargs.keys() or "R" not in kwargs.keys(): - raise GMTInvalidInput("Both 'region' and 'increment' must be specified.") + raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.") with GMTTempFile(suffix=".nc") as tmpfile: with Session() as lib: file_context = lib.virtualfile_from_data(check_kind="vector", data=table) diff --git a/pygmt/tests/test_sphdistance.py b/pygmt/tests/test_sphdistance.py index 05bde8b9300..ebdbb13dc2b 100644 --- a/pygmt/tests/test_sphdistance.py +++ b/pygmt/tests/test_sphdistance.py @@ -26,7 +26,7 @@ def test_sphdistance_outgrid(array): """ with GMTTempFile(suffix=".nc") as tmpfile: result = sphdistance( - table=array, outgrid=tmpfile.name, increment=1, region=[82, 87, 22, 24] + table=array, outgrid=tmpfile.name, spacing=1, region=[82, 87, 22, 24] ) assert result is None # return value is None assert os.path.exists(path=tmpfile.name) # check that outgrid exists @@ -36,7 +36,7 @@ def test_sphdistance_no_outgrid(array): """ Test sphdistance with no set outgrid. """ - temp_grid = sphdistance(table=array, increment=[1, 2], region=[82, 87, 22, 24]) + temp_grid = sphdistance(table=array, spacing=[1, 2], region=[82, 87, 22, 24]) assert temp_grid.dims == ("lat", "lon") assert temp_grid.gmt.gtype == 1 # Geographic grid assert temp_grid.gmt.registration == 0 # Gridline registration