Skip to content

Commit 16cbe9c

Browse files
committed
Add informations on nice display of observations
1 parent 4b1f449 commit 16cbe9c

File tree

4 files changed

+89
-49
lines changed

4 files changed

+89
-49
lines changed

src/py_eddy_tracker/appli/eddies.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ def display_infos():
104104
"latitude",
105105
]
106106
for filename in args.observations:
107-
print(f"-- {filename} --")
108-
e = EddiesObservations.load_file(filename, include_vars=vars)
107+
with Dataset(filename) as h:
108+
track = 'track' in h.variables
109+
print(f"-- {filename} -- ")
110+
if track:
111+
vars_ = vars.copy()
112+
vars_.extend(('track', 'observation_number', 'observation_flag'))
113+
e = TrackEddiesObservations.load_file(filename, include_vars=vars_)
114+
else:
115+
e = EddiesObservations.load_file(filename, include_vars=vars)
109116
print(e)

src/py_eddy_tracker/generic.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
bool_,
4040
concatenate,
4141
radians,
42+
histogram,
4243
)
4344
from numba import njit, prange, types as numba_types
4445
from .poly import winding_number_grid_in_poly
@@ -82,6 +83,11 @@ def build_index(groups):
8283
return first_index, last_index, i0
8384

8485

86+
@njit(cache=True)
87+
def hist_numba(x, bins):
88+
return histogram(x, bins)
89+
90+
8591
@njit(cache=True, fastmath=True, parallel=False)
8692
def distance_grid(lon0, lat0, lon1, lat1):
8793
"""

src/py_eddy_tracker/observations/observation.py

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
reverse_index,
7171
get_pixel_in_regular,
7272
bbox_indice_regular,
73+
hist_numba,
7374
)
7475
from ..poly import bbox_intersection, vertice_overlap, create_vertice
7576

@@ -112,11 +113,6 @@ def shifted_ellipsoid_degrees_mask2(lon0, lat0, lon1, lat1, minor=1.5, major=1.5
112113
return m
113114

114115

115-
@njit(cache=True)
116-
def hist_numba(x, bins):
117-
return histogram(x, bins)
118-
119-
120116
class EddiesObservations(object):
121117
"""
122118
Class to hold eddy properties *amplitude* and counts of
@@ -220,6 +216,32 @@ def _repr_html_(self):
220216
infos = self.get_infos()
221217
return f"""<b>{infos['nb_obs']} observations from {infos['t0']} to {infos['t1']} </b>"""
222218

219+
def hist(self, varname, x, bins, percent=False, mean=False, nb=False):
220+
"""
221+
:param str varname: variable to use to compute stat
222+
:param str x: variable to use to know in which bins
223+
:param array bins:
224+
:param bool percent: normalize by sum of all bins
225+
:param bool mean: compute mean by bins
226+
:param nb mean: only count by bins
227+
:return: value by bins
228+
:rtype: array
229+
"""
230+
if nb:
231+
v = hist_numba(self[x], bins=bins)[0]
232+
else:
233+
v = histogram(self[x], bins=bins, weights=self[varname])[0]
234+
if percent:
235+
v = v.astype("f4") / v.sum() * 100
236+
elif mean:
237+
v /= hist_numba(self[x], bins=bins)[0]
238+
return v
239+
240+
@staticmethod
241+
def box_display(value):
242+
"""Return value evenly spaced with few numbers"""
243+
return "".join([f"{v_:10.2f}" for v_ in value])
244+
223245
def __repr__(self):
224246
"""
225247
return general informations on dataset as a string
@@ -234,48 +256,25 @@ def __repr__(self):
234256
bins_radius = array((0, 15, 30, 45, 60, 75, 100, 200, 2000))
235257
nb_obs = self.observations.shape[0]
236258

237-
def hist(varname, x="lat", bins=bins_lat, percent=False, mean=False, nb=False):
238-
"""
239-
:param str varname: variable to use to compute stat
240-
:param str x: variable to use to know in which bins
241-
:param array bins:
242-
:param bool percent: normalize by sum of all bins
243-
:param bool mean: compute mean by bins
244-
:param nb mean: only count by bins
245-
:return: value by bins
246-
:rtype: array
247-
"""
248-
if nb:
249-
v = hist_numba(self[x], bins=bins)[0]
250-
else:
251-
v = histogram(self[x], bins=bins, weights=self[varname])[0]
252-
if percent:
253-
v = v.astype("f4") / v.sum() * 100
254-
elif mean:
255-
v /= hist_numba(self[x], bins=bins)[0]
256-
return v
257-
258-
def box_display(value):
259-
"""Return value evenly spaced with few numbers"""
260-
return "".join([f"{v_:10.2f}" for v_ in value])
261-
262-
return f"""{nb_obs} observations from {t0} to {t1} ({period} days, ~{nb_obs / period:.0f} obs/day)
263-
Speed area : {self["speed_area"].sum() / period / 1e12:.2f} Mkm²/day
264-
Effective area : {self["effective_area"].sum() / period / 1e12:.2f} Mkm²/day
265-
----Distribution in Amplitude:
266-
Amplitude bounds (cm) {box_display(bins_amplitude)}
267-
Percent of eddies : {box_display(hist('time', 'amplitude', bins_amplitude / 100., percent=True, nb=True))}
268-
----Distribution in Radius:
269-
Speed radius (km) {box_display(bins_radius)}
270-
Percent of eddies : {box_display(hist('time', 'radius_s', bins_radius * 1000., percent=True, nb=True))}
271-
----Distribution in Latitude
272-
Latitude bounds {box_display(bins_lat)}
273-
Percent of eddies : {box_display(hist('time', percent=True, nb=True))}
274-
Percent of speed area : {box_display(hist('speed_area', percent=True))}
275-
Percent of effective area : {box_display(hist('effective_area', percent=True))}
276-
Mean speed radius (km) : {box_display(hist('radius_s', mean=True) / 1000.)}
277-
Mean effective radius (km): {box_display(hist('radius_e', mean=True) / 1000.)}
278-
Mean amplitude (cm) : {box_display(hist('amplitude', mean=True) * 100.)}"""
259+
return f""" | {nb_obs} observations from {t0} to {t1} ({period} days, ~{nb_obs / period:.0f} obs/day)
260+
| Speed area : {self["speed_area"].sum() / period / 1e12:.2f} Mkm²/day
261+
| Effective area : {self["effective_area"].sum() / period / 1e12:.2f} Mkm²/day
262+
----Distribution in Amplitude:
263+
| Amplitude bounds (cm) {self.box_display(bins_amplitude)}
264+
| Percent of eddies : {
265+
self.box_display(self.hist('time', 'amplitude', bins_amplitude / 100., percent=True, nb=True))}
266+
----Distribution in Radius:
267+
| Speed radius (km) {self.box_display(bins_radius)}
268+
| Percent of eddies : {
269+
self.box_display(self.hist('time', 'radius_s', bins_radius * 1000., percent=True, nb=True))}
270+
----Distribution in Latitude
271+
Latitude bounds {self.box_display(bins_lat)}
272+
Percent of eddies : {self.box_display(self.hist('time', 'lat', bins_lat, percent=True, nb=True))}
273+
Percent of speed area : {self.box_display(self.hist('speed_area', 'lat', bins_lat, percent=True))}
274+
Percent of effective area : {self.box_display(self.hist('effective_area', 'lat', bins_lat, percent=True))}
275+
Mean speed radius (km) : {self.box_display(self.hist('radius_s', 'lat', bins_lat, mean=True) / 1000.)}
276+
Mean effective radius (km): {self.box_display(self.hist('radius_e', 'lat', bins_lat, mean=True) / 1000.)}
277+
Mean amplitude (cm) : {self.box_display(self.hist('amplitude', 'lat', bins_lat, mean=True) * 100.)}"""
279278

280279
def __getitem__(self, attr):
281280
if attr in self.elements:

src/py_eddy_tracker/observations/tracking.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
zeros,
3939
array,
4040
median,
41+
histogram
4142
)
4243
from datetime import datetime, timedelta
4344
from numba import njit
@@ -62,6 +63,8 @@ class TrackEddiesObservations(EddiesObservations):
6263
"lat",
6364
"radius_s",
6465
"radius_e",
66+
"speed_area",
67+
"effective_area",
6568
"amplitude",
6669
"speed_average",
6770
"time",
@@ -83,6 +86,31 @@ def __init__(self, *args, **kwargs):
8386
self.__first_index_of_track = None
8487
self.__obs_by_track = None
8588

89+
def __repr__(self):
90+
content = super().__repr__()
91+
t0, t1 = self.period
92+
period = t1 - t0 + 1
93+
nb = self.nb_obs_by_track
94+
nb_obs = self.observations.shape[0]
95+
m = self["virtual"].astype("bool")
96+
nb_m = m.sum()
97+
bins_t = (0, 20, 50, 100, 200, 1000, 10000)
98+
nb_tracks_by_t = histogram(nb, bins=bins_t)[0]
99+
nb_obs_by_t = histogram(nb, bins=bins_t, weights=nb)[0]
100+
pct_tracks_by_t = nb_tracks_by_t / nb_tracks_by_t.sum() * 100.
101+
pct_obs_by_t = nb_obs_by_t / nb_obs_by_t.sum() * 100.
102+
content += f"""
103+
| {nb.shape[0]} tracks ({nb.mean():.2f} obs/tracks, shorter {nb.min()} obs, longer {nb.max()} obs)
104+
| {nb_m} filled observations ({nb_m / nb.shape[0]:.2f} obs/tracks, {nb_m / nb_obs * 100:.2f} % of total)
105+
| Intepolated speed area : {self["speed_area"][m].sum() / period / 1e12:.2f} Mkm²/day
106+
| Intepolated effective area : {self["effective_area"][m].sum() / period / 1e12:.2f} Mkm²/day
107+
----Distribution in lifetime:
108+
| Lifetime (days ) {self.box_display(bins_t)}
109+
| Percent of tracks : {self.box_display(pct_tracks_by_t)}
110+
| Percent of eddies : {self.box_display(pct_obs_by_t)}
111+
"""
112+
return content
113+
86114
def filled_by_interpolation(self, mask):
87115
"""Filled selected values by interpolation
88116
"""

0 commit comments

Comments
 (0)