From 6df2d83fd32d027658e6da23e931f090d2fc88d1 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 17 Jan 2024 21:59:34 +0800 Subject: [PATCH 1/7] pygmt.binstats: Let the parameter 'statistic' support long-form arguments --- pygmt/src/binstats.py | 102 ++++++++++++++++++++++++++--------- pygmt/tests/test_binstats.py | 4 +- 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index 18711451cb0..372556eafa8 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -2,15 +2,17 @@ binstats - Bin spatial data and determine statistics per bin. """ +from typing import Literal + import xarray as xr from pygmt._typing import PathLike, TableLike +from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias @fmt_docstring @use_alias( - C="statistic", E="empty", I="spacing", N="normalize", @@ -26,7 +28,28 @@ ) @kwargs_to_strings(I="sequence", R="sequence", i="sequence_comma") def binstats( - data: PathLike | TableLike, outgrid: PathLike | None = None, **kwargs + data: PathLike | TableLike, + outgrid: PathLike | None = None, + statistic: Literal[ + "mean", + "mad", + "full", + "interquartile", + "min", + "minpos", + "median", + "number", + "lms", + "mode", + "quantile", + "rms", + "stddev", + "max", + "maxneg", + "sum", + ] = "number", + quantile_value: float = 50, + **kwargs, ) -> xr.DataArray | None: r""" Bin spatial data and determine statistics per bin. @@ -48,29 +71,29 @@ def binstats( data A file name of an ASCII data table or a 2-D {table-classes}. {outgrid} - statistic : str - **a**\|\ **d**\|\ **g**\|\ **i**\|\ **l**\|\ **L**\|\ **m**\|\ **n**\ - \|\ **o**\|\ **p**\|\ **q**\ [*quant*]\|\ **r**\|\ **s**\|\ **u**\ - \|\ **U**\|\ **z**. - Choose the statistic that will be computed per node based on the - points that are within *radius* distance of the node. Select one of: + statistic + Choose the statistic that will be computed per node based on the points that are + within *radius* distance of the node. Select one of: - - **a**: mean (average) - - **d**: median absolute deviation (MAD) - - **g**: full (max-min) range - - **i**: 25-75% interquartile range - - **l**: minimum (low) - - **L**: minimum of positive values only - - **m**: median - - **n**: number of values - - **o**: LMS scale - - **p**: mode (maximum likelihood) - - **q**: selected quantile (append desired quantile in 0-100% range [50]) - - **r**: root mean square (RMS) - - **s**: standard deviation - - **u**: maximum (upper) - - **U**: maximum of negative values only - - **z**: sum + - **mean**: Compute the mean value (average). + - **mad**: Compute the median absolute deviation (MAD). + - **full**: Compute the full (max-min) range. + - **interquartile**: Compute the 25-75% interquartile range. + - **min**: Compute the minimum value. + - **minpos**: Compute the minimum of positive values only. + - **median**: Compute the median value. + - **number**: Compute the number of values. + - **lms**: Compute the LMS scale. + - **mode**: Compute the mode (maximum likelihood). + - **quantile**: Compute the selected quantile. The quantile value is in 0-100% + range and is specified by the ``quantile_value`` parameter. + - **rms**: Compute the root mean square (RMS). + - **stddev**: Compute the standard deviation. + - **max**: Compute the maximum value. + - **maxneg**: Compute the maximum of negative values only. + - **sum**: Compute the sum of values. + quantile_value + The quantile value if ``statistic="quantile"``. empty : float Set the value assigned to empty nodes [Default is NaN]. normalize : bool @@ -104,13 +127,40 @@ def binstats( - ``None`` if ``outgrid`` is set (grid output will be stored in the file set by ``outgrid``) """ + aliasdict = AliasSystem( + C=Alias( + statistic, + name="statistic", + mapping={ + "mean": "a", + "mad": "d", + "full": "g", + "interquartile": "i", + "min": "l", + "minpos": "L", + "median": "m", + "number": "n", + "lms": "o", + "mode": "p", + "quantile": "q", + "rms": "r", + "stddev": "s", + "max": "u", + "maxneg": "U", + "sum": "z", + }, + ), + ).merge(kwargs) + if statistic == "quantile": + aliasdict["C"] += f"{quantile_value}" + with Session() as lib: with ( lib.virtualfile_in(check_kind="vector", data=data) as vintbl, lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, ): - kwargs["G"] = voutgrd + aliasdict["G"] = voutgrd lib.call_module( - module="binstats", args=build_arg_list(kwargs, infile=vintbl) + module="binstats", args=build_arg_list(aliasdict, infile=vintbl) ) return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/tests/test_binstats.py b/pygmt/tests/test_binstats.py index 6b77c82f861..7e25f069da9 100644 --- a/pygmt/tests/test_binstats.py +++ b/pygmt/tests/test_binstats.py @@ -20,7 +20,7 @@ def test_binstats_outgrid(): data="@capitals.gmt", outgrid=tmpfile.name, spacing=5, - statistic="z", + statistic="sum", search_radius="1000k", aspatial="2=population", region="g", @@ -37,7 +37,7 @@ def test_binstats_no_outgrid(): temp_grid = binstats( data="@capitals.gmt", spacing=5, - statistic="z", + statistic="sum", search_radius="1000k", aspatial="2=population", region="g", From 4779c367c7c3c4b5362e1b01d3f49b9345e9582d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 3 Aug 2025 13:17:43 +0800 Subject: [PATCH 2/7] Add a test to increase coverage --- pygmt/tests/test_binstats.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pygmt/tests/test_binstats.py b/pygmt/tests/test_binstats.py index 7e25f069da9..35d8b774df7 100644 --- a/pygmt/tests/test_binstats.py +++ b/pygmt/tests/test_binstats.py @@ -49,3 +49,25 @@ def test_binstats_no_outgrid(): npt.assert_allclose(temp_grid.min(), 53) npt.assert_allclose(temp_grid.median(), 1232714.5) npt.assert_allclose(temp_grid.mean(), 4227489) + + +def test_binstats_quantile(): + """ + Test binstats with no set outgrid. + """ + temp_grid = binstats( + data="@capitals.gmt", + spacing=5, + statistic="quantile", + quantile_value=75, + search_radius="1000k", + aspatial="2=population", + region="g", + ) + assert temp_grid.dims == ("y", "x") + assert temp_grid.gmt.gtype is GridType.CARTESIAN + assert temp_grid.gmt.registration is GridRegistration.GRIDLINE + npt.assert_allclose(temp_grid.max(), 15047685) + npt.assert_allclose(temp_grid.min(), 53) + npt.assert_allclose(temp_grid.median(), 543664.5) + npt.assert_allclose(temp_grid.mean(), 1661363.6) From 9138a4cec9df25caa838d4ac77cbc88a730ca5ce Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 7 Aug 2025 20:04:54 +0800 Subject: [PATCH 3/7] Update pygmt/src/binstats.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com> --- pygmt/src/binstats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index 372556eafa8..3544dcd8ddb 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -83,7 +83,7 @@ def binstats( - **minpos**: Compute the minimum of positive values only. - **median**: Compute the median value. - **number**: Compute the number of values. - - **lms**: Compute the LMS scale. + - **lms**: Compute the least median square (LMS) scale. - **mode**: Compute the mode (maximum likelihood). - **quantile**: Compute the selected quantile. The quantile value is in 0-100% range and is specified by the ``quantile_value`` parameter. From 40cdc59dcd44545db0094c1eac2b4c5d25c97e0a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 8 Aug 2025 12:13:14 +0800 Subject: [PATCH 4/7] Add C to alias docstring --- pygmt/src/binstats.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index 3544dcd8ddb..fdf74966dca 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -65,6 +65,7 @@ def binstats( Full GMT docs at :gmt-docs:`gmtbinstats.html`. {aliases} + - C=statistic Parameters ---------- From 1c1c1444b194667bed3a2041d22f0dc19f48a155 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 8 Aug 2025 12:14:08 +0800 Subject: [PATCH 5/7] Update pygmt/tests/test_binstats.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- pygmt/tests/test_binstats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_binstats.py b/pygmt/tests/test_binstats.py index 35d8b774df7..9d633aebf3e 100644 --- a/pygmt/tests/test_binstats.py +++ b/pygmt/tests/test_binstats.py @@ -53,7 +53,7 @@ def test_binstats_no_outgrid(): def test_binstats_quantile(): """ - Test binstats with no set outgrid. + Test binstats quantile statistic functionality. """ temp_grid = binstats( data="@capitals.gmt", From 153af6659c242d096abb2313cfe9cb5513b40e6a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 9 Aug 2025 22:55:34 +0800 Subject: [PATCH 6/7] Reformat descriptive arguments --- pygmt/src/binstats.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index fdf74966dca..b6b5bd0f606 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -76,23 +76,23 @@ def binstats( Choose the statistic that will be computed per node based on the points that are within *radius* distance of the node. Select one of: - - **mean**: Compute the mean value (average). - - **mad**: Compute the median absolute deviation (MAD). - - **full**: Compute the full (max-min) range. - - **interquartile**: Compute the 25-75% interquartile range. - - **min**: Compute the minimum value. - - **minpos**: Compute the minimum of positive values only. - - **median**: Compute the median value. - - **number**: Compute the number of values. - - **lms**: Compute the least median square (LMS) scale. - - **mode**: Compute the mode (maximum likelihood). - - **quantile**: Compute the selected quantile. The quantile value is in 0-100% + - ``"mean"``: Compute the mean value (average). + - ``"mad"``: Compute the median absolute deviation (MAD). + - ``"full"``: Compute the full (max-min) range. + - ``"interquartile"``: Compute the 25-75% interquartile range. + - ``"min"``: Compute the minimum value. + - ``"minpos"``: Compute the minimum of positive values only. + - ``"median"``: Compute the median value. + - ``"number"``: Compute the number of values. + - ``"lms"``: Compute the least median square (LMS) scale. + - ``"mode"``: Compute the mode (maximum likelihood). + - ``"quantile"``: Compute the selected quantile. The quantile value is in 0-100% range and is specified by the ``quantile_value`` parameter. - - **rms**: Compute the root mean square (RMS). - - **stddev**: Compute the standard deviation. - - **max**: Compute the maximum value. - - **maxneg**: Compute the maximum of negative values only. - - **sum**: Compute the sum of values. + - ``"rms"``: Compute the root mean square (RMS). + - ``"stddev"``: Compute the standard deviation. + - ``"max"``: Compute the maximum value. + - ``"maxneg"``: Compute the maximum of negative values only. + - ``"sum"``: Compute the sum of values. quantile_value The quantile value if ``statistic="quantile"``. empty : float From ae6fc3c9bfb89da4cbf109fe52f68e3bada341e8 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 9 Aug 2025 23:03:01 +0800 Subject: [PATCH 7/7] Update the description of arguments to match upstream docs --- pygmt/src/binstats.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index b6b5bd0f606..d671082952c 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -76,23 +76,23 @@ def binstats( Choose the statistic that will be computed per node based on the points that are within *radius* distance of the node. Select one of: - - ``"mean"``: Compute the mean value (average). - - ``"mad"``: Compute the median absolute deviation (MAD). - - ``"full"``: Compute the full (max-min) range. - - ``"interquartile"``: Compute the 25-75% interquartile range. - - ``"min"``: Compute the minimum value. - - ``"minpos"``: Compute the minimum of positive values only. - - ``"median"``: Compute the median value. - - ``"number"``: Compute the number of values. - - ``"lms"``: Compute the least median square (LMS) scale. - - ``"mode"``: Compute the mode (maximum likelihood). - - ``"quantile"``: Compute the selected quantile. The quantile value is in 0-100% - range and is specified by the ``quantile_value`` parameter. - - ``"rms"``: Compute the root mean square (RMS). - - ``"stddev"``: Compute the standard deviation. - - ``"max"``: Compute the maximum value. - - ``"maxneg"``: Compute the maximum of negative values only. - - ``"sum"``: Compute the sum of values. + - ``"mean"``: Mean (i.e., average). + - ``"mad"``: Median absolute deviation (MAD). + - ``"full"``: The full (max-min) range. + - ``"interquartile"``: The 25-75% interquartile range. + - ``"min"``: Minimum (lowest value). + - ``"minpos"``: Minimum of positive values only. + - ``"median"``: Median value. + - ``"number"``: The number of values per bin. + - ``"lms"``: Least median square (LMS) scale. + - ``"mode"``: Mode (maximum likelihood estimate). + - ``"quantile"``: Selected quantile. The quantile value is specified by the + ``quantile_value`` parameter and is in the 0-100% range. + - ``"rms"``: Root mean square (RMS). + - ``"stddev"``: Standard deviation. + - ``"max"``: Maximum (highest value). + - ``"maxneg"``: Maximum of negative values only. + - ``"sum"``: The sum of the values. quantile_value The quantile value if ``statistic="quantile"``. empty : float