27
27
sin ,
28
28
histogram ,
29
29
digitize ,
30
+ percentile ,
30
31
)
31
32
from netCDF4 import Dataset
32
33
from datetime import datetime
@@ -1685,6 +1686,51 @@ def grid_count(self, bins, intern=False, center=False):
1685
1686
grid .mask = grid == 0
1686
1687
return regular_grid
1687
1688
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
+
1688
1734
def grid_stat (self , bins , varname , data = None ):
1689
1735
"""
1690
1736
Compute mean of eddies in each bin
@@ -1701,7 +1747,7 @@ def grid_stat(self, bins, varname, data=None):
1701
1747
x0 = bins [0 ][0 ]
1702
1748
x , y = (self .longitude - x0 ) % 360 + x0 , self .latitude
1703
1749
data = self [varname ] if data is None else data
1704
- if hasattr (data , ' mask' ):
1750
+ if hasattr (data , " mask" ):
1705
1751
m = ~ data .mask
1706
1752
sum_obs = histogram2d (x [m ], y [m ], (x_bins , y_bins ), weights = data [m ])[0 ]
1707
1753
nb_obs = histogram2d (x [m ], y [m ], (x_bins , y_bins ))[0 ]
@@ -1717,6 +1763,7 @@ def grid_stat(self, bins, varname, data=None):
1717
1763
"x" : x_bins [:- 1 ],
1718
1764
"y" : y_bins [:- 1 ],
1719
1765
},
1766
+ centered = False ,
1720
1767
)
1721
1768
return regular_grid
1722
1769
@@ -1770,6 +1817,9 @@ def period(self):
1770
1817
1771
1818
@njit (cache = True )
1772
1819
def grid_count_ (grid , i , j ):
1820
+ """
1821
+ Add one for each indice
1822
+ """
1773
1823
for i_ , j_ in zip (i , j ):
1774
1824
grid [i_ , j_ ] += 1
1775
1825
@@ -1801,6 +1851,59 @@ def insidepoly(x_p, y_p, x_c, y_c):
1801
1851
return flag
1802
1852
1803
1853
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
+
1804
1907
@njit (cache = True )
1805
1908
def grid_stat (x_c , y_c , grid , x , y , result , circular = False , method = "mean" ):
1806
1909
"""
0 commit comments