22
22
"""
23
23
24
24
import numpy as np
25
- from datetime import datetime
26
25
import matplotlib .pyplot as plt
26
+ from datetime import datetime , timedelta
27
27
from matplotlib .projections import register_projection
28
- import py_eddy_tracker_sample as sample
29
28
from .generic import flatten_line_matrix , split_line
30
- from .observations .tracking import TrackEddiesObservations
31
29
32
30
33
31
try :
@@ -65,10 +63,6 @@ def end_pan(self, *args, **kwargs):
65
63
register_projection (GUIAxes )
66
64
67
65
68
- class A (TrackEddiesObservations ):
69
- pass
70
-
71
-
72
66
def no (* args , ** kwargs ):
73
67
return False
74
68
@@ -81,6 +75,7 @@ class GUI:
81
75
"time_ax" ,
82
76
"param_ax" ,
83
77
"settings" ,
78
+ "d_indexs" ,
84
79
"m" ,
85
80
"last_event" ,
86
81
)
@@ -89,6 +84,7 @@ class GUI:
89
84
90
85
def __init__ (self , ** datasets ):
91
86
self .datasets = datasets
87
+ self .d_indexs = dict ()
92
88
self .m = dict ()
93
89
self .set_initial_values ()
94
90
self .setup ()
@@ -140,8 +136,9 @@ def setup(self):
140
136
# map
141
137
self .map = self .figure .add_axes ((0 , 0.25 , 1 , 0.75 ), projection = "full_axes" )
142
138
self .map .grid ()
143
- self .map .tick_params ("x" , pad = - 12 )
144
- self .map .tick_params ("y" , pad = - 22 )
139
+ self .map .tick_params ("both" , pad = - 22 )
140
+ # self.map.tick_params("y", pad=-22)
141
+ self .map .bg_cache = None
145
142
# time ax
146
143
self .time_ax = self .figure .add_axes ((0 , 0.15 , 1 , 0.1 ), facecolor = ".95" )
147
144
self .time_ax .can_pan
@@ -159,41 +156,65 @@ def setup(self):
159
156
self .param_ax = self .figure .add_axes ((0 , 0 , 1 , 0.15 ), facecolor = "0.2" )
160
157
161
158
def draw (self ):
159
+ self .m ["mini_ax" ] = self .figure .add_axes ((0.3 , 0.85 , 0.4 , 0.15 ), zorder = 80 )
160
+ self .m ["mini_ax" ].grid ()
162
161
# map
163
162
for i , (name , dataset ) in enumerate (self .datasets .items ()):
163
+ kwargs = dict (color = self .COLORS [i ])
164
164
self .m [name ] = dict (
165
- contour_s = self .map .plot (
166
- [], [], color = self .COLORS [i ], lw = 0.5 , label = name
167
- )[0 ],
168
- contour_e = self .map .plot ([], [], color = self .COLORS [i ], lw = 0.5 )[0 ],
169
- path_previous = self .map .plot ([], [], color = self .COLORS [i ], lw = 0.5 )[0 ],
170
- path_future = self .map .plot ([], [], color = self .COLORS [i ], lw = 0.2 , ls = ":" )[
171
- 0
172
- ],
165
+ contour_s = self .map .plot ([], [], lw = 1 , label = name , ** kwargs )[0 ],
166
+ contour_e = self .map .plot ([], [], lw = 0.5 , ls = "-." , ** kwargs )[0 ],
167
+ path_previous = self .map .plot ([], [], lw = 0.5 , ** kwargs )[0 ],
168
+ path_future = self .map .plot ([], [], lw = 0.2 , ls = ":" , ** kwargs )[0 ],
169
+ mini_line = self .m ["mini_ax" ].plot ([], [], ** kwargs , lw = 1 )[0 ]
173
170
)
174
- self .m ["title" ] = self .map .set_title ("" )
175
171
# time_ax
172
+ self .m ["annotate" ] = self .map .annotate (
173
+ "" ,
174
+ (0 , 0 ),
175
+ xycoords = "figure pixels" ,
176
+ zorder = 100 ,
177
+ fontsize = 9 ,
178
+ bbox = dict (boxstyle = "round" , facecolor = "w" , edgecolor = "0.5" , alpha = 0.85 ),
179
+ )
180
+ self .m ["mini_ax" ].set_visible (False )
181
+ self .m ["annotate" ].set_visible (False )
182
+
176
183
self .m ["time_vline" ] = self .time_ax .axvline (0 , color = "k" , lw = 1 )
177
184
self .m ["time_text" ] = self .time_ax .text (
178
- 0 , 0 , "" , fontsize = 8 , bbox = dict (facecolor = "w" , alpha = 0.75 )
185
+ 0 ,
186
+ 0 ,
187
+ "" ,
188
+ fontsize = 8 ,
189
+ bbox = dict (facecolor = "w" , alpha = 0.75 ),
190
+ verticalalignment = "bottom" ,
179
191
)
180
192
181
193
def update (self ):
182
- # text = []
194
+ time_text = [
195
+ (timedelta (days = int (self .now )) + datetime (1950 , 1 , 1 )).strftime ("%d/%m/%Y" )
196
+ ]
183
197
# map
184
198
xs , ys , ns = list (), list (), list ()
185
199
for j , (name , dataset ) in enumerate (self .datasets .items ()):
186
200
i = self .indexs (dataset )
201
+ self .d_indexs [name ] = i
187
202
self .m [name ]["contour_s" ].set_label (f"{ name } { len (i )} eddies" )
188
203
if len (i ) == 0 :
189
204
self .m [name ]["contour_s" ].set_data ([], [])
205
+ self .m [name ]["contour_e" ].set_data ([], [])
190
206
else :
191
- if ' contour_lon_s' in dataset .elements :
207
+ if " contour_lon_s" in dataset .elements :
192
208
self .m [name ]["contour_s" ].set_data (
193
209
flatten_line_matrix (dataset ["contour_lon_s" ][i ]),
194
210
flatten_line_matrix (dataset ["contour_lat_s" ][i ]),
195
211
)
196
- # text.append(f"{i.shape[0]}")
212
+ if "contour_lon_e" in dataset .elements :
213
+ self .m [name ]["contour_e" ].set_data (
214
+ flatten_line_matrix (dataset ["contour_lon_e" ][i ]),
215
+ flatten_line_matrix (dataset ["contour_lat_e" ][i ]),
216
+ )
217
+ time_text .append (f"{ i .shape [0 ]} " )
197
218
local_path = dataset .extract_ids (dataset ["track" ][i ])
198
219
x , y , t , n , tr = (
199
220
local_path .longitude ,
@@ -229,12 +250,11 @@ def update(self):
229
250
self .map .text (x_ , y_ , n_ ) for x_ , y_ , n_ in zip (x , y , n ) if n_ >= n_min
230
251
]
231
252
232
- self .m ["title" ].set_text (self .now )
233
253
self .map .legend ()
234
254
# time ax
235
255
x , y = self .m ["time_vline" ].get_data ()
236
256
self .m ["time_vline" ].set_data (self .now , y )
237
- # self.m["time_text"].set_text("\n".join(text ))
257
+ self .m ["time_text" ].set_text ("\n " .join (time_text ))
238
258
self .m ["time_text" ].set_position ((self .now , 0 ))
239
259
# force update
240
260
self .map .figure .canvas .draw ()
@@ -263,6 +283,30 @@ def press(self, event):
263
283
self .time_ax .press = True
264
284
self .time_ax .bg_cache = self .figure .canvas .copy_from_bbox (self .time_ax .bbox )
265
285
286
+ def get_infos (self , name , index ):
287
+ i = self .d_indexs [name ][index ]
288
+ d = self .datasets [name ]
289
+ now = d .obs [i ]
290
+ tr = now ["track" ]
291
+ nb = d .nb_obs_by_track [tr ]
292
+ i_first = d .index_from_track [tr ]
293
+ track = d .obs [i_first : i_first + nb ]
294
+ nb -= 1
295
+ t0 = timedelta (days = int (track [0 ]["time" ])) + datetime (1950 , 1 , 1 )
296
+ t1 = timedelta (days = int (track [- 1 ]["time" ])) + datetime (1950 , 1 , 1 )
297
+ txt = f"--{ name } --\n "
298
+ txt += f" { t0 } -> { t1 } \n "
299
+ txt += f" Tracks : { tr } { now ['n' ]} /{ nb } ({ now ['n' ] / nb * 100 :.2f} %)\n "
300
+ for label , n , f , u in (
301
+ ("Amp." , "amplitude" , 100 , "cm" ),
302
+ ("S. radius" , "radius_s" , 1e-3 , "km" ),
303
+ ("E. radius" , "radius_e" , 1e-3 , "km" ),
304
+ ):
305
+ v = track [n ] * f
306
+ min_ , max_ , mean_ , std_ = v .min (), v .max (), v .mean (), v .std ()
307
+ txt += f" { label } : { now [n ] * f :.1f} { u } ({ min_ :.1f} <-{ mean_ :.1f} +-{ std_ :.1f} -> { max_ :.1f} )\n "
308
+ return track , txt .strip ()
309
+
266
310
def move (self , event ):
267
311
if event .inaxes == self .time_ax and self .time_ax .press :
268
312
x , y = self .m ["time_vline" ].get_data ()
@@ -271,6 +315,49 @@ def move(self, event):
271
315
self .time_ax .draw_artist (self .m ["time_vline" ])
272
316
self .figure .canvas .blit (self .time_ax .bbox )
273
317
318
+ if event .inaxes == self .map :
319
+ touch = dict ()
320
+ for name in self .datasets .keys ():
321
+ flag , data = self .m [name ]["contour_s" ].contains (event )
322
+ if flag :
323
+ # 51 is for contour on 50 point must be rewrote
324
+ touch [name ] = data ["ind" ][0 ] // 51
325
+ a = self .m ["annotate" ]
326
+ ax = self .m ["mini_ax" ]
327
+ if touch :
328
+ if not a .get_visible ():
329
+ self .map .bg_cache = self .figure .canvas .copy_from_bbox (self .map .bbox )
330
+ a .set_visible (True )
331
+ ax .set_visible (True )
332
+ else :
333
+ self .figure .canvas .restore_region (self .map .bg_cache )
334
+ a .set_x (event .x ), a .set_y (event .y )
335
+ txt = list ()
336
+ x0_ , x1_ , y1_ = list (), list (), list ()
337
+ for name in self .datasets .keys ():
338
+ if name in touch :
339
+ track , txt_ = self .get_infos (name , touch [name ])
340
+ txt .append (txt_ )
341
+ x , y = track ["time" ], track ["radius_s" ] / 1e3
342
+ self .m [name ]["mini_line" ].set_data (x , y )
343
+ x0_ .append (x .min ()), x1_ .append (x .max ()), y1_ .append (y .max ())
344
+ else :
345
+ self .m [name ]["mini_line" ].set_data ([], [])
346
+ ax .set_xlim (min (x0_ ), max (x1_ )), ax .set_ylim (0 , max (y1_ ))
347
+ a .set_text ("\n " .join (txt ))
348
+
349
+ self .map .draw_artist (a )
350
+ self .map .draw_artist (ax )
351
+ self .figure .canvas .blit (self .map .bbox )
352
+ if not flag and self .map .bg_cache is not None and a .get_visible ():
353
+ a .set_visible (False )
354
+ ax .set_visible (False )
355
+ self .figure .canvas .restore_region (self .map .bg_cache )
356
+ self .map .draw_artist (a )
357
+ self .map .draw_artist (ax )
358
+ self .figure .canvas .blit (self .map .bbox )
359
+ self .map .bg_cache = None
360
+
274
361
def release (self , event ):
275
362
if self .time_ax .press :
276
363
self .time_ax .press = False
@@ -293,21 +380,3 @@ def adjust(self, event=None):
293
380
def show (self ):
294
381
self .update ()
295
382
plt .show ()
296
-
297
-
298
- if __name__ == "__main__" :
299
-
300
- # a_ = A.load_file(
301
- # "/home/toto/dev/work/pet/20200611_example_dataset/tracking/Anticyclonic_track_too_short.nc"
302
- # )
303
- # c_ = A.load_file(
304
- # "/home/toto/dev/work/pet/20200611_example_dataset/tracking/Cyclonic_track_too_short.nc"
305
- # )
306
- a = A .load_file (sample .get_path ("eddies_med_adt_allsat_dt2018/Anticyclonic.zarr" ))
307
- # c = A.load_file(sample.get_path("eddies_med_adt_allsat_dt2018/Cyclonic.zarr"))
308
- # g = GUI(Acyc=a, Cyc=c, Acyc_short=a_, Cyc_short=c_)
309
- g = GUI (Acyc = a )
310
- # g = GUI(Acyc_short=a_)
311
- # g = GUI(Acyc_short=a_, Cyc_short=c_)
312
- g .med ()
313
- g .show ()
0 commit comments