From 3777b07776bbf1582955db66fff16689c83d72bb Mon Sep 17 00:00:00 2001 From: Jamie Quinn Date: Thu, 8 Jul 2021 15:34:48 +0100 Subject: [PATCH 01/23] Add implementation of nearneighbor The implementation mirrors that of the already implemented surface. The documentation has been cobbled together from similar portions in surface and from the [official GMT documentation on nearneighbor](https://docs.generic-mapping-tools.org/latest/nearneighbor.html). Additional long-form flags have been added, reflecting the flags particularly useful for nearneighbor, mainly `-Ssearch_radius`, `-Eempty` and `-Nsectors`. Tests have been blatently copied from those testing surface, since the two functions should operate broadly similarly. --- pygmt/__init__.py | 1 + pygmt/src/__init__.py | 1 + pygmt/src/nearneighbor.py | 131 +++++++++++++++++++++++++++++++ pygmt/tests/test_nearneighbor.py | 119 ++++++++++++++++++++++++++++ 4 files changed, 252 insertions(+) create mode 100644 pygmt/src/nearneighbor.py create mode 100644 pygmt/tests/test_nearneighbor.py diff --git a/pygmt/__init__.py b/pygmt/__init__.py index 972f6474286..cf77ff4b730 100644 --- a/pygmt/__init__.py +++ b/pygmt/__init__.py @@ -43,6 +43,7 @@ grdtrack, info, makecpt, + nearneighbor, surface, which, x2sys_cross, diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index f8bae667f02..4355bdb147d 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -29,6 +29,7 @@ from pygmt.src.logo import logo from pygmt.src.makecpt import makecpt from pygmt.src.meca import meca +from pygmt.src.nearneighbor import nearneighbor from pygmt.src.plot import plot from pygmt.src.plot3d import plot3d from pygmt.src.rose import rose diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py new file mode 100644 index 00000000000..2ae6a225795 --- /dev/null +++ b/pygmt/src/nearneighbor.py @@ -0,0 +1,131 @@ +""" +nearneighbor - Grid table data using a "Nearest neighbor" algorithm +""" + +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( + I="spacing", + R="region", + V="verbose", + G="outfile", + a="aspatial", + f="coltypes", + r="registration", + S="search_radius", + E="empty", + N="sectors", +) +@kwargs_to_strings(R="sequence") +def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): + r""" + Grid table data using a "Nearest neighbor" algorithm + + **nearneighbor** reads arbitrarily located (*x,y,z*\ [,\ *w*]) triples + [quadruplets] and uses a nearest neighbor algorithm to assign a weighted + average value to each node that has one or more data points within a search + radius centered on the node with adequate coverage across a subset of the + chosen sectors. The node value is computed as a weighted mean of the + nearest point from each sector inside the search radius. + + Takes a matrix, xyz triples, or a file name as input. + + Must provide either ``data`` or ``x``, ``y``, and ``z``. + + Full option list at :gmt-docs:`nearneighbor.html` + + {aliases} + + Parameters + ---------- + x/y/z : 1d arrays + Arrays of x and y coordinates and values z of the data points. + data : str or 2d array + Either a data file name or a 2d numpy array with the tabular data. + + {I} + + region : str or list + *xmin/xmax/ymin/ymax*\[**+r**][**+u**\ *unit*]. + Specify the region of interest. + + search_radius : str + Sets the search radius that determines which data points are considered close to a node. + + outfile : str + Optional. The file name for the output netcdf file with extension .nc + to store the grid in. + + {V} + {a} + {f} + {r} + + empty : str + Optional. Set the value assigned to empty nodes. Defaults to NaN. + + sectors : str + Optional. **\ *sectors*\ [**+m**\ *min_sectors*]\|\ **n** + The circular search area centered on each node is divided into sectors + sectors. Average values will only be computed if there is at least one + value inside each of at least min_sectors of the sectors for a given + node. Nodes that fail this test are assigned the value NaN (but see + -E). If +m is omitted then min_sectors is set to be at least 50% of + sectors (i.e., rounded up to next integer) [Default is a quadrant + search with 100% coverage, i.e., sectors = min_sectors = 4]. Note that + only the nearest value per sector enters into the averaging; the more + distant points are ignored. Alternatively, use -Nn to call GDALʻs + nearest neighbor algorithm instead. + + Returns + ------- + ret: xarray.DataArray or None + Return type depends on whether the ``outfile`` parameter is set: + + - :class:`xarray.DataArray`: if ``outfile`` is not set + - None if ``outfile`` is set (grid output will be stored in file set by + ``outfile``) + """ + + kind = data_kind(data, x, y, z) + if kind == "vectors" and z is None: + raise GMTInvalidInput("Must provide z with x and y.") + + with GMTTempFile(suffix=".nc") as tmpfile: + with Session() as lib: + if kind == "file": + file_context = dummy_context(data) + elif kind == "matrix": + file_context = lib.virtualfile_from_matrix(data) + elif kind == "vectors": + file_context = lib.virtualfile_from_vectors(x, y, z) + else: + raise GMTInvalidInput("Unrecognized data type: {}".format(type(data))) + with file_context as infile: + if "G" not in kwargs.keys(): # if outfile is unset, output to tmpfile + kwargs.update({"G": tmpfile.name}) + outfile = kwargs["G"] + arg_str = " ".join([infile, build_arg_string(kwargs)]) + lib.call_module(module="nearneighbor", args=arg_str) + + if outfile == tmpfile.name: # if user did not set outfile, return DataArray + with xr.open_dataarray(outfile) as dataarray: + result = dataarray.load() + _ = result.gmt # load GMTDataArray accessor information + elif outfile != tmpfile.name: # if user sets an outfile, return None + result = None + + return result diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py new file mode 100644 index 00000000000..6a8cf314d52 --- /dev/null +++ b/pygmt/tests/test_nearneighbor.py @@ -0,0 +1,119 @@ +""" +Tests for nearneighbor. +""" +import os + +import pytest +import xarray as xr +from pygmt import nearneighbor, which +from pygmt.datasets import load_sample_bathymetry +from pygmt.exceptions import GMTInvalidInput +from pygmt.helpers import data_kind + +TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") +TEMP_GRID = os.path.join(TEST_DATA_DIR, "tmp_grid.nc") + + +@pytest.fixture(scope="module", name="ship_data") +def fixture_ship_data(): + """ + Load the data from the sample bathymetry dataset. + """ + return load_sample_bathymetry() + + +def test_nearneighbor_input_file(): + """ + Run nearneighbor by passing in a filename. + """ + fname = which("@tut_ship.xyz", download="c") + output = nearneighbor(data=fname, spacing="5m", region=[245, 255, 20, 30], search_radius="10m") + assert isinstance(output, xr.DataArray) + assert output.gmt.registration == 0 # Gridline registration + assert output.gmt.gtype == 0 # Cartesian type + return output + + +def test_nearneighbor_input_data_array(ship_data): + """ + Run nearneighbor by passing in a numpy array into data. + """ + data = ship_data.values # convert pandas.DataFrame to numpy.ndarray + output = nearneighbor(data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m") + assert isinstance(output, xr.DataArray) + return output + + +def test_nearneighbor_input_xyz(ship_data): + """ + Run nearneighbor by passing in x, y, z numpy.ndarrays individually. + """ + output = nearneighbor( + x=ship_data.longitude, + y=ship_data.latitude, + z=ship_data.bathymetry, + spacing="5m", + region=[245, 255, 20, 30], + search_radius="10m", + ) + assert isinstance(output, xr.DataArray) + return output + + +def test_nearneighbor_input_xy_no_z(ship_data): + """ + Run nearneighbor by passing in x and y, but no z. + """ + with pytest.raises(GMTInvalidInput): + nearneighbor( + x=ship_data.longitude, + y=ship_data.latitude, + spacing="5m", + region=[245, 255, 20, 30], + search_radius="10m", + ) + + +def test_nearneighbor_wrong_kind_of_input(ship_data): + """ + Run nearneighbor using grid input that is not file/matrix/vectors. + """ + data = ship_data.bathymetry.to_xarray() # convert pandas.Series to xarray.DataArray + assert data_kind(data) == "grid" + with pytest.raises(GMTInvalidInput): + nearneighbor(data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m") + + +def test_nearneighbor_with_outfile_param(ship_data): + """ + Run nearneighbor with the -Goutputfile.nc parameter. + """ + data = ship_data.values # convert pandas.DataFrame to numpy.ndarray + try: + output = nearneighbor( + data=data, spacing="5m", region=[245, 255, 20, 30], outfile=TEMP_GRID, search_radius="10m" + ) + assert output is None # check that output is None since outfile is set + assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path + with xr.open_dataarray(TEMP_GRID) as grid: + assert isinstance(grid, xr.DataArray) # ensure netcdf grid loads ok + finally: + os.remove(path=TEMP_GRID) + return output + + +def test_nearneighbor_short_aliases(ship_data): + """ + Run nearneighbor using short aliases -I for spacing, -R for region, -G for + outfile, -S for search radius. + """ + data = ship_data.values # convert pandas.DataFrame to numpy.ndarray + try: + output = nearneighbor(data=data, I="5m", R=[245, 255, 20, 30], G=TEMP_GRID, S="10m") + assert output is None # check that output is None since outfile is set + assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path + with xr.open_dataarray(TEMP_GRID) as grid: + assert isinstance(grid, xr.DataArray) # ensure netcdf grid loads ok + finally: + os.remove(path=TEMP_GRID) + return output From 0ef1683e36e6a8405bc5f83a0b6c8f68073f28cb Mon Sep 17 00:00:00 2001 From: Jamie Quinn Date: Thu, 8 Jul 2021 15:46:04 +0100 Subject: [PATCH 02/23] Improve formatting --- pygmt/src/nearneighbor.py | 5 +++-- pygmt/tests/test_nearneighbor.py | 22 +++++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 2ae6a225795..91f51535714 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -39,7 +39,7 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): average value to each node that has one or more data points within a search radius centered on the node with adequate coverage across a subset of the chosen sectors. The node value is computed as a weighted mean of the - nearest point from each sector inside the search radius. + nearest point from each sector inside the search radius. Takes a matrix, xyz triples, or a file name as input. @@ -63,7 +63,8 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): Specify the region of interest. search_radius : str - Sets the search radius that determines which data points are considered close to a node. + Sets the search radius that determines which data points are considered + close to a node. outfile : str Optional. The file name for the output netcdf file with extension .nc diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index 6a8cf314d52..ac95038fb71 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -27,7 +27,9 @@ def test_nearneighbor_input_file(): Run nearneighbor by passing in a filename. """ fname = which("@tut_ship.xyz", download="c") - output = nearneighbor(data=fname, spacing="5m", region=[245, 255, 20, 30], search_radius="10m") + output = nearneighbor( + data=fname, spacing="5m", region=[245, 255, 20, 30], search_radius="10m" + ) assert isinstance(output, xr.DataArray) assert output.gmt.registration == 0 # Gridline registration assert output.gmt.gtype == 0 # Cartesian type @@ -39,7 +41,9 @@ def test_nearneighbor_input_data_array(ship_data): Run nearneighbor by passing in a numpy array into data. """ data = ship_data.values # convert pandas.DataFrame to numpy.ndarray - output = nearneighbor(data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m") + output = nearneighbor( + data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m" + ) assert isinstance(output, xr.DataArray) return output @@ -81,7 +85,9 @@ def test_nearneighbor_wrong_kind_of_input(ship_data): data = ship_data.bathymetry.to_xarray() # convert pandas.Series to xarray.DataArray assert data_kind(data) == "grid" with pytest.raises(GMTInvalidInput): - nearneighbor(data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m") + nearneighbor( + data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m" + ) def test_nearneighbor_with_outfile_param(ship_data): @@ -91,7 +97,11 @@ def test_nearneighbor_with_outfile_param(ship_data): data = ship_data.values # convert pandas.DataFrame to numpy.ndarray try: output = nearneighbor( - data=data, spacing="5m", region=[245, 255, 20, 30], outfile=TEMP_GRID, search_radius="10m" + data=data, + spacing="5m", + region=[245, 255, 20, 30], + outfile=TEMP_GRID, + search_radius="10m", ) assert output is None # check that output is None since outfile is set assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path @@ -109,7 +119,9 @@ def test_nearneighbor_short_aliases(ship_data): """ data = ship_data.values # convert pandas.DataFrame to numpy.ndarray try: - output = nearneighbor(data=data, I="5m", R=[245, 255, 20, 30], G=TEMP_GRID, S="10m") + output = nearneighbor( + data=data, I="5m", R=[245, 255, 20, 30], G=TEMP_GRID, S="10m" + ) assert output is None # check that output is None since outfile is set assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path with xr.open_dataarray(TEMP_GRID) as grid: From 1fccc07603c835e0b23627bce1fd1257e8fc3721 Mon Sep 17 00:00:00 2001 From: Jamie Quinn Date: Thu, 8 Jul 2021 15:47:21 +0100 Subject: [PATCH 03/23] Add nearneighbor to API index --- doc/api/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 40ab49ac430..05de5a478e3 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -81,6 +81,7 @@ Operations on tabular data: blockmean blockmedian + nearneighbor surface Operations on grids: From 91c17075d03f194abcc6a8bc36f4bed6ef7a3789 Mon Sep 17 00:00:00 2001 From: Jamie J Quinn Date: Tue, 13 Jul 2021 11:41:24 +0100 Subject: [PATCH 04/23] Apply suggestions from code review There are many pieces of older code mirroring those found in the implementation of `surface`. These have since been updating in other parts of pyGMT. Most of the review suggestions modernise this PR. Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/src/nearneighbor.py | 44 ++++++++++++++++++-------------- pygmt/tests/test_nearneighbor.py | 43 ++++++++++--------------------- 2 files changed, 39 insertions(+), 48 deletions(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 91f51535714..2aa4dd0d6ae 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -18,16 +18,16 @@ @fmt_docstring @use_alias( + E="empty", + G="outfile", I="spacing", + N="sectors", R="region", + S="search_radius", V="verbose", - G="outfile", a="aspatial", f="coltypes", r="registration", - S="search_radius", - E="empty", - N="sectors", ) @kwargs_to_strings(R="sequence") def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): @@ -39,7 +39,17 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): average value to each node that has one or more data points within a search radius centered on the node with adequate coverage across a subset of the chosen sectors. The node value is computed as a weighted mean of the - nearest point from each sector inside the search radius. + nearest point from each sector inside the search radius. The weighting + function and the averaging used is given by: + + .. math:: + w(r_i) = \frac{{w_i}}{{1 + d(r_i) ^ 2}}, + \quad d(r) = \frac {{3r}}{{R}}, + \quad \bar{{z}} = \frac{{\sum_i^n w(r_i) z_i}}{{\sum_i^n w(r_i)}} + + where :math:`n` is the number of data points that satisfy the selection + criteria and :math:`r_i` is the distance from the node to the *i*'th data + point. If no data weights are supplied then :math:`w_i = 1`. Takes a matrix, xyz triples, or a file name as input. @@ -70,11 +80,6 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): Optional. The file name for the output netcdf file with extension .nc to store the grid in. - {V} - {a} - {f} - {r} - empty : str Optional. Set the value assigned to empty nodes. Defaults to NaN. @@ -91,6 +96,11 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): distant points are ignored. Alternatively, use -Nn to call GDALʻs nearest neighbor algorithm instead. + {V} + {a} + {f} + {r} + Returns ------- ret: xarray.DataArray or None @@ -107,15 +117,11 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): with GMTTempFile(suffix=".nc") as tmpfile: with Session() as lib: - if kind == "file": - file_context = dummy_context(data) - elif kind == "matrix": - file_context = lib.virtualfile_from_matrix(data) - elif kind == "vectors": - file_context = lib.virtualfile_from_vectors(x, y, z) - else: - raise GMTInvalidInput("Unrecognized data type: {}".format(type(data))) - with file_context as infile: + # Choose how data will be passed into the module + table_context = lib.virtualfile_from_data( + check_kind="vector", data=data, x=x, y=y, z=z + ) + with table_context as infile: if "G" not in kwargs.keys(): # if outfile is unset, output to tmpfile kwargs.update({"G": tmpfile.name}) outfile = kwargs["G"] diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index ac95038fb71..4944172c844 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -3,15 +3,13 @@ """ import os +import numpy.testing as npt import pytest import xarray as xr from pygmt import nearneighbor, which from pygmt.datasets import load_sample_bathymetry from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import data_kind - -TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") -TEMP_GRID = os.path.join(TEST_DATA_DIR, "tmp_grid.nc") +from pygmt.helpers import GMTTempFile, data_kind @pytest.fixture(scope="module", name="ship_data") @@ -33,6 +31,8 @@ def test_nearneighbor_input_file(): assert isinstance(output, xr.DataArray) assert output.gmt.registration == 0 # Gridline registration assert output.gmt.gtype == 0 # Cartesian type + assert output.shape == (121, 121) + npt.assert_allclose(output.mean(), -2378.2385) return output @@ -45,6 +45,8 @@ def test_nearneighbor_input_data_array(ship_data): data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m" ) assert isinstance(output, xr.DataArray) + assert output.shape == (121, 121) + npt.assert_allclose(output.mean(), -2378.2385) return output @@ -61,6 +63,8 @@ def test_nearneighbor_input_xyz(ship_data): search_radius="10m", ) assert isinstance(output, xr.DataArray) + assert output.shape == (121, 121) + npt.assert_allclose(output.mean(), -2378.2385) return output @@ -95,37 +99,18 @@ def test_nearneighbor_with_outfile_param(ship_data): Run nearneighbor with the -Goutputfile.nc parameter. """ data = ship_data.values # convert pandas.DataFrame to numpy.ndarray - try: + with GMTTempFile() as tmpfile: output = nearneighbor( data=data, spacing="5m", region=[245, 255, 20, 30], - outfile=TEMP_GRID, + outfile=tmpfile.name, search_radius="10m", ) assert output is None # check that output is None since outfile is set - assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path - with xr.open_dataarray(TEMP_GRID) as grid: - assert isinstance(grid, xr.DataArray) # ensure netcdf grid loads ok - finally: - os.remove(path=TEMP_GRID) - return output - - -def test_nearneighbor_short_aliases(ship_data): - """ - Run nearneighbor using short aliases -I for spacing, -R for region, -G for - outfile, -S for search radius. - """ - data = ship_data.values # convert pandas.DataFrame to numpy.ndarray - try: - output = nearneighbor( - data=data, I="5m", R=[245, 255, 20, 30], G=TEMP_GRID, S="10m" - ) - assert output is None # check that output is None since outfile is set - assert os.path.exists(path=TEMP_GRID) # check that outfile exists at path - with xr.open_dataarray(TEMP_GRID) as grid: + assert os.path.exists(path=tmpfile.name) # check that outfile exists at path + with xr.open_dataarray(tmpfile.name) as grid: assert isinstance(grid, xr.DataArray) # ensure netcdf grid loads ok - finally: - os.remove(path=TEMP_GRID) + assert grid.shape == (121, 121) + npt.assert_allclose(grid.mean(), -2378.2385) return output From 51fa503987dfe349aabdf93f79b1723d3d2c9689 Mon Sep 17 00:00:00 2001 From: Jamie Quinn Date: Fri, 16 Jul 2021 17:49:45 +0100 Subject: [PATCH 05/23] Fix unused import --- pygmt/src/nearneighbor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 2aa4dd0d6ae..9e125e7ae2a 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -9,7 +9,6 @@ GMTTempFile, build_arg_string, data_kind, - dummy_context, fmt_docstring, kwargs_to_strings, use_alias, From 0fbc83aca121b4688ddcb57506473948b35d1dbe Mon Sep 17 00:00:00 2001 From: Jamie J Quinn Date: Wed, 4 Aug 2021 11:34:44 +0100 Subject: [PATCH 06/23] Update pygmt/src/nearneighbor.py Enhance nearneighbour documentation Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/src/nearneighbor.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 9e125e7ae2a..27ca3919811 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -83,17 +83,17 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): Optional. Set the value assigned to empty nodes. Defaults to NaN. sectors : str - Optional. **\ *sectors*\ [**+m**\ *min_sectors*]\|\ **n** - The circular search area centered on each node is divided into sectors - sectors. Average values will only be computed if there is at least one - value inside each of at least min_sectors of the sectors for a given - node. Nodes that fail this test are assigned the value NaN (but see - -E). If +m is omitted then min_sectors is set to be at least 50% of - sectors (i.e., rounded up to next integer) [Default is a quadrant - search with 100% coverage, i.e., sectors = min_sectors = 4]. Note that - only the nearest value per sector enters into the averaging; the more - distant points are ignored. Alternatively, use -Nn to call GDALʻs - nearest neighbor algorithm instead. + *sectors*\ [**+m**\ *min_sectors*]\|\ **n**. + Optional. The circular search area centered on each node is divided + into *sectors* sectors. Average values will only be computed if there + is *at least* one value inside each of at least *min_sectors* of the + sectors for a given node. Nodes that fail this test are assigned the + value NaN (but see ``empty``). If +m is omitted then *min_sectors* is + set to be at least 50% of *sectors* (i.e., rounded up to next integer) + [Default is a quadrant search with 100% coverage, i.e., *sectors* = + *min_sectors* = 4]. Note that only the nearest value per sector enters + into the averaging; the more distant points are ignored. Alternatively, + use ``sectors="n"`` to call GDALʻs nearest neighbor algorithm instead. {V} {a} From 4ae19cbb35e693d69d9c3ceda2dd36096e7dfb85 Mon Sep 17 00:00:00 2001 From: Jamie Quinn Date: Wed, 4 Aug 2021 11:49:43 +0100 Subject: [PATCH 07/23] Add similar figure to that found in GMTs nearneighbor documentation --- pygmt/src/nearneighbor.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 27ca3919811..b64564aff77 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -50,6 +50,15 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): criteria and :math:`r_i` is the distance from the node to the *i*'th data point. If no data weights are supplied then :math:`w_i = 1`. + .. figure:: https://docs.generic-mapping-tools.org/latest/_images/GMT_nearneighbor.png + :width: 300 px + :align: center + + Search geometry includes the search radius (R) which limits the points + considered and the number of sectors (here 4), which restricts how points inside + the search radius contribute to the value at the node. Only the closest point + in each sector (red circles) contribute to the weighted estimate. + Takes a matrix, xyz triples, or a file name as input. Must provide either ``data`` or ``x``, ``y``, and ``z``. From cedcda2202b3f6f36e1c6ff47f1f123a9c064fce Mon Sep 17 00:00:00 2001 From: Jamie J Quinn Date: Wed, 8 Sep 2021 20:02:21 +0100 Subject: [PATCH 08/23] Don't use which in test Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/tests/test_nearneighbor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index 4944172c844..8d1e6f3900d 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -24,9 +24,8 @@ def test_nearneighbor_input_file(): """ Run nearneighbor by passing in a filename. """ - fname = which("@tut_ship.xyz", download="c") output = nearneighbor( - data=fname, spacing="5m", region=[245, 255, 20, 30], search_radius="10m" + data="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30], search_radius="10m" ) assert isinstance(output, xr.DataArray) assert output.gmt.registration == 0 # Gridline registration From a4bb96e9ad294072e56c967ac6489b7c6c272aab Mon Sep 17 00:00:00 2001 From: Jamie J Quinn Date: Wed, 8 Sep 2021 20:02:41 +0100 Subject: [PATCH 09/23] Name test more appropriately Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/tests/test_nearneighbor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index 8d1e6f3900d..5340ea20d9f 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -35,7 +35,7 @@ def test_nearneighbor_input_file(): return output -def test_nearneighbor_input_data_array(ship_data): +def test_nearneighbor_input_numpy_array(ship_data): """ Run nearneighbor by passing in a numpy array into data. """ From fc43c85976b95b73d622621e25295cec51e67bbf Mon Sep 17 00:00:00 2001 From: Jamie J Quinn Date: Wed, 8 Sep 2021 20:03:03 +0100 Subject: [PATCH 10/23] Add newer common options Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/src/nearneighbor.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index b64564aff77..f9e67efc88e 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -25,8 +25,15 @@ S="search_radius", V="verbose", a="aspatial", + b="binary", + d="nodata", + e="find", f="coltypes", + g="gap", + h="header", + i="incols", r="registration", + w="wrap", ) @kwargs_to_strings(R="sequence") def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): From 57aba71e644e0747afd86d763aa49c4e5f20c3de Mon Sep 17 00:00:00 2001 From: Jamie J Quinn Date: Wed, 8 Sep 2021 20:03:09 +0100 Subject: [PATCH 11/23] Update pygmt/src/nearneighbor.py Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/src/nearneighbor.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index f9e67efc88e..d0471c5d4f6 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -113,8 +113,15 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): {V} {a} + {b} + {d} + {e} {f} + {g} + {h} + {i} {r} + {w} Returns ------- From 620e99a225f424ea524e5ca58f84c8b5b132a87a Mon Sep 17 00:00:00 2001 From: Jamie Quinn Date: Wed, 8 Sep 2021 20:12:09 +0100 Subject: [PATCH 12/23] Remove unused import --- pygmt/tests/test_nearneighbor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index 5340ea20d9f..1ea38702685 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -6,7 +6,7 @@ import numpy.testing as npt import pytest import xarray as xr -from pygmt import nearneighbor, which +from pygmt import nearneighbor from pygmt.datasets import load_sample_bathymetry from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import GMTTempFile, data_kind From 62d452274af459bf5bd4a0376eaaa232a8748f2e Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Wed, 15 Sep 2021 22:46:14 +1200 Subject: [PATCH 13/23] Apply suggestions from code review Co-authored-by: Meghan Jones Co-authored-by: Michael Grund <23025878+michaelgrund@users.noreply.github.com> --- pygmt/src/nearneighbor.py | 35 +++++++++++++------------------- pygmt/tests/test_nearneighbor.py | 13 +++++++----- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index d0471c5d4f6..cf1c1786e7f 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -2,7 +2,6 @@ nearneighbor - Grid table data using a "Nearest neighbor" algorithm """ -import xarray as xr from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( @@ -13,12 +12,13 @@ kwargs_to_strings, use_alias, ) +from pygmt.io import load_dataarray @fmt_docstring @use_alias( E="empty", - G="outfile", + G="outgrid", I="spacing", N="sectors", R="region", @@ -36,7 +36,7 @@ w="wrap", ) @kwargs_to_strings(R="sequence") -def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): +def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): r""" Grid table data using a "Nearest neighbor" algorithm @@ -76,22 +76,22 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): Parameters ---------- + data : str or {table-like} + Pass in (x, y, z) or (longitude, latitude, elevation) values by + providing a file name to an ASCII data table, a 2D + {table-classes}. x/y/z : 1d arrays Arrays of x and y coordinates and values z of the data points. - data : str or 2d array - Either a data file name or a 2d numpy array with the tabular data. {I} - region : str or list - *xmin/xmax/ymin/ymax*\[**+r**][**+u**\ *unit*]. - Specify the region of interest. + {R} search_radius : str Sets the search radius that determines which data points are considered close to a node. - outfile : str + outgrid : str Optional. The file name for the output netcdf file with extension .nc to store the grid in. @@ -126,11 +126,11 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): Returns ------- ret: xarray.DataArray or None - Return type depends on whether the ``outfile`` parameter is set: + Return type depends on whether the ``outgrid`` parameter is set: - - :class:`xarray.DataArray`: if ``outfile`` is not set - - None if ``outfile`` is set (grid output will be stored in file set by - ``outfile``) + - :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(data, x, y, z) @@ -150,11 +150,4 @@ def nearneighbor(x=None, y=None, z=None, data=None, **kwargs): arg_str = " ".join([infile, build_arg_string(kwargs)]) lib.call_module(module="nearneighbor", args=arg_str) - if outfile == tmpfile.name: # if user did not set outfile, return DataArray - with xr.open_dataarray(outfile) as dataarray: - result = dataarray.load() - _ = result.gmt # load GMTDataArray accessor information - elif outfile != tmpfile.name: # if user sets an outfile, return None - result = None - - return result + return load_dataarray(outgrid) if outgrid == tmpfile.name else None diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index 1ea38702685..6a230e7f1a1 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -25,7 +25,10 @@ def test_nearneighbor_input_file(): Run nearneighbor by passing in a filename. """ output = nearneighbor( - data="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30], search_radius="10m" + data="@tut_ship.xyz", + spacing="5m", + region=[245, 255, 20, 30], + search_radius="10m", ) assert isinstance(output, xr.DataArray) assert output.gmt.registration == 0 # Gridline registration @@ -93,7 +96,7 @@ def test_nearneighbor_wrong_kind_of_input(ship_data): ) -def test_nearneighbor_with_outfile_param(ship_data): +def test_nearneighbor_with_outgrid_param(ship_data): """ Run nearneighbor with the -Goutputfile.nc parameter. """ @@ -103,11 +106,11 @@ def test_nearneighbor_with_outfile_param(ship_data): data=data, spacing="5m", region=[245, 255, 20, 30], - outfile=tmpfile.name, + outgrid=tmpfile.name, search_radius="10m", ) - assert output is None # check that output is None since outfile is set - assert os.path.exists(path=tmpfile.name) # check that outfile exists at path + assert output is None # check that output is None since outgrid is set + assert os.path.exists(path=tmpfile.name) # check that outgrid exists at path with xr.open_dataarray(tmpfile.name) as grid: assert isinstance(grid, xr.DataArray) # ensure netcdf grid loads ok assert grid.shape == (121, 121) From c22ebb0f2502b2d8189e7eb27416ec20b56308b9 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Wed, 15 Sep 2021 22:57:30 +1200 Subject: [PATCH 14/23] Fix lint errors --- pygmt/src/nearneighbor.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index cf1c1786e7f..90a9f7f8884 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -57,14 +57,15 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): criteria and :math:`r_i` is the distance from the node to the *i*'th data point. If no data weights are supplied then :math:`w_i = 1`. - .. figure:: https://docs.generic-mapping-tools.org/latest/_images/GMT_nearneighbor.png + .. figure:: :gmt-docs:`_images/GMT_nearneighbor.png` :width: 300 px :align: center Search geometry includes the search radius (R) which limits the points - considered and the number of sectors (here 4), which restricts how points inside - the search radius contribute to the value at the node. Only the closest point - in each sector (red circles) contribute to the weighted estimate. + considered and the number of sectors (here 4), which restricts how + points inside the search radius contribute to the value at the node. + Only the closest point in each sector (red circles) contribute to the + weighted estimate. Takes a matrix, xyz triples, or a file name as input. @@ -144,9 +145,9 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): check_kind="vector", data=data, x=x, y=y, z=z ) with table_context as infile: - if "G" not in kwargs.keys(): # if outfile is unset, output to tmpfile + if "G" not in kwargs.keys(): # if outgrid is unset, output to tmpfile kwargs.update({"G": tmpfile.name}) - outfile = kwargs["G"] + outgrid = kwargs["G"] arg_str = " ".join([infile, build_arg_string(kwargs)]) lib.call_module(module="nearneighbor", args=arg_str) From 38cb0f70ad82cd21101c5e48e06371222b7aef3e Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 16 Sep 2021 12:48:16 +1200 Subject: [PATCH 15/23] Set incols (i) to use sequence_comma Co-Authored-By: Dongdong Tian --- pygmt/src/nearneighbor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 90a9f7f8884..6c126fdc3fb 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -35,7 +35,7 @@ r="registration", w="wrap", ) -@kwargs_to_strings(R="sequence") +@kwargs_to_strings(R="sequence", i="sequence_comma") def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): r""" Grid table data using a "Nearest neighbor" algorithm From d09d63d9e4f94373545ff4c3944bf09d872560cd Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 16 Sep 2021 12:51:06 +1200 Subject: [PATCH 16/23] Remove test_nearneighbor_input_xy_no_z Following #1478. --- pygmt/tests/test_nearneighbor.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index 6a230e7f1a1..ca0be740e8e 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -70,20 +70,6 @@ def test_nearneighbor_input_xyz(ship_data): return output -def test_nearneighbor_input_xy_no_z(ship_data): - """ - Run nearneighbor by passing in x and y, but no z. - """ - with pytest.raises(GMTInvalidInput): - nearneighbor( - x=ship_data.longitude, - y=ship_data.latitude, - spacing="5m", - region=[245, 255, 20, 30], - search_radius="10m", - ) - - def test_nearneighbor_wrong_kind_of_input(ship_data): """ Run nearneighbor using grid input that is not file/matrix/vectors. From 3e33f3ad95434527032c3719f1faefa22c773e6d Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 17 Sep 2021 16:24:07 +1200 Subject: [PATCH 17/23] Ignore flake8 error using noqa W505 --- pygmt/src/nearneighbor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 6c126fdc3fb..30b42e71d1d 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -57,7 +57,7 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): criteria and :math:`r_i` is the distance from the node to the *i*'th data point. If no data weights are supplied then :math:`w_i = 1`. - .. figure:: :gmt-docs:`_images/GMT_nearneighbor.png` + .. figure:: https://docs.generic-mapping-tools.org/latest/_images/GMT_nearneighbor.png # noqa: W505 :width: 300 px :align: center From 6118d23179ae0df728f20a4096c9c4852dc80630 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:11:50 +1200 Subject: [PATCH 18/23] Fix incorrect indentation --- pygmt/src/nearneighbor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 30b42e71d1d..4d6324c93f6 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -151,4 +151,4 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): arg_str = " ".join([infile, build_arg_string(kwargs)]) lib.call_module(module="nearneighbor", args=arg_str) - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + return load_dataarray(outgrid) if outgrid == tmpfile.name else None From f344cf507e201c8765e87d7d2c3c9619a80d8b9b Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:16:02 +1200 Subject: [PATCH 19/23] Shorten line length to under 100 using the dev image --- pygmt/src/nearneighbor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 4d6324c93f6..a42544b0749 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -57,7 +57,7 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): criteria and :math:`r_i` is the distance from the node to the *i*'th data point. If no data weights are supplied then :math:`w_i = 1`. - .. figure:: https://docs.generic-mapping-tools.org/latest/_images/GMT_nearneighbor.png # noqa: W505 + .. figure:: https://docs.generic-mapping-tools.org/dev/_images/GMT_nearneighbor.png # noqa: W505 :width: 300 px :align: center From a0da121d5efaf28725b713a8f7fd5b472047a5a1 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Sun, 19 Sep 2021 10:15:54 +1200 Subject: [PATCH 20/23] Apply suggestions from code review Co-Authored-By: Dongdong Tian --- pygmt/src/nearneighbor.py | 8 +------- pygmt/tests/test_nearneighbor.py | 9 ++------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index a42544b0749..a1fcbc7947f 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -7,7 +7,6 @@ from pygmt.helpers import ( GMTTempFile, build_arg_string, - data_kind, fmt_docstring, kwargs_to_strings, use_alias, @@ -133,16 +132,11 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): - None if ``outgrid`` is set (grid output will be stored in file set by ``outgrid``) """ - - kind = data_kind(data, x, y, z) - if kind == "vectors" and z is None: - raise GMTInvalidInput("Must provide z with x and y.") - with GMTTempFile(suffix=".nc") as tmpfile: with Session() as lib: # Choose how data will be passed into the module table_context = lib.virtualfile_from_data( - check_kind="vector", data=data, x=x, y=y, z=z + check_kind="vector", data=data, x=x, y=y, z=z, required_z=True ) with table_context as infile: if "G" not in kwargs.keys(): # if outgrid is unset, output to tmpfile diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index ca0be740e8e..12f92ff1343 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -35,7 +35,6 @@ def test_nearneighbor_input_file(): assert output.gmt.gtype == 0 # Cartesian type assert output.shape == (121, 121) npt.assert_allclose(output.mean(), -2378.2385) - return output def test_nearneighbor_input_numpy_array(ship_data): @@ -49,7 +48,6 @@ def test_nearneighbor_input_numpy_array(ship_data): assert isinstance(output, xr.DataArray) assert output.shape == (121, 121) npt.assert_allclose(output.mean(), -2378.2385) - return output def test_nearneighbor_input_xyz(ship_data): @@ -67,7 +65,6 @@ def test_nearneighbor_input_xyz(ship_data): assert isinstance(output, xr.DataArray) assert output.shape == (121, 121) npt.assert_allclose(output.mean(), -2378.2385) - return output def test_nearneighbor_wrong_kind_of_input(ship_data): @@ -84,12 +81,11 @@ def test_nearneighbor_wrong_kind_of_input(ship_data): def test_nearneighbor_with_outgrid_param(ship_data): """ - Run nearneighbor with the -Goutputfile.nc parameter. + Run nearneighbor with the 'outgrid' parameter. """ - data = ship_data.values # convert pandas.DataFrame to numpy.ndarray with GMTTempFile() as tmpfile: output = nearneighbor( - data=data, + data=ship_data, spacing="5m", region=[245, 255, 20, 30], outgrid=tmpfile.name, @@ -101,4 +97,3 @@ def test_nearneighbor_with_outgrid_param(ship_data): assert isinstance(grid, xr.DataArray) # ensure netcdf grid loads ok assert grid.shape == (121, 121) npt.assert_allclose(grid.mean(), -2378.2385) - return output From 334939609e8d3b5533f4f81398237accba2d5bb7 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Sun, 19 Sep 2021 10:30:22 +1200 Subject: [PATCH 21/23] Merge two tests using pytest parametrize Check that numpy.array and xarray.Dataset inputs work. --- pygmt/tests/test_nearneighbor.py | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/pygmt/tests/test_nearneighbor.py b/pygmt/tests/test_nearneighbor.py index 12f92ff1343..5722aa5e71a 100644 --- a/pygmt/tests/test_nearneighbor.py +++ b/pygmt/tests/test_nearneighbor.py @@ -3,6 +3,7 @@ """ import os +import numpy as np import numpy.testing as npt import pytest import xarray as xr @@ -20,32 +21,18 @@ def fixture_ship_data(): return load_sample_bathymetry() -def test_nearneighbor_input_file(): +@pytest.mark.parametrize("array_func", [np.array, xr.Dataset]) +def test_nearneighbor_input_data(array_func, ship_data): """ - Run nearneighbor by passing in a filename. + Run nearneighbor by passing in a numpy.array or xarray.Dataset. """ - output = nearneighbor( - data="@tut_ship.xyz", - spacing="5m", - region=[245, 255, 20, 30], - search_radius="10m", - ) - assert isinstance(output, xr.DataArray) - assert output.gmt.registration == 0 # Gridline registration - assert output.gmt.gtype == 0 # Cartesian type - assert output.shape == (121, 121) - npt.assert_allclose(output.mean(), -2378.2385) - - -def test_nearneighbor_input_numpy_array(ship_data): - """ - Run nearneighbor by passing in a numpy array into data. - """ - data = ship_data.values # convert pandas.DataFrame to numpy.ndarray + data = array_func(ship_data) output = nearneighbor( data=data, spacing="5m", region=[245, 255, 20, 30], search_radius="10m" ) assert isinstance(output, xr.DataArray) + assert output.gmt.registration == 0 # Gridline registration + assert output.gmt.gtype == 1 # Geographic type assert output.shape == (121, 121) npt.assert_allclose(output.mean(), -2378.2385) From 523e5ecc137c8d1c2ae09e2d46b14f6c0c97d86a Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Tue, 21 Sep 2021 10:39:04 +1200 Subject: [PATCH 22/23] Remove unused GMTInvalidInput import --- pygmt/src/nearneighbor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index a1fcbc7947f..58cf92143bb 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -3,7 +3,6 @@ """ from pygmt.clib import Session -from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( GMTTempFile, build_arg_string, From 3857cf9efb15d8b8709521391bb6e56af63ef94f Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 23 Sep 2021 11:54:24 +1200 Subject: [PATCH 23/23] Typo fixes Co-Authored-By: Dongdong Tian --- pygmt/src/nearneighbor.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 58cf92143bb..496c9bef87a 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -103,12 +103,13 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): into *sectors* sectors. Average values will only be computed if there is *at least* one value inside each of at least *min_sectors* of the sectors for a given node. Nodes that fail this test are assigned the - value NaN (but see ``empty``). If +m is omitted then *min_sectors* is - set to be at least 50% of *sectors* (i.e., rounded up to next integer) - [Default is a quadrant search with 100% coverage, i.e., *sectors* = - *min_sectors* = 4]. Note that only the nearest value per sector enters - into the averaging; the more distant points are ignored. Alternatively, - use ``sectors="n"`` to call GDALʻs nearest neighbor algorithm instead. + value NaN (but see ``empty``). If **+m** is omitted then *min_sectors* + is set to be at least 50% of *sectors* (i.e., rounded up to next + integer) [Default is a quadrant search with 100% coverage, i.e., + *sectors* = *min_sectors* = 4]. Note that only the nearest value per + sector enters into the averaging; the more distant points are ignored. + Alternatively, use ``sectors="n"`` to call GDAL's nearest neighbor + algorithm instead. {V} {a}