3838 zeros ,
3939 array ,
4040 median ,
41- histogram
41+ histogram ,
4242)
4343from datetime import datetime , timedelta
4444from numba import njit
4545from Polygon import Polygon
4646from .observation import EddiesObservations
4747from .. import VAR_DESCR_inv
48- from ..generic import split_line , wrap_longitude , build_index
48+ from ..generic import split_line , wrap_longitude , build_index , distance , cumsum_by_track
4949from ..poly import polygon_overlap , create_vertice_from_2darray
5050
5151
@@ -56,7 +56,7 @@ class TrackEddiesObservations(EddiesObservations):
5656 """Class to practice Tracking on observations
5757 """
5858
59- __slots__ = ("__obs_by_track" , "__first_index_of_track" )
59+ __slots__ = ("__obs_by_track" , "__first_index_of_track" , "__nb_track" )
6060
6161 ELEMENTS = [
6262 "lon" ,
@@ -85,6 +85,16 @@ def __init__(self, *args, **kwargs):
8585 super ().__init__ (* args , ** kwargs )
8686 self .__first_index_of_track = None
8787 self .__obs_by_track = None
88+ self .__nb_track = None
89+
90+ @property
91+ def nb_tracks (self ):
92+ """
93+ Will count and send number of track
94+ """
95+ if self .__nb_track is None :
96+ self .__nb_track = (self .nb_obs_by_track != 0 ).sum ()
97+ return self .__nb_track
8898
8999 def __repr__ (self ):
90100 content = super ().__repr__ ()
@@ -94,23 +104,56 @@ def __repr__(self):
94104 nb_obs = self .observations .shape [0 ]
95105 m = self ["virtual" ].astype ("bool" )
96106 nb_m = m .sum ()
97- bins_t = (0 , 20 , 50 , 100 , 200 , 1000 , 10000 )
107+ bins_t = (1 , 20 , 50 , 100 , 200 , 1000 , 10000 )
98108 nb_tracks_by_t = histogram (nb , bins = bins_t )[0 ]
99109 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.
110+ pct_tracks_by_t = nb_tracks_by_t / nb_tracks_by_t .sum () * 100.0
111+ pct_obs_by_t = nb_obs_by_t / nb_obs_by_t .sum () * 100.0
112+ d = self .distance_to_next () / 1000.0
113+ cum_d = cumsum_by_track (d , self .tracks )
114+ m_last = ones (d .shape , dtype = "bool" )
115+ m_last [- 1 ] = False
116+ m_last [self .index_from_track [1 :] - 1 ] = False
102117 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
118+ | { self .nb_tracks } tracks ({
119+ nb_obs / self .nb_tracks :.2f} obs/tracks, shorter { nb [nb != 0 ].min ()} obs, longer { nb .max ()} obs)
120+ | { nb_m } filled observations ({ nb_m / self .nb_tracks :.2f} obs/tracks, { nb_m / nb_obs * 100 :.2f} % of total)
121+ | Intepolated speed area : { self ["speed_area" ][m ].sum () / period / 1e12 :.2f} Mkm²/day
122+ | Intepolated effective area : { self ["effective_area" ][m ].sum () / period / 1e12 :.2f} Mkm²/day
123+ | Distance by day : Mean { d [m_last ].mean ():.2f} , Median { median (d [m_last ]):.2f} km/day
124+ | Distance by track : Mean { cum_d [~ m_last ].mean ():.2f} , Median { median (cum_d [~ m_last ]):.2f} km/track
107125 ----Distribution in lifetime:
108126 | Lifetime (days ) { self .box_display (bins_t )}
109127 | Percent of tracks : { self .box_display (pct_tracks_by_t )}
110- | Percent of eddies : { self .box_display (pct_obs_by_t )}
111- """
128+ | Percent of eddies : { self .box_display (pct_obs_by_t )} """
112129 return content
113130
131+ def add_distance (self ):
132+ """Add a field of distance (m) between to consecutive observation, 0 for the last observation of each track
133+ """
134+ if "distance_next" in self .observations .dtype .descr :
135+ return self
136+ new = self .add_fields (("distance_next" ,))
137+ new ["distance_next" ][:1 ] = self .distance_to_next ()
138+ return new
139+
140+ def distance_to_next (self ):
141+ """
142+ :return: array of distance in m, 0 when next obs if from another track
143+ :rtype: array
144+ """
145+ d = distance (
146+ self .longitude [:- 1 ],
147+ self .latitude [:- 1 ],
148+ self .longitude [1 :],
149+ self .latitude [1 :],
150+ )
151+ d [self .index_from_track [1 :] - 1 ] = 0
152+ d_ = empty (d .shape [0 ] + 1 , dtype = d .dtype )
153+ d_ [:- 1 ] = d
154+ d_ [- 1 ] = 0
155+ return d_
156+
114157 def filled_by_interpolation (self , mask ):
115158 """Filled selected values by interpolation
116159 """
@@ -329,15 +372,14 @@ def __extract_with_mask(
329372 ):
330373 """
331374 Extract a subset of observations
332- Args:
333- mask: mask to select observations
334- full_path: extract full path if only one part is selected
335- remove_incomplete: delete path which are not fully selected
336- compress_id: resample track number to use a little range
337- reject_virtual: if track are only virtual in selection we remove track
338-
339- Returns:
340- same object with selected observations
375+
376+ :param array(bool) mask: mask to select observations
377+ :param full_path: extract full path if only one part is selected
378+ :param remove_incomplete: delete path which are not fully selected
379+ :param compress_id: resample track number to use a little range
380+ :param reject_virtual: if track are only virtual in selection we remove track
381+ :return: same object with selected observations
382+ :rtype: self
341383 """
342384 if full_path and remove_incomplete :
343385 logger .warning (
@@ -373,6 +415,14 @@ def __extract_with_mask(
373415 return new
374416
375417 def plot (self , ax , ref = None , ** kwargs ):
418+ """
419+ This function will draw path of each track
420+
421+ :param matplotlib.axes.Axes ax: ax where drawed
422+ :param float,int ref: if defined all coordinates will be wrapped with ref like west boundary
423+ :param dict kwargs: keyword arguments for Axes.plot
424+ :return: matplotlib mappable
425+ """
376426 if "label" in kwargs :
377427 kwargs ["label" ] += " (%s eddies)" % (self .nb_obs_by_track != 0 ).sum ()
378428 x , y = split_line (self .longitude , self .latitude , self .tracks )
@@ -436,7 +486,15 @@ def split_network(self, intern=True, **kwargs):
436486 # )
437487
438488 def set_tracks (self , x , y , ids , window ):
439- # Will split one group in tracks
489+ """
490+ Will split one group in tracks
491+
492+ :param array x: coordinates of group
493+ :param array y: coordinates of group
494+ :param ndarray ids: several fields like time, group, ...
495+ :param int windows: number of days where observations could missed
496+ """
497+
440498 time_index = build_index (ids ["time" ])
441499 nb = x .shape [0 ]
442500 used = zeros (nb , dtype = "bool" )
0 commit comments