Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 76 additions & 26 deletions pygmt/src/binstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Comment thread
seisman marked this conversation as resolved.
C="statistic",
E="empty",
I="spacing",
N="normalize",
Expand All @@ -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.
Expand All @@ -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.
Comment thread
seisman marked this conversation as resolved.
Outdated
- **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
Expand Down Expand Up @@ -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)
26 changes: 24 additions & 2 deletions pygmt/tests/test_binstats.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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.
Comment thread
seisman marked this conversation as resolved.
Outdated
"""
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)
Loading