Skip to content

Commit 2b3200c

Browse files
committed
Add method to apply a method on each box
1 parent 16a7a67 commit 2b3200c

File tree

2 files changed

+105
-2
lines changed

2 files changed

+105
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ python setup.py install
3535
### Tools gallery ###
3636
Several examples based on py eddy tracker module are [here](https://py-eddy-tracker.readthedocs.io/en/latest/python_module/index.html).
3737

38-
![](https://py-eddy-tracker.readthedocs.io/en/latest/_static/logo.png)
38+
[![](https://py-eddy-tracker.readthedocs.io/en/latest/_static/logo.png)](https://py-eddy-tracker.readthedocs.io/en/latest/python_module/index.html)
3939

4040
### Quick use ###
4141

src/py_eddy_tracker/observations/observation.py

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
sin,
2828
histogram,
2929
digitize,
30+
percentile,
3031
)
3132
from netCDF4 import Dataset
3233
from datetime import datetime
@@ -1685,6 +1686,51 @@ def grid_count(self, bins, intern=False, center=False):
16851686
grid.mask = grid == 0
16861687
return regular_grid
16871688

1689+
def grid_box_stat(self, bins, varname, method=50, data=None):
1690+
"""
1691+
Compute mean of eddies in each bin
1692+
1693+
:param (numpy.array,numpy.array) bins: bins to compute count
1694+
:param str varname: name of variable to compute mean
1695+
:param str,float method: method to apply at each set
1696+
:param array data: Array used to compute stat if defined
1697+
:return: return grid of method
1698+
:rtype: py_eddy_tracker.dataset.grid.RegularGridDataset
1699+
1700+
.. minigallery:: py_eddy_tracker.EddiesObservations.grid_box_stat
1701+
"""
1702+
x_bins, y_bins = arange(*bins[0]), arange(*bins[1])
1703+
x0 = bins[0][0]
1704+
x, y = (self.longitude - x0) % 360 + x0, self.latitude
1705+
data = self[varname] if data is None else data
1706+
if hasattr(data, "mask"):
1707+
m = ~data.mask
1708+
x, y, data = x[m], y[m], data[m]
1709+
1710+
from ..dataset.grid import RegularGridDataset
1711+
1712+
shape = (x_bins.shape[0] - 1, y_bins.shape[0] - 1)
1713+
grid = ma.empty(shape, dtype=data.dtype)
1714+
grid.mask = ones(shape, dtype="bool")
1715+
regular_grid = RegularGridDataset.with_array(
1716+
coordinates=("x", "y"),
1717+
datas={varname: grid, "x": x_bins[:-1], "y": y_bins[:-1]},
1718+
centered=False,
1719+
)
1720+
grid_box_stat(
1721+
regular_grid.x_c,
1722+
regular_grid.y_c,
1723+
grid.data,
1724+
grid.mask,
1725+
x,
1726+
y,
1727+
data,
1728+
regular_grid.is_circular(),
1729+
method,
1730+
)
1731+
1732+
return regular_grid
1733+
16881734
def grid_stat(self, bins, varname, data=None):
16891735
"""
16901736
Compute mean of eddies in each bin
@@ -1701,7 +1747,7 @@ def grid_stat(self, bins, varname, data=None):
17011747
x0 = bins[0][0]
17021748
x, y = (self.longitude - x0) % 360 + x0, self.latitude
17031749
data = self[varname] if data is None else data
1704-
if hasattr(data, 'mask'):
1750+
if hasattr(data, "mask"):
17051751
m = ~data.mask
17061752
sum_obs = histogram2d(x[m], y[m], (x_bins, y_bins), weights=data[m])[0]
17071753
nb_obs = histogram2d(x[m], y[m], (x_bins, y_bins))[0]
@@ -1717,6 +1763,7 @@ def grid_stat(self, bins, varname, data=None):
17171763
"x": x_bins[:-1],
17181764
"y": y_bins[:-1],
17191765
},
1766+
centered=False,
17201767
)
17211768
return regular_grid
17221769

@@ -1770,6 +1817,9 @@ def period(self):
17701817

17711818
@njit(cache=True)
17721819
def grid_count_(grid, i, j):
1820+
"""
1821+
Add one for each indice
1822+
"""
17731823
for i_, j_ in zip(i, j):
17741824
grid[i_, j_] += 1
17751825

@@ -1801,6 +1851,59 @@ def insidepoly(x_p, y_p, x_c, y_c):
18011851
return flag
18021852

18031853

1854+
@njit(cache=True)
1855+
def grid_box_stat(x_c, y_c, grid, mask, x, y, value, circular=False, method=50):
1856+
"""
1857+
Compute method on each set (one set by box)
1858+
1859+
:param array_like x_c: longitude coordinate of grid
1860+
:param array_like y_c: latitude coordinate of grid
1861+
:param array_like grid: grid to store result of method
1862+
:param array[bool] mask: grid to store not used box
1863+
:param array_like x: longitude of positions
1864+
:param array_like y: latitude of positions
1865+
:param array_like value: value to group to apply method
1866+
:param bool circular: True if grid is wrappable
1867+
:param float method: percentile
1868+
"""
1869+
xstep, ystep = x_c[1] - x_c[0], y_c[1] - y_c[0]
1870+
x0, y0 = x_c[0] - xstep / 2.0, y_c[0] - ystep / 2.0
1871+
nb_x = x_c.shape[0]
1872+
nb_y = y_c.shape[0]
1873+
i, j = (
1874+
((x - x0) // xstep).astype(numba_types.int32),
1875+
((y - y0) // ystep).astype(numba_types.int32),
1876+
)
1877+
if circular:
1878+
i %= nb_x
1879+
else:
1880+
if (i < 0).any():
1881+
raise Exception("x indices underflow")
1882+
if (i >= nb_x).any():
1883+
raise Exception("x indices overflow")
1884+
if (j < 0).any():
1885+
raise Exception("y indices underflow")
1886+
if (j >= nb_y).any():
1887+
raise Exception("y indices overflow")
1888+
abs_i = j * nb_x + i
1889+
k_sort = abs_i.argsort()
1890+
i0, j0 = i[k_sort[0]], j[k_sort[0]]
1891+
values = list()
1892+
for k in k_sort:
1893+
i_, j_ = i[k], j[k]
1894+
# group change
1895+
if i_ != i0 or j_ != j0:
1896+
# apply method and store result
1897+
grid[i_, j_] = percentile(values, method)
1898+
# grid[i_, j_] = len(values)
1899+
mask[i_, j_] = False
1900+
# start new group
1901+
i0, j0 = i_, j_
1902+
# reset list
1903+
values.clear()
1904+
values.append(value[k])
1905+
1906+
18041907
@njit(cache=True)
18051908
def grid_stat(x_c, y_c, grid, x, y, result, circular=False, method="mean"):
18061909
"""

0 commit comments

Comments
 (0)