11# -*- coding: utf-8 -*- 
22""" 
3- Class to manage observations gathered in track  
3+ Class to manage observations gathered in trajectories  
44""" 
55import  logging 
66from  datetime  import  datetime , timedelta 
@@ -123,7 +123,7 @@ def __repr__(self):
123123        return  content 
124124
125125    def  add_distance (self ):
126-         """Add a field of distance (m) between to  consecutive observation , 0 for the last observation of each track""" 
126+         """Add a field of distance (m) between two  consecutive observations , 0 for the last observation of each track""" 
127127        if  "distance_next"  in  self .observations .dtype .descr :
128128            return  self 
129129        new  =  self .add_fields (("distance_next" ,))
@@ -181,7 +181,7 @@ def filled_by_interpolation(self, mask):
181181            )
182182
183183    def  extract_longer_eddies (self , nb_min , nb_obs , compress_id = True ):
184-         """Select eddies which are  longer than nb_min""" 
184+         """Select the trajectories  longer than nb_min""" 
185185        mask  =  nb_obs  >=  nb_min 
186186        nb_obs_select  =  mask .sum ()
187187        logger .info ("Selection of %d observations" , nb_obs_select )
@@ -226,9 +226,9 @@ def set_global_attr_netcdf(self, h_nc):
226226
227227    def  extract_with_period (self , period , ** kwargs ):
228228        """ 
229-         Extract with a  period 
229+         Extract within a time  period 
230230
231-         :param (int,int) period: two date  to define period, must be specify from 1/1/1950 
231+         :param (int,int) period: two dates  to define the  period, must be specify from 1/1/1950 
232232        :param dict kwargs: look at :py:meth:`extract_with_mask` 
233233        :return: Return all eddy tracks which are in bounds 
234234        :rtype: TrackEddiesObservations 
@@ -251,9 +251,9 @@ def extract_with_period(self, period, **kwargs):
251251
252252    def  get_azimuth (self , equatorward = False ):
253253        """ 
254-         Return azimuth for each tracks . 
254+         Return azimuth for each track . 
255255
256-         Azimuth is compute  with first and last observation 
256+         Azimuth is computed  with first and last observation 
257257
258258        :param bool equatorward: If True,  Poleward are positive and equatorward negative 
259259        :rtype: array 
@@ -285,7 +285,7 @@ def compute_index(self):
285285        """ 
286286        if  self .__first_index_of_track  is  None :
287287            s  =  self .tracks .max () +  1 
288-             # Doesn't work => core dump with numba, maybe he wait  i8 instead of u4 
288+             # Doesn't work => core dump with numba, maybe he wants  i8 instead of u4 
289289            # self.__first_index_of_track = -ones(s, self.tracks.dtype) 
290290            # self.__obs_by_track = zeros(s, self.observation_number.dtype) 
291291            self .__first_index_of_track  =  - ones (s , "i8" )
@@ -333,12 +333,12 @@ def nb_obs_by_track(self):
333333
334334    @property  
335335    def  lifetime (self ):
336-         """Return for each observation lifetime """ 
336+         """Return lifetime  for each observation""" 
337337        return  self .nb_obs_by_track .repeat (self .nb_obs_by_track )
338338
339339    @property  
340340    def  age (self ):
341-         """Return for each observation  age in %, will be [0:100]""" 
341+         """Return age in % for each observation , will be [0:100]""" 
342342        return  self .n .astype ("f4" ) /  (self .lifetime  -  1 ) *  100.0 
343343
344344    def  extract_ids (self , tracks ):
@@ -347,10 +347,10 @@ def extract_ids(self, tracks):
347347
348348    def  extract_toward_direction (self , west = True , delta_lon = None ):
349349        """ 
350-         Get eddy which go in  same direction 
350+         Get trajectories going in the  same direction 
351351
352-         :param bool west: Only eastward eddy  if True return westward 
353-         :param None,float delta_lon: Only eddy  with more than delta_lon span in longitude 
352+         :param bool west: Only eastward eddies  if True return westward 
353+         :param None,float delta_lon: Only eddies  with more than delta_lon span in longitude 
354354        :return: Only eastern eddy 
355355        :rtype: __class__ 
356356
@@ -397,10 +397,10 @@ def extract_in_direction(self, direction, value=0):
397397
398398    def  extract_with_length (self , bounds ):
399399        """ 
400-         Return all  observations in  [b0:b1] 
400+         Return the  observations within trajectories lasting between  [b0:b1] 
401401
402-         :param (int,int) bounds: length min and max of selected eddies , if use of  -1 this bound is not used 
403-         :return: Return all eddy tracks which have  length between bounds 
402+         :param (int,int) bounds: length min and max of the desired trajectories , if -1 this bound is not used 
403+         :return: Return all trajectories having  length between bounds 
404404        :rtype: TrackEddiesObservations 
405405
406406        .. minigallery:: py_eddy_tracker.TrackEddiesObservations.extract_with_length 
@@ -460,11 +460,11 @@ def extract_with_mask(
460460        Extract a subset of observations 
461461
462462        :param array(bool) mask: mask to select observations 
463-         :param bool full_path: extract full path  if only one part is selected 
464-         :param bool remove_incomplete: delete path which are  not fully selected 
465-         :param bool compress_id: resample track  number to use a little  range 
466-         :param bool reject_virtual: if track are  only virtual in selection we remove track  
467-         :return: same object with selected observations 
463+         :param bool full_path: extract the  full trajectory  if only one part is selected 
464+         :param bool remove_incomplete: delete trajectory if  not fully selected 
465+         :param bool compress_id: resample trajectory  number to use a smaller  range 
466+         :param bool reject_virtual: if only virtual are selected, the trajectory is removed  
467+         :return: same object with the  selected observations 
468468        :rtype: self.__class__ 
469469        """ 
470470        if  full_path  and  remove_incomplete :
@@ -509,7 +509,9 @@ def re_reference_index(index, ref):
509509
510510    def  shape_polygon (self , intern = False ):
511511        """ 
512-         Get polygons which enclosed each track 
512+         Get the polygon enclosing each trajectory. 
513+ 
514+         The polygon merges the non-overlapping bounds of the specified contours 
513515
514516        :param bool intern: If True use speed contour instead of effective contour 
515517        :rtype: list(array, array) 
@@ -519,9 +521,9 @@ def shape_polygon(self, intern=False):
519521
520522    def  display_shape (self , ax , ref = None , intern = False , ** kwargs ):
521523        """ 
522-         This function will draw shape of each track  
524+         This function will draw the  shape of each trajectory  
523525
524-         :param matplotlib.axes.Axes ax: ax where drawed  
526+         :param matplotlib.axes.Axes ax: ax to draw  
525527        :param float,int ref: if defined all coordinates will be wrapped with ref like west boundary 
526528        :param bool intern: If True use speed contour instead of effective contour 
527529        :param dict kwargs: keyword arguments for Axes.plot 
@@ -546,10 +548,10 @@ def display_shape(self, ax, ref=None, intern=False, **kwargs):
546548
547549    def  close_tracks (self , other , nb_obs_min = 10 , ** kwargs ):
548550        """ 
549-         Get close from another atlas. 
551+         Get close trajectories  from another atlas. 
550552
551553        :param self other: Atlas to compare 
552-         :param int nb_obs_min: Minimal number of overlap for one track  
554+         :param int nb_obs_min: Minimal number of overlap for one trajectory  
553555        :param dict kwargs: keyword arguments for match function 
554556        :return: return other atlas reduce to common track with self 
555557
@@ -576,10 +578,10 @@ def format_label(self, label):
576578
577579    def  plot (self , ax , ref = None , ** kwargs ):
578580        """ 
579-         This function will draw path of each track  
581+         This function will draw path of each trajectory  
580582
581-         :param matplotlib.axes.Axes ax: ax where drawed  
582-         :param float,int ref: if defined all coordinates will be wrapped with ref like west boundary 
583+         :param matplotlib.axes.Axes ax: ax to draw  
584+         :param float,int ref: if defined,  all coordinates will be wrapped with ref like west boundary 
583585        :param dict kwargs: keyword arguments for Axes.plot 
584586        :return: matplotlib mappable 
585587        """ 
@@ -594,7 +596,7 @@ def plot(self, ax, ref=None, **kwargs):
594596        return  ax .plot (x , y , ** kwargs )
595597
596598    def  split_network (self , intern = True , ** kwargs ):
597-         """Divide  each group in track """ 
599+         """Return  each group (network) divided  in segments """ 
598600        track_s , track_e , track_ref  =  build_index (self .tracks )
599601        ids  =  empty (
600602            len (self ),
@@ -609,17 +611,23 @@ def split_network(self, intern=True, **kwargs):
609611            ],
610612        )
611613        ids ["group" ], ids ["time" ] =  self .tracks , self .time 
612-         # To store id track 
614+         # Initialisation 
615+         # To store the id of the segments, the backward and forward cost associations 
613616        ids ["track" ], ids ["previous_cost" ], ids ["next_cost" ] =  0 , 0 , 0 
617+         # To store the indexes of the backward and forward observations associated 
614618        ids ["previous_obs" ], ids ["next_obs" ] =  - 1 , - 1 
619+         # At the end, ids["previous_obs"] == -1 means the start of a non-split segment 
620+         # and ids["next_obs"] == -1 means the end of a non-merged segment 
615621
616622        xname , yname  =  self .intern (intern )
617623        for  i_s , i_e  in  zip (track_s , track_e ):
618624            if  i_s  ==  i_e  or  self .tracks [i_s ] ==  self .NOGROUP :
619625                continue 
620626            sl  =  slice (i_s , i_e )
621627            local_ids  =  ids [sl ]
628+             # built segments with local indices 
622629            self .set_tracks (self [xname ][sl ], self [yname ][sl ], local_ids , ** kwargs )
630+             # shift the local indices to the total indexation for the used observations 
623631            m  =  local_ids ["previous_obs" ] !=  - 1 
624632            local_ids ["previous_obs" ][m ] +=  i_s 
625633            m  =  local_ids ["next_obs" ] !=  - 1 
@@ -628,7 +636,7 @@ def split_network(self, intern=True, **kwargs):
628636
629637    def  set_tracks (self , x , y , ids , window , ** kwargs ):
630638        """ 
631-         Will split one group in tracks  
639+         Will split one group (network)  in segments  
632640
633641        :param array x: coordinates of group 
634642        :param array y: coordinates of group 
@@ -640,18 +648,21 @@ def set_tracks(self, x, y, ids, window, **kwargs):
640648        nb  =  x .shape [0 ]
641649        used  =  zeros (nb , dtype = "bool" )
642650        track_id  =  1 
643-         # build all polygon  (need to check if wrap is needed) 
651+         # build all polygons  (need to check if wrap is needed) 
644652        for  i  in  range (nb ):
645-             # If observation already in one track, we go to the next one 
653+             # If the  observation is  already in one track, we go to the next one 
646654            if  used [i ]:
647655                continue 
656+             # Search a possible continuation (forward) 
648657            self .follow_obs (i , track_id , used , ids , x , y , * time_index , window , ** kwargs )
649658            track_id  +=  1 
650-             # Search a possible ancestor 
659+             # Search a possible ancestor (backward)  
651660            self .previous_obs (i , ids , x , y , * time_index , window , ** kwargs )
652661
653662    @classmethod  
654663    def  follow_obs (cls , i_next , track_id , used , ids , * args , ** kwargs ):
664+         """Associate the observations to the segments""" 
665+ 
655666        while  i_next  !=  - 1 :
656667            # Flag 
657668            used [i_next ] =  True 
@@ -675,14 +686,16 @@ def follow_obs(cls, i_next, track_id, used, ids, *args, **kwargs):
675686
676687    @staticmethod  
677688    def  previous_obs (i_current , ids , x , y , time_s , time_e , time_ref , window , ** kwargs ):
689+         """Backward association of observations to the segments""" 
690+ 
678691        time_cur  =  ids ["time" ][i_current ]
679692        t0 , t1  =  time_cur  -  1  -  time_ref , max (time_cur  -  window  -  time_ref , 0 )
680693        for  t_step  in  range (t0 , t1  -  1 , - 1 ):
681694            i0 , i1  =  time_s [t_step ], time_e [t_step ]
682695            # No observation at the time step 
683696            if  i0  ==  i1 :
684697                continue 
685-             # Intersection / union, to be able to separte in case of multiple inside  
698+             # Search for overlaps  
686699            xi , yi , xj , yj  =  x [[i_current ]], y [[i_current ]], x [i0 :i1 ], y [i0 :i1 ]
687700            ii , ij  =  bbox_intersection (xi , yi , xj , yj )
688701            if  len (ii ) ==  0 :
@@ -703,6 +716,7 @@ def previous_obs(i_current, ids, x, y, time_s, time_e, time_ref, window, **kwarg
703716
704717    @staticmethod  
705718    def  next_obs (i_current , ids , x , y , time_s , time_e , time_ref , window , ** kwargs ):
719+         """Forward association of observations to the segments""" 
706720        time_max  =  time_e .shape [0 ] -  1 
707721        time_cur  =  ids ["time" ][i_current ]
708722        t0 , t1  =  time_cur  +  1  -  time_ref , min (time_cur  +  window  -  time_ref , time_max )
@@ -713,7 +727,7 @@ def next_obs(i_current, ids, x, y, time_s, time_e, time_ref, window, **kwargs):
713727            # No observation at the time step 
714728            if  i0  ==  i1 :
715729                continue 
716-             # Intersection / union, to be able to separte in case of multiple inside  
730+             # Search for overlaps  
717731            xi , yi , xj , yj  =  x [[i_current ]], y [[i_current ]], x [i0 :i1 ], y [i0 :i1 ]
718732            ii , ij  =  bbox_intersection (xi , yi , xj , yj )
719733            if  len (ii ) ==  0 :
0 commit comments