From efa05193d76b1459a4d9c95760e618df2db3b2c2 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 26 May 2021 06:53:11 +0100 Subject: [PATCH 01/27] Create grdvolume.py --- pygmt/src/grdvolume.py | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 pygmt/src/grdvolume.py diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py new file mode 100644 index 00000000000..0f67302686f --- /dev/null +++ b/pygmt/src/grdvolume.py @@ -0,0 +1,46 @@ +""" +grdvolume - Calculate grid volume and area constrained by a contour. +""" +from pygmt.clib import Session +from pygmt.helpers import ( + GMTTempFile, + build_arg_string, + fmt_docstring, + kwargs_to_strings, + use_alias, +) + + +@fmt_docstring +@use_alias( + C="above", + Cr="below", + R="region", + V="verbose", +) +@kwargs_to_strings(C="sequence", R="sequence") +def grdvolume(grid, **kwargs): + r""" + {aliases} + + Parameters + ---------- + grid : str or xarray.DataArray + The file name of the input grid or the grid loaded as a DataArray. + This is the only required parameter. + {R} + {V} + + Returns + ------- + volume : str + A string with the volume between the surface and specified plane. + """ + with GMTTempFile() as outfile: + with Session() as lib: + file_context = lib.virtualfile_from_data(check_kind="raster", data=grid) + with file_context as infile: + arg_str = " ".join([infile, build_arg_string(kwargs)]) + lib.call_module("grdvolume", arg_str) + result = outfile.read() + return result From 19f2fe74755b288279fef2d0fd37a3cf76b37f4c Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 26 May 2021 06:53:21 +0100 Subject: [PATCH 02/27] add grdvolume to imports --- doc/api/index.rst | 1 + pygmt/__init__.py | 1 + pygmt/src/__init__.py | 1 + 3 files changed, 3 insertions(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 1e74629c5af..5bce391e5d8 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -94,6 +94,7 @@ Operations on grids: grdfilter grdgradient grdtrack + grdvolume Crossover analysis with x2sys: diff --git a/pygmt/__init__.py b/pygmt/__init__.py index 57e223d5c14..9b5c5707b16 100644 --- a/pygmt/__init__.py +++ b/pygmt/__init__.py @@ -40,6 +40,7 @@ grdgradient, grdinfo, grdtrack, + grdvolume, info, makecpt, surface, diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index 4e79d0d96f7..123fc43384b 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -20,6 +20,7 @@ from pygmt.src.grdinfo import grdinfo from pygmt.src.grdtrack import grdtrack from pygmt.src.grdview import grdview +from pygmt.src.grdvolume import grdvolume from pygmt.src.histogram import histogram from pygmt.src.image import image from pygmt.src.info import info From d3ed614106078a1125a448903b0ae436cbacdb6c Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 26 May 2021 07:45:39 +0100 Subject: [PATCH 03/27] add unit and slice parameters --- pygmt/src/grdvolume.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index 0f67302686f..02c5567f1b9 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -13,9 +13,11 @@ @fmt_docstring @use_alias( - C="above", - Cr="below", + C="plane", + Cr="outside_volume", + D="slice", R="region", + S="unit", V="verbose", ) @kwargs_to_strings(C="sequence", R="sequence") @@ -40,7 +42,9 @@ def grdvolume(grid, **kwargs): with Session() as lib: file_context = lib.virtualfile_from_data(check_kind="raster", data=grid) with file_context as infile: - arg_str = " ".join([infile, build_arg_string(kwargs)]) + arg_str = " ".join( + [infile, build_arg_string(kwargs), "->" + outfile.name] + ) lib.call_module("grdvolume", arg_str) result = outfile.read() return result From 68fab7ceed26083a07ef23681733c33e8dabe827 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 26 May 2021 10:37:12 +0100 Subject: [PATCH 04/27] add formatting to return array or DataFrame --- pygmt/src/grdvolume.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index 02c5567f1b9..d7f232512e2 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -1,7 +1,10 @@ """ grdvolume - Calculate grid volume and area constrained by a contour. """ +import numpy as np +import pandas as pd from pygmt.clib import Session +from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( GMTTempFile, build_arg_string, @@ -21,7 +24,7 @@ V="verbose", ) @kwargs_to_strings(C="sequence", R="sequence") -def grdvolume(grid, **kwargs): +def grdvolume(grid, data_format="a", **kwargs): r""" {aliases} @@ -47,4 +50,20 @@ def grdvolume(grid, **kwargs): ) lib.call_module("grdvolume", arg_str) result = outfile.read() + if data_format == "s": + return result + data_list = [] + for string_entry in result.strip().split("\n"): + float_entry = [] + string_list = string_entry.strip().split() + for i in string_list: + float_entry.append(float(i)) + data_list.append(float_entry) + data_array = np.array(data_list) + if data_format == "a": + result = data_array + elif data_format == "d": + result = pd.DataFrame(data_array) + else: + raise GMTInvalidInput("""Must specify format as either a, d, or s.""") return result From 89eb397dae5b6350fc7f41a27fa5c5269a9b5cb2 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 15 Jun 2021 06:58:29 +0100 Subject: [PATCH 05/27] add test_grdvolume.py --- pygmt/tests/test_grdvolume.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 pygmt/tests/test_grdvolume.py diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py new file mode 100644 index 00000000000..d0be9b40cdf --- /dev/null +++ b/pygmt/tests/test_grdvolume.py @@ -0,0 +1,30 @@ +""" +Tests for grdvolume. +""" +import numpy as np +import pandas as pd +import pytest +from pygmt import grdvolume +from pygmt.datasets import load_earth_relief +from pygmt.exceptions import GMTInvalidInput + + +@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=[-1, 1, -1, 1]) + + +def test_grdvolume(grid): + """ + Make sure grdvolume works as expected. + """ + volume_data = grdvolume(grid=grid, data_format="s") + assert volume_data.strip().split() == [ + "0", + "49453592037.5", + "-2.40882119642e+14", + "-4870.87205839", + ] From 57633c38792141d5975163dfb95a88b784feb1eb Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 15 Jun 2021 07:01:17 +0100 Subject: [PATCH 06/27] add test_grdvolume_format --- pygmt/tests/test_grdvolume.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index d0be9b40cdf..5bcdf34b292 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -28,3 +28,15 @@ def test_grdvolume(grid): "-2.40882119642e+14", "-4870.87205839", ] + + +def test_grdvolume_format(grid): + """ + Test that correct formats are returned. + """ + grdvolume_array = grdvolume(grid=grid) + assert isinstance(grdvolume_array, np.ndarray) + grdvolume_df = grdvolume(grid=grid, data_format="d") + assert isinstance(grdvolume_df, pd.DataFrame) + grdvolume_string = grdvolume(grid=grid, data_format="s") + assert isinstance(grdvolume_string, str) From 97adf310b491e322765c16735af1d562a4161373 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 15 Jun 2021 07:03:51 +0100 Subject: [PATCH 07/27] add test_grdvolume_invalid_format --- pygmt/tests/test_grdvolume.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index 5bcdf34b292..4e56757e8fd 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -40,3 +40,11 @@ def test_grdvolume_format(grid): assert isinstance(grdvolume_df, pd.DataFrame) grdvolume_string = grdvolume(grid=grid, data_format="s") assert isinstance(grdvolume_string, str) + + +def test_grdvolume_invalid_format(grid): + """ + Test that grdvolume fails with incorrect data_format argument. + """ + with pytest.raises(GMTInvalidInput): + grdvolume(grid=grid, data_format=1) From 75ff3a295cca886c64f6016f810efccdd0fd45fa Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 15 Jun 2021 07:46:05 +0100 Subject: [PATCH 08/27] add docstring for grdvolume --- pygmt/src/grdvolume.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index d7f232512e2..a8f446d4dc1 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -26,6 +26,14 @@ @kwargs_to_strings(C="sequence", R="sequence") def grdvolume(grid, data_format="a", **kwargs): r""" + Read a 2-D grid file and calculate the volume contained below the surface + and above the plane specified by the given contour (or zero if not given) + and return the contour, area, volume, and maximum mean height + (volume/area). Alternatively, a range of contours can be specified to + return the volume and area inside the contour for all contour values. + Using **-T**, the contour that produced the maximum mean height + (or maximum curvature of heights vs contour value) is returned as well. + {aliases} Parameters From c94288fdcdfc87291fd5eb62f07ee6ed8d4f34c9 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 15 Jun 2021 07:47:42 +0100 Subject: [PATCH 09/27] update data_format docstring --- pygmt/src/grdvolume.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index a8f446d4dc1..b4c3c413e03 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -41,12 +41,17 @@ def grdvolume(grid, data_format="a", **kwargs): grid : str or xarray.DataArray The file name of the input grid or the grid loaded as a DataArray. This is the only required parameter. + data_format : str + Determine the format the data will be returned in: + **a**: numpy array [Default option] + **d**: pandas DataFrame + **s**: string {R} {V} Returns ------- - volume : str + volume : str or numpy.array or pandas.DataFrame A string with the volume between the surface and specified plane. """ with GMTTempFile() as outfile: From 7eb90b5971ee483ba04acb0ac028f249aaa82492 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 15 Jun 2021 08:40:42 +0100 Subject: [PATCH 10/27] update data_format docstring to give one-line description --- pygmt/src/grdvolume.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index b4c3c413e03..be1ac6a8ecb 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -26,6 +26,8 @@ @kwargs_to_strings(C="sequence", R="sequence") def grdvolume(grid, data_format="a", **kwargs): r""" + Determine the volume between the surface of a grid and a plane. + Read a 2-D grid file and calculate the volume contained below the surface and above the plane specified by the given contour (or zero if not given) and return the contour, area, volume, and maximum mean height From 64279fb7eb2e03e5d398aa6ec5c4d55d4aeef385 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 25 Aug 2021 19:40:56 +0100 Subject: [PATCH 11/27] update table output format --- pygmt/src/grdvolume.py | 66 ++++++++++++++++++++--------------- pygmt/tests/test_grdvolume.py | 26 ++++---------- 2 files changed, 43 insertions(+), 49 deletions(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index be1ac6a8ecb..d8d2ba87b14 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -24,7 +24,7 @@ V="verbose", ) @kwargs_to_strings(C="sequence", R="sequence") -def grdvolume(grid, data_format="a", **kwargs): +def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): r""" Determine the volume between the surface of a grid and a plane. @@ -43,42 +43,50 @@ def grdvolume(grid, data_format="a", **kwargs): grid : str or xarray.DataArray The file name of the input grid or the grid loaded as a DataArray. This is the only required parameter. - data_format : str - Determine the format the data will be returned in: - **a**: numpy array [Default option] - **d**: pandas DataFrame - **s**: string + output_type : str + Determine the format the xyz data will be returned in [Default is + ``pandas``]: + - ``numpy`` - :class:`numpy.ndarray` + - ``pandas``- :class:`pandas.DataFrame` + - ``file`` - ASCII file (requires ``outfile``) + outfile : str + The file name for the output ASCII file. {R} {V} Returns ------- - volume : str or numpy.array or pandas.DataFrame - A string with the volume between the surface and specified plane. + ret : pandas.DataFrame or numpy.ndarray or None + Return type depends on ``outfile`` and ``output_type``: + - None if ``outfile`` is set (output will be stored in file set by + ``outfile``) + - :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` is + not set (depends on ``output_type`` [Default is + :class:`pandas.DataFrame`]) + """ - with GMTTempFile() as outfile: + if output_type not in ["numpy", "pandas", "file"]: + raise GMTInvalidInput( + """Must specify format as either numpy, pandas, or file.""" + ) + if output_type == "file" and outfile is None: + raise GMTInvalidInput("""Must specify outfile for ASCII output.""") + + with GMTTempFile() as tmpfile: with Session() as lib: file_context = lib.virtualfile_from_data(check_kind="raster", data=grid) with file_context as infile: - arg_str = " ".join( - [infile, build_arg_string(kwargs), "->" + outfile.name] - ) + if outfile is None: + outfile = tmpfile.name + arg_str = " ".join([infile, build_arg_string(kwargs), "->" + outfile]) lib.call_module("grdvolume", arg_str) - result = outfile.read() - if data_format == "s": - return result - data_list = [] - for string_entry in result.strip().split("\n"): - float_entry = [] - string_list = string_entry.strip().split() - for i in string_list: - float_entry.append(float(i)) - data_list.append(float_entry) - data_array = np.array(data_list) - if data_format == "a": - result = data_array - elif data_format == "d": - result = pd.DataFrame(data_array) - else: - raise GMTInvalidInput("""Must specify format as either a, d, or s.""") + + # Read temporary csv output to a pandas table + if outfile == tmpfile.name: # if user did not set outfile, return pd.DataFrame + result = pd.read_csv(tmpfile.name, sep="\t", header=None, comment=">") + elif outfile != tmpfile.name: # return None if outfile set, output in outfile + result = None + + if output_type == "numpy": + result = result.to_numpy() return result diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index 4e56757e8fd..19a0f89e838 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -16,35 +16,21 @@ def fixture_grid(): """ return load_earth_relief(resolution="01d", region=[-1, 1, -1, 1]) - -def test_grdvolume(grid): - """ - Make sure grdvolume works as expected. - """ - volume_data = grdvolume(grid=grid, data_format="s") - assert volume_data.strip().split() == [ - "0", - "49453592037.5", - "-2.40882119642e+14", - "-4870.87205839", - ] - - def test_grdvolume_format(grid): """ Test that correct formats are returned. """ - grdvolume_array = grdvolume(grid=grid) + grdvolume_default = grdvolume(grid=grid) + assert isinstance(grdvolume_default, pd.DataFrame) + grdvolume_array = grdvolume(grid=grid, output_type="numpy") assert isinstance(grdvolume_array, np.ndarray) - grdvolume_df = grdvolume(grid=grid, data_format="d") + grdvolume_df = grdvolume(grid=grid, output_type="pandas") assert isinstance(grdvolume_df, pd.DataFrame) - grdvolume_string = grdvolume(grid=grid, data_format="s") - assert isinstance(grdvolume_string, str) def test_grdvolume_invalid_format(grid): """ - Test that grdvolume fails with incorrect data_format argument. + Test that grdvolume fails with incorrect output_type argument. """ with pytest.raises(GMTInvalidInput): - grdvolume(grid=grid, data_format=1) + grdvolume(grid=grid, output_type=1) From d4e33acf7c87c9567b71167d5796f3c434710236 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 25 Aug 2021 19:45:36 +0100 Subject: [PATCH 12/27] run make format and make check --- pygmt/src/grdvolume.py | 66 +++++++++++++++++------------------ pygmt/tests/test_grdvolume.py | 1 + 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index d8d2ba87b14..6ec2b2b0662 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -26,43 +26,43 @@ @kwargs_to_strings(C="sequence", R="sequence") def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): r""" - Determine the volume between the surface of a grid and a plane. + Determine the volume between the surface of a grid and a plane. - Read a 2-D grid file and calculate the volume contained below the surface - and above the plane specified by the given contour (or zero if not given) - and return the contour, area, volume, and maximum mean height - (volume/area). Alternatively, a range of contours can be specified to - return the volume and area inside the contour for all contour values. - Using **-T**, the contour that produced the maximum mean height - (or maximum curvature of heights vs contour value) is returned as well. + Read a 2-D grid file and calculate the volume contained below the surface + and above the plane specified by the given contour (or zero if not given) + and return the contour, area, volume, and maximum mean height + (volume/area). Alternatively, a range of contours can be specified to + return the volume and area inside the contour for all contour values. + Using **-T**, the contour that produced the maximum mean height + (or maximum curvature of heights vs contour value) is returned as well. - {aliases} + {aliases} - Parameters - ---------- - grid : str or xarray.DataArray - The file name of the input grid or the grid loaded as a DataArray. - This is the only required parameter. - output_type : str - Determine the format the xyz data will be returned in [Default is - ``pandas``]: - - ``numpy`` - :class:`numpy.ndarray` - - ``pandas``- :class:`pandas.DataFrame` - - ``file`` - ASCII file (requires ``outfile``) - outfile : str - The file name for the output ASCII file. - {R} - {V} + Parameters + ---------- + grid : str or xarray.DataArray + The file name of the input grid or the grid loaded as a DataArray. + This is the only required parameter. + output_type : str + Determine the format the xyz data will be returned in [Default is + ``pandas``]: + - ``numpy`` - :class:`numpy.ndarray` + - ``pandas``- :class:`pandas.DataFrame` + - ``file`` - ASCII file (requires ``outfile``) + outfile : str + The file name for the output ASCII file. + {R} + {V} - Returns - ------- - ret : pandas.DataFrame or numpy.ndarray or None - Return type depends on ``outfile`` and ``output_type``: - - None if ``outfile`` is set (output will be stored in file set by - ``outfile``) - - :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` is - not set (depends on ``output_type`` [Default is - :class:`pandas.DataFrame`]) + Returns + ------- + ret : pandas.DataFrame or numpy.ndarray or None + Return type depends on ``outfile`` and ``output_type``: + - None if ``outfile`` is set (output will be stored in file set by + ``outfile``) + - :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` + is not set (depends on ``output_type`` [Default is + :class:`pandas.DataFrame`]) """ if output_type not in ["numpy", "pandas", "file"]: diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index 19a0f89e838..338d736bf53 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -16,6 +16,7 @@ def fixture_grid(): """ return load_earth_relief(resolution="01d", region=[-1, 1, -1, 1]) + def test_grdvolume_format(grid): """ Test that correct formats are returned. From c4f9ac9a3e79a118b5b45546010541cedb8c210b Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 25 Aug 2021 19:49:48 +0100 Subject: [PATCH 13/27] remove unused numpy import --- pygmt/src/grdvolume.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index 6ec2b2b0662..fad13ef2ab9 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -1,7 +1,6 @@ """ grdvolume - Calculate grid volume and area constrained by a contour. """ -import numpy as np import pandas as pd from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput From 00178bba46e11a2e8d4b11e7b70ee9d44c5d7d92 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Tue, 19 Oct 2021 17:48:52 +0100 Subject: [PATCH 14/27] Apply suggestions from code review Co-authored-by: Meghan Jones --- pygmt/src/grdvolume.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index fad13ef2ab9..d98f6f0d7a5 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -15,9 +15,7 @@ @fmt_docstring @use_alias( - C="plane", - Cr="outside_volume", - D="slice", + C="contour" R="region", S="unit", V="verbose", @@ -32,8 +30,6 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): and return the contour, area, volume, and maximum mean height (volume/area). Alternatively, a range of contours can be specified to return the volume and area inside the contour for all contour values. - Using **-T**, the contour that produced the maximum mean height - (or maximum curvature of heights vs contour value) is returned as well. {aliases} From d636c588b9246e7725d585a7567d086f75b133d3 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 20 Oct 2021 20:27:29 +0100 Subject: [PATCH 15/27] fixing syntax error --- pygmt/src/grdvolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index d98f6f0d7a5..e0874ae3a90 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -15,7 +15,7 @@ @fmt_docstring @use_alias( - C="contour" + C="contour", R="region", S="unit", V="verbose", From e45ecc0e996a49c592eeb14d7e39636b952ac2cb Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 20 Oct 2021 20:40:31 +0100 Subject: [PATCH 16/27] adding contour docstring --- pygmt/src/grdvolume.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index e0874ae3a90..ca6d52387f9 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -46,6 +46,20 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): - ``file`` - ASCII file (requires ``outfile``) outfile : str The file name for the output ASCII file. + contour : str + *cval*\ |*low/high/delta*\ |**r**\ *low/high*\ |**r**\ *cval*. + Find area, volume and mean height (volume/area) inside and above the + *cval* contour. Alternatively, search using all contours from *low* to + *high* in steps of *delta*. [Default returns area, volume and mean + height of the entire grid]. The area is measured in the plane of the + contour. Adding the **r** prefix computes the volume below the grid + surface and above the planes defined by *low* and *high*, or below + *cval* and grid's minimum. Note that this is an *outside* volume + whilst the other forms compute an *inside* (below the surface) area + volume. Use this form to compute for example the volume of water + between two contours. If no *contour* is given then there is no contour + and the entire grid area, volume and the mean height is returned and + *cval* will be reported as 0. {R} {V} From 0e8195ca88ab625ae14cb73c659f0c5030fd17eb Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 20 Oct 2021 20:57:52 +0100 Subject: [PATCH 17/27] change accepted formats for contour in docstring --- pygmt/src/grdvolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index ca6d52387f9..99ac6e666c5 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -46,7 +46,7 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): - ``file`` - ASCII file (requires ``outfile``) outfile : str The file name for the output ASCII file. - contour : str + contour : str or int or float or list *cval*\ |*low/high/delta*\ |**r**\ *low/high*\ |**r**\ *cval*. Find area, volume and mean height (volume/area) inside and above the *cval* contour. Alternatively, search using all contours from *low* to From b80edb495ed31296b65d0500f85f20201be8b280 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Wed, 20 Oct 2021 20:58:08 +0100 Subject: [PATCH 18/27] change size of grid file for tests --- pygmt/tests/test_grdvolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index 338d736bf53..f5968aa0671 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -14,7 +14,7 @@ def fixture_grid(): """ Load the grid data from the sample earth_relief file. """ - return load_earth_relief(resolution="01d", region=[-1, 1, -1, 1]) + return load_earth_relief(resolution="01d", region=[-5, 5, -5, 5]) def test_grdvolume_format(grid): From c4937769b7de4edb9e616af1684c082a3e5f8baf Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 21 Oct 2021 06:50:19 +0100 Subject: [PATCH 19/27] Apply suggestions from code review Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/src/grdvolume.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index 99ac6e666c5..647ff10b065 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -23,7 +23,7 @@ @kwargs_to_strings(C="sequence", R="sequence") def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): r""" - Determine the volume between the surface of a grid and a plane. + Determine the volume between the surface of a grid and a plane. Read a 2-D grid file and calculate the volume contained below the surface and above the plane specified by the given contour (or zero if not given) @@ -31,6 +31,8 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): (volume/area). Alternatively, a range of contours can be specified to return the volume and area inside the contour for all contour values. + Full option list at :gmt-docs:`grdvolume.html` + {aliases} Parameters From 7be5047f4b969a53f2d053b1771b79e9528b1ff7 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 21 Oct 2021 06:53:59 +0100 Subject: [PATCH 20/27] fix spacing --- pygmt/src/grdvolume.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index 647ff10b065..eec89bace78 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -37,17 +37,17 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): Parameters ---------- - grid : str or xarray.DataArray - The file name of the input grid or the grid loaded as a DataArray. - This is the only required parameter. - output_type : str - Determine the format the xyz data will be returned in [Default is - ``pandas``]: - - ``numpy`` - :class:`numpy.ndarray` - - ``pandas``- :class:`pandas.DataFrame` - - ``file`` - ASCII file (requires ``outfile``) - outfile : str - The file name for the output ASCII file. + grid : str or xarray.DataArray + The file name of the input grid or the grid loaded as a DataArray. + This is the only required parameter. + output_type : str + Determine the format the xyz data will be returned in [Default is + ``pandas``]: + - ``numpy`` - :class:`numpy.ndarray` + - ``pandas``- :class:`pandas.DataFrame` + - ``file`` - ASCII file (requires ``outfile``) + outfile : str + The file name for the output ASCII file. contour : str or int or float or list *cval*\ |*low/high/delta*\ |**r**\ *low/high*\ |**r**\ *cval*. Find area, volume and mean height (volume/area) inside and above the @@ -68,12 +68,12 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): Returns ------- ret : pandas.DataFrame or numpy.ndarray or None - Return type depends on ``outfile`` and ``output_type``: - - None if ``outfile`` is set (output will be stored in file set by - ``outfile``) - - :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` - is not set (depends on ``output_type`` [Default is - :class:`pandas.DataFrame`]) + Return type depends on ``outfile`` and ``output_type``: + - None if ``outfile`` is set (output will be stored in file set by + ``outfile``) + - :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` + is not set (depends on ``output_type`` [Default is + class:`pandas.DataFrame`]) """ if output_type not in ["numpy", "pandas", "file"]: From b4ae9dbf1b5df135413a0a424631370bff6bda02 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 21 Oct 2021 07:02:46 +0100 Subject: [PATCH 21/27] changing test coordinates to be on land --- pygmt/tests/test_grdvolume.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index f5968aa0671..6a53111e9ea 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -14,7 +14,7 @@ def fixture_grid(): """ Load the grid data from the sample earth_relief file. """ - return load_earth_relief(resolution="01d", region=[-5, 5, -5, 5]) + return load_earth_relief(resolution="01d", region=[-100, -95, 34, 39]) def test_grdvolume_format(grid): From eb0286622f0f6b7ed5e728092dc396dad739e6d6 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 21 Oct 2021 07:26:06 +0100 Subject: [PATCH 22/27] add test_grdvolume_no_output --- pygmt/tests/test_grdvolume.py | 53 ++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index 6a53111e9ea..3088e7f6eff 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -2,9 +2,10 @@ Tests for grdvolume. """ import numpy as np +import numpy.testing as npt import pandas as pd import pytest -from pygmt import grdvolume +from pygmt import grdvolume, load_dataarray from pygmt.datasets import load_earth_relief from pygmt.exceptions import GMTInvalidInput @@ -17,6 +18,48 @@ def fixture_grid(): return load_earth_relief(resolution="01d", region=[-100, -95, 34, 39]) +@pytest.fixture(scope="module", name="data") +def fixture_data(): + """ + Load the expected grdvolume data result as a numpy array. + """ + data = np.array( + [ + [ + 2.00000000e02, + 1.59920815e11, + 3.16386172e13, + 1.97839269e02, + ], + [ + 2.50000000e02, + 1.44365835e11, + 2.38676788e13, + 1.65327751e02, + ], + [ + 3.00000000e02, + 1.23788259e11, + 1.71278707e13, + 1.38364259e02, + ], + [ + 3.50000000e02, + 9.79597525e10, + 1.15235913e13, + 1.17635978e02, + ], + [ + 4.00000000e02, + 7.26646663e10, + 7.22303463e12, + 9.94022955e01, + ], + ] + ) + return data + + def test_grdvolume_format(grid): """ Test that correct formats are returned. @@ -35,3 +78,11 @@ def test_grdvolume_invalid_format(grid): """ with pytest.raises(GMTInvalidInput): grdvolume(grid=grid, output_type=1) + + +def test_grdvolume_no_outgrid(grid, data): + """ + Test the expected output of grdvolume with no output file set. + """ + test_output = grdvolume(grid=grid, contour=[200, 400, 50], output_type="numpy") + npt.assert_allclose(test_output, data) From d7c98cda64035aaca8bc3259e1d0e21507adeb19 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 21 Oct 2021 07:36:42 +0100 Subject: [PATCH 23/27] add test_grdvolume_outgrid --- pygmt/tests/test_grdvolume.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index 3088e7f6eff..4dec2cd3297 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -1,13 +1,16 @@ """ Tests for grdvolume. """ +import os + import numpy as np import numpy.testing as npt import pandas as pd import pytest -from pygmt import grdvolume, load_dataarray +from pygmt import grdvolume from pygmt.datasets import load_earth_relief from pygmt.exceptions import GMTInvalidInput +from pygmt.helpers import GMTTempFile @pytest.fixture(scope="module", name="grid") @@ -86,3 +89,15 @@ def test_grdvolume_no_outgrid(grid, data): """ test_output = grdvolume(grid=grid, contour=[200, 400, 50], output_type="numpy") npt.assert_allclose(test_output, data) + + +def test_grdvolume_outgrid(grid): + """ + Test the expected output of grdvolume with an output file set. + """ + with GMTTempFile(suffix=".csv") as tmpfile: + result = grdvolume( + grid=grid, contour=[200, 400, 50], output_type="file", outfile=tmpfile.name + ) + assert result is None # return value is None + assert os.path.exists(path=tmpfile.name) # check that outfile exists From 0509f027a9515aaf8e1787e57f888ce5c970c524 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Thu, 21 Oct 2021 07:39:03 +0100 Subject: [PATCH 24/27] add test_grdvolume_no_outfile --- pygmt/tests/test_grdvolume.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pygmt/tests/test_grdvolume.py b/pygmt/tests/test_grdvolume.py index 4dec2cd3297..959f8d12f56 100644 --- a/pygmt/tests/test_grdvolume.py +++ b/pygmt/tests/test_grdvolume.py @@ -83,6 +83,15 @@ def test_grdvolume_invalid_format(grid): grdvolume(grid=grid, output_type=1) +def test_grdvolume_no_outfile(grid): + """ + Test that grdvolume fails when output_type set to 'file' but no outfile is + specified. + """ + with pytest.raises(GMTInvalidInput): + grdvolume(grid=grid, output_type="file") + + def test_grdvolume_no_outgrid(grid, data): """ Test the expected output of grdvolume with no output file set. From 5150a85102039059dc56791b5a7d02aded752dc7 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sat, 23 Oct 2021 07:23:45 +0100 Subject: [PATCH 25/27] Apply suggestions from code review Co-authored-by: Meghan Jones --- pygmt/src/grdvolume.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index eec89bace78..205100ae6f1 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -25,31 +25,32 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): r""" Determine the volume between the surface of a grid and a plane. - Read a 2-D grid file and calculate the volume contained below the surface - and above the plane specified by the given contour (or zero if not given) - and return the contour, area, volume, and maximum mean height - (volume/area). Alternatively, a range of contours can be specified to - return the volume and area inside the contour for all contour values. + Read a 2-D grid file and calculate the volume contained below the surface + and above the plane specified by the given contour (or zero if not given) + and return the contour, area, volume, and maximum mean height + (volume/area). Alternatively, a range of contours can be specified to + return the volume and area inside the contour for all contour values. Full option list at :gmt-docs:`grdvolume.html` - {aliases} + {aliases} - Parameters - ---------- + Parameters + ---------- grid : str or xarray.DataArray The file name of the input grid or the grid loaded as a DataArray. This is the only required parameter. output_type : str Determine the format the xyz data will be returned in [Default is ``pandas``]: + - ``numpy`` - :class:`numpy.ndarray` - ``pandas``- :class:`pandas.DataFrame` - ``file`` - ASCII file (requires ``outfile``) outfile : str The file name for the output ASCII file. contour : str or int or float or list - *cval*\ |*low/high/delta*\ |**r**\ *low/high*\ |**r**\ *cval*. + *cval*\|\ *low/high/delta*\|\ **r**\ *low/high*\|\ **r**\ *cval*. Find area, volume and mean height (volume/area) inside and above the *cval* contour. Alternatively, search using all contours from *low* to *high* in steps of *delta*. [Default returns area, volume and mean @@ -62,19 +63,20 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): between two contours. If no *contour* is given then there is no contour and the entire grid area, volume and the mean height is returned and *cval* will be reported as 0. - {R} - {V} + {R} + {V} - Returns - ------- + Returns + ------- + ret : pandas.DataFrame or numpy.ndarray or None ret : pandas.DataFrame or numpy.ndarray or None Return type depends on ``outfile`` and ``output_type``: + - None if ``outfile`` is set (output will be stored in file set by - ``outfile``) + ``outfile``) - :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` - is not set (depends on ``output_type`` [Default is - class:`pandas.DataFrame`]) - + is not set (depends on ``output_type`` [Default is + class:`pandas.DataFrame`]) """ if output_type not in ["numpy", "pandas", "file"]: raise GMTInvalidInput( From dd478e90e872f0c7a9fe683a41d67535bcded110 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sat, 23 Oct 2021 22:17:01 +0100 Subject: [PATCH 26/27] Update pygmt/src/grdvolume.py Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/src/grdvolume.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index 205100ae6f1..ac5ec4b9cea 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -68,7 +68,6 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): Returns ------- - ret : pandas.DataFrame or numpy.ndarray or None ret : pandas.DataFrame or numpy.ndarray or None Return type depends on ``outfile`` and ``output_type``: From ece4f8fad967c1884691ba8f702d5c7b40c409fa Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Mon, 25 Oct 2021 07:31:13 +0100 Subject: [PATCH 27/27] Apply suggestions from code review Co-authored-by: Dongdong Tian --- pygmt/src/grdvolume.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pygmt/src/grdvolume.py b/pygmt/src/grdvolume.py index ac5ec4b9cea..bd05bea29eb 100644 --- a/pygmt/src/grdvolume.py +++ b/pygmt/src/grdvolume.py @@ -39,9 +39,8 @@ def grdvolume(grid, output_type="pandas", outfile=None, **kwargs): ---------- grid : str or xarray.DataArray The file name of the input grid or the grid loaded as a DataArray. - This is the only required parameter. output_type : str - Determine the format the xyz data will be returned in [Default is + Determine the format the output data will be returned in [Default is ``pandas``]: - ``numpy`` - :class:`numpy.ndarray`