11
11
from ..generic import build_index , wrap_longitude
12
12
from ..poly import bbox_intersection , vertice_overlap
13
13
from .observation import EddiesObservations
14
- from .tracking import TrackEddiesObservations
14
+ from .tracking import TrackEddiesObservations , track_median_filter
15
15
16
16
logger = logging .getLogger ("pet" )
17
17
@@ -168,7 +168,17 @@ def only_one_network(self):
168
168
# TODO
169
169
pass
170
170
171
- def display_timeline (self , ax , event = True ):
171
+ def median_filter (self , half_window , xfield , yfield , inplace = True ):
172
+ # FIXME: segments is not enough with several network
173
+ result = track_median_filter (
174
+ half_window , self [xfield ], self [yfield ], self .segment
175
+ )
176
+ if inplace :
177
+ self [yfield ][:] = result
178
+ return self
179
+ return result
180
+
181
+ def display_timeline (self , ax , event = True , field = None , method = None ):
172
182
"""
173
183
Must be call on only one network
174
184
"""
@@ -183,21 +193,33 @@ def display_timeline(self, ax, event=True):
183
193
)
184
194
mappables = dict (lines = list ())
185
195
if event :
186
- mappables .update (self .event_timeline (ax ))
196
+ mappables .update (self .event_timeline (ax , field = field , method = method ))
187
197
for i , b0 , b1 in self .iter_on ("segment" ):
188
198
x = self .time [i ]
189
199
if x .shape [0 ] == 0 :
190
200
continue
191
- y = b0 * ones (x .shape )
201
+ if field is None :
202
+ y = b0 * ones (x .shape )
203
+ else :
204
+ if method == "all" :
205
+ y = self [field ][i ]
206
+ else :
207
+ y = self [field ][i ].mean () * ones (x .shape )
192
208
line = ax .plot (x , y , ** line_kw , color = self .COLORS [j % self .NB_COLORS ])[0 ]
193
209
mappables ["lines" ].append (line )
194
210
j += 1
195
211
196
212
return mappables
197
213
198
- def event_timeline (self , ax ):
214
+ def event_timeline (self , ax , field = None , method = None ):
199
215
j = 0
200
216
# TODO : fill mappables dict
217
+ y_seg = dict ()
218
+ if field is not None and method != "all" :
219
+ for i , b0 , _ in self .iter_on ("segment" ):
220
+ y = self [field ][i ]
221
+ if y .shape [0 ] != 0 :
222
+ y_seg [b0 ] = y .mean ()
201
223
mappables = dict ()
202
224
for i , b0 , b1 in self .iter_on ("segment" ):
203
225
x = self .time [i ]
@@ -208,12 +230,33 @@ def event_timeline(self, ax):
208
230
self .next_obs [i .stop - 1 ],
209
231
self .previous_obs [i .start ],
210
232
)
233
+ if field is None :
234
+ y0 = b0
235
+ else :
236
+ if method == "all" :
237
+ y0 = self [field ][i .stop - 1 ]
238
+ else :
239
+ y0 = y_seg [b0 ]
211
240
if i_n != - 1 :
212
- ax .plot ((x [- 1 ], self .time [i_n ]), (b0 , self .segment [i_n ]), ** event_kw )
213
- ax .plot (x [- 1 ], b0 , color = "k" , marker = ">" , markersize = 10 , zorder = - 1 )
241
+ seg_next = self .segment [i_n ]
242
+ y1 = (
243
+ seg_next
244
+ if field is None
245
+ else (self [field ][i_n ] if method == "all" else y_seg [seg_next ])
246
+ )
247
+ ax .plot ((x [- 1 ], self .time [i_n ]), (y0 , y1 ), ** event_kw )[0 ]
248
+ ax .plot (x [- 1 ], y0 , color = "k" , marker = ">" , markersize = 10 , zorder = - 1 )[0 ]
214
249
if i_p != - 1 :
215
- ax .plot ((x [0 ], self .time [i_p ]), (b0 , self .segment [i_p ]), ** event_kw )
216
- ax .plot (x [0 ], b0 , color = "k" , marker = "*" , markersize = 12 , zorder = - 1 )
250
+ seg_previous = self .segment [i_p ]
251
+ if field is not None and method == "all" :
252
+ y0 = self [field ][i .start ]
253
+ y1 = (
254
+ seg_previous
255
+ if field is None
256
+ else (self [field ][i_p ] if method == "all" else y_seg [seg_previous ])
257
+ )
258
+ ax .plot ((x [0 ], self .time [i_p ]), (y0 , y1 ), ** event_kw )[0 ]
259
+ ax .plot (x [0 ], y0 , color = "k" , marker = "*" , markersize = 12 , zorder = - 1 )[0 ]
217
260
j += 1
218
261
return mappables
219
262
@@ -235,16 +278,7 @@ def insert_virtual(self):
235
278
# TODO
236
279
pass
237
280
238
- def merging_event (self ):
239
- indices = list ()
240
- for i , b0 , b1 in self .iter_on ("segment" ):
241
- nb = i .stop - i .start
242
- if nb == 0 :
243
- continue
244
- i_n = self .next_obs [i .stop - 1 ]
245
- if i_n != - 1 :
246
- indices .append (i .stop - 1 )
247
- indices = list (set (indices ))
281
+ def extract_event (self , indices ):
248
282
nb = len (indices )
249
283
new = EddiesObservations (
250
284
nb ,
@@ -260,30 +294,54 @@ def merging_event(self):
260
294
new .sign_type = self .sign_type
261
295
return new
262
296
297
+ def segment_track_array (self ):
298
+ return build_unique_array (self .segment , self .track )
299
+
300
+ def birth_event (self ):
301
+ # FIXME how to manage group 0
302
+ indices = list ()
303
+ for i , b0 , b1 in self .iter_on (self .segment_track_array ()):
304
+ nb = i .stop - i .start
305
+ if nb == 0 :
306
+ continue
307
+ i_p = self .previous_obs [i .start ]
308
+ if i_p == - 1 :
309
+ indices .append (i .start )
310
+ return self .extract_event (list (set (indices )))
311
+
312
+ def death_event (self ):
313
+ # FIXME how to manage group 0
314
+ indices = list ()
315
+ for i , b0 , b1 in self .iter_on (self .segment_track_array ()):
316
+ nb = i .stop - i .start
317
+ if nb == 0 :
318
+ continue
319
+ i_n = self .next_obs [i .stop - 1 ]
320
+ if i_n == - 1 :
321
+ indices .append (i .stop - 1 )
322
+ return self .extract_event (list (set (indices )))
323
+
324
+ def merging_event (self ):
325
+ indices = list ()
326
+ for i , b0 , b1 in self .iter_on (self .segment_track_array ()):
327
+ nb = i .stop - i .start
328
+ if nb == 0 :
329
+ continue
330
+ i_n = self .next_obs [i .stop - 1 ]
331
+ if i_n != - 1 :
332
+ indices .append (i .stop - 1 )
333
+ return self .extract_event (list (set (indices )))
334
+
263
335
def spliting_event (self ):
264
336
indices = list ()
265
- for i , b0 , b1 in self .iter_on ("segment" ):
337
+ for i , b0 , b1 in self .iter_on (self . segment_track_array () ):
266
338
nb = i .stop - i .start
267
339
if nb == 0 :
268
340
continue
269
341
i_p = self .previous_obs [i .start ]
270
342
if i_p != - 1 :
271
343
indices .append (i .start )
272
- indices = list (set (indices ))
273
- nb = len (indices )
274
- new = EddiesObservations (
275
- nb ,
276
- track_extra_variables = self .track_extra_variables ,
277
- track_array_variables = self .track_array_variables ,
278
- array_variables = self .array_variables ,
279
- only_variables = self .only_variables ,
280
- raw_data = self .raw_data ,
281
- )
282
-
283
- for k in new .obs .dtype .names :
284
- new [k ][:] = self [k ][indices ]
285
- new .sign_type = self .sign_type
286
- return new
344
+ return self .extract_event (list (set (indices )))
287
345
288
346
def fully_connected (self ):
289
347
self .only_one_network ()
@@ -463,14 +521,16 @@ def group_observations(self, **kwargs):
463
521
print ()
464
522
465
523
gr = self .get_group_array (results , nb_obs )
524
+ nb_alone , nb_obs , nb_gr = (gr == self .NOGROUP ).sum (), len (gr ), len (unique (gr ))
466
525
logger .info (
467
- f"{ (gr == self .NOGROUP ).sum ()} alone / { len (gr )} obs, { len (unique (gr ))} groups"
526
+ f"{ nb_alone } alone / { nb_obs } obs, { nb_gr } groups, "
527
+ f"{ nb_alone * 100. / nb_obs :.2f} % alone, { (nb_obs - nb_alone ) / (nb_gr - 1 ):.1f} obs/group"
468
528
)
469
529
return gr
470
530
471
531
def build_dataset (self , group ):
472
532
nb_obs = group .shape [0 ]
473
- model = EddiesObservations .load_file (self .filenames [- 1 ], raw_data = True )
533
+ model = TrackEddiesObservations .load_file (self .filenames [- 1 ], raw_data = True )
474
534
eddies = TrackEddiesObservations .new_like (model , nb_obs )
475
535
eddies .sign_type = model .sign_type
476
536
# Get new index to re-order observation by group
@@ -485,17 +545,16 @@ def build_dataset(self, group):
485
545
if self .memory :
486
546
# Only if netcdf
487
547
with open (filename , "rb" ) as h :
488
- e = EddiesObservations .load_file (h , raw_data = True )
548
+ e = TrackEddiesObservations .load_file (h , raw_data = True )
489
549
else :
490
- e = EddiesObservations .load_file (filename , raw_data = True )
550
+ e = TrackEddiesObservations .load_file (filename , raw_data = True )
491
551
stop = i + len (e )
492
552
sl = slice (i , stop )
493
553
for element in elements :
494
554
eddies [element ][new_i [sl ]] = e [element ]
495
555
i = stop
496
556
if display_iteration :
497
557
print ()
498
- eddies = eddies .add_fields (("track" ,))
499
558
eddies .track [new_i ] = group
500
559
return eddies
501
560
@@ -518,3 +577,18 @@ def apply_replace(x, x0, x1):
518
577
for i in range (nb ):
519
578
if x [i ] == x0 :
520
579
x [i ] = x1
580
+
581
+
582
+ @njit (cache = True )
583
+ def build_unique_array (id1 , id2 ):
584
+ k = 0
585
+ new_id = empty (id1 .shape , dtype = id1 .dtype )
586
+ id1_previous = id1 [0 ]
587
+ id2_previous = id2 [0 ]
588
+ for i in range (id1 .shape [0 ]):
589
+ id1_ , id2_ = id1 [i ], id2 [i ]
590
+ if id1_ != id1_previous or id2_ != id2_previous :
591
+ k += 1
592
+ new_id [i ] = k
593
+ id1_previous , id2_previous = id1_ , id2_
594
+ return new_id
0 commit comments