Skip to content

Commit 2bc5931

Browse files
seismanyvonnefroehlichCopilot
authored
pygmt.binstats: Let the parameter 'statistic' support descriptive arguments (#3012)
Co-authored-by: Yvonne Fröhlich <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 372763a commit 2bc5931

File tree

2 files changed

+101
-28
lines changed

2 files changed

+101
-28
lines changed

pygmt/src/binstats.py

Lines changed: 77 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22
binstats - Bin spatial data and determine statistics per bin.
33
"""
44

5+
from typing import Literal
6+
57
import xarray as xr
68
from pygmt._typing import PathLike, TableLike
9+
from pygmt.alias import Alias, AliasSystem
710
from pygmt.clib import Session
811
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias
912

1013

1114
@fmt_docstring
1215
@use_alias(
13-
C="statistic",
1416
E="empty",
1517
I="spacing",
1618
N="normalize",
@@ -26,7 +28,28 @@
2628
)
2729
@kwargs_to_strings(I="sequence", R="sequence", i="sequence_comma")
2830
def binstats(
29-
data: PathLike | TableLike, outgrid: PathLike | None = None, **kwargs
31+
data: PathLike | TableLike,
32+
outgrid: PathLike | None = None,
33+
statistic: Literal[
34+
"mean",
35+
"mad",
36+
"full",
37+
"interquartile",
38+
"min",
39+
"minpos",
40+
"median",
41+
"number",
42+
"lms",
43+
"mode",
44+
"quantile",
45+
"rms",
46+
"stddev",
47+
"max",
48+
"maxneg",
49+
"sum",
50+
] = "number",
51+
quantile_value: float = 50,
52+
**kwargs,
3053
) -> xr.DataArray | None:
3154
r"""
3255
Bin spatial data and determine statistics per bin.
@@ -42,35 +65,36 @@ def binstats(
4265
Full GMT docs at :gmt-docs:`gmtbinstats.html`.
4366
4467
{aliases}
68+
- C=statistic
4569
4670
Parameters
4771
----------
4872
data
4973
A file name of an ASCII data table or a 2-D {table-classes}.
5074
{outgrid}
51-
statistic : str
52-
**a**\|\ **d**\|\ **g**\|\ **i**\|\ **l**\|\ **L**\|\ **m**\|\ **n**\
53-
\|\ **o**\|\ **p**\|\ **q**\ [*quant*]\|\ **r**\|\ **s**\|\ **u**\
54-
\|\ **U**\|\ **z**.
55-
Choose the statistic that will be computed per node based on the
56-
points that are within *radius* distance of the node. Select one of:
75+
statistic
76+
Choose the statistic that will be computed per node based on the points that are
77+
within *radius* distance of the node. Select one of:
5778
58-
- **a**: mean (average)
59-
- **d**: median absolute deviation (MAD)
60-
- **g**: full (max-min) range
61-
- **i**: 25-75% interquartile range
62-
- **l**: minimum (low)
63-
- **L**: minimum of positive values only
64-
- **m**: median
65-
- **n**: number of values
66-
- **o**: LMS scale
67-
- **p**: mode (maximum likelihood)
68-
- **q**: selected quantile (append desired quantile in 0-100% range [50])
69-
- **r**: root mean square (RMS)
70-
- **s**: standard deviation
71-
- **u**: maximum (upper)
72-
- **U**: maximum of negative values only
73-
- **z**: sum
79+
- ``"mean"``: Mean (i.e., average).
80+
- ``"mad"``: Median absolute deviation (MAD).
81+
- ``"full"``: The full (max-min) range.
82+
- ``"interquartile"``: The 25-75% interquartile range.
83+
- ``"min"``: Minimum (lowest value).
84+
- ``"minpos"``: Minimum of positive values only.
85+
- ``"median"``: Median value.
86+
- ``"number"``: The number of values per bin.
87+
- ``"lms"``: Least median square (LMS) scale.
88+
- ``"mode"``: Mode (maximum likelihood estimate).
89+
- ``"quantile"``: Selected quantile. The quantile value is specified by the
90+
``quantile_value`` parameter and is in the 0-100% range.
91+
- ``"rms"``: Root mean square (RMS).
92+
- ``"stddev"``: Standard deviation.
93+
- ``"max"``: Maximum (highest value).
94+
- ``"maxneg"``: Maximum of negative values only.
95+
- ``"sum"``: The sum of the values.
96+
quantile_value
97+
The quantile value if ``statistic="quantile"``.
7498
empty : float
7599
Set the value assigned to empty nodes [Default is NaN].
76100
normalize : bool
@@ -104,13 +128,40 @@ def binstats(
104128
- ``None`` if ``outgrid`` is set (grid output will be stored in the file set by
105129
``outgrid``)
106130
"""
131+
aliasdict = AliasSystem(
132+
C=Alias(
133+
statistic,
134+
name="statistic",
135+
mapping={
136+
"mean": "a",
137+
"mad": "d",
138+
"full": "g",
139+
"interquartile": "i",
140+
"min": "l",
141+
"minpos": "L",
142+
"median": "m",
143+
"number": "n",
144+
"lms": "o",
145+
"mode": "p",
146+
"quantile": "q",
147+
"rms": "r",
148+
"stddev": "s",
149+
"max": "u",
150+
"maxneg": "U",
151+
"sum": "z",
152+
},
153+
),
154+
).merge(kwargs)
155+
if statistic == "quantile":
156+
aliasdict["C"] += f"{quantile_value}"
157+
107158
with Session() as lib:
108159
with (
109160
lib.virtualfile_in(check_kind="vector", data=data) as vintbl,
110161
lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd,
111162
):
112-
kwargs["G"] = voutgrd
163+
aliasdict["G"] = voutgrd
113164
lib.call_module(
114-
module="binstats", args=build_arg_list(kwargs, infile=vintbl)
165+
module="binstats", args=build_arg_list(aliasdict, infile=vintbl)
115166
)
116167
return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid)

pygmt/tests/test_binstats.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def test_binstats_outgrid():
2020
data="@capitals.gmt",
2121
outgrid=tmpfile.name,
2222
spacing=5,
23-
statistic="z",
23+
statistic="sum",
2424
search_radius="1000k",
2525
aspatial="2=population",
2626
region="g",
@@ -37,7 +37,7 @@ def test_binstats_no_outgrid():
3737
temp_grid = binstats(
3838
data="@capitals.gmt",
3939
spacing=5,
40-
statistic="z",
40+
statistic="sum",
4141
search_radius="1000k",
4242
aspatial="2=population",
4343
region="g",
@@ -49,3 +49,25 @@ def test_binstats_no_outgrid():
4949
npt.assert_allclose(temp_grid.min(), 53)
5050
npt.assert_allclose(temp_grid.median(), 1232714.5)
5151
npt.assert_allclose(temp_grid.mean(), 4227489)
52+
53+
54+
def test_binstats_quantile():
55+
"""
56+
Test binstats quantile statistic functionality.
57+
"""
58+
temp_grid = binstats(
59+
data="@capitals.gmt",
60+
spacing=5,
61+
statistic="quantile",
62+
quantile_value=75,
63+
search_radius="1000k",
64+
aspatial="2=population",
65+
region="g",
66+
)
67+
assert temp_grid.dims == ("y", "x")
68+
assert temp_grid.gmt.gtype is GridType.CARTESIAN
69+
assert temp_grid.gmt.registration is GridRegistration.GRIDLINE
70+
npt.assert_allclose(temp_grid.max(), 15047685)
71+
npt.assert_allclose(temp_grid.min(), 53)
72+
npt.assert_allclose(temp_grid.median(), 543664.5)
73+
npt.assert_allclose(temp_grid.mean(), 1661363.6)

0 commit comments

Comments
 (0)