2222"""
2323
2424import numpy as np
25- from datetime import datetime
2625import matplotlib .pyplot as plt
26+ from datetime import datetime , timedelta
2727from matplotlib .projections import register_projection
28- import py_eddy_tracker_sample as sample
2928from .generic import flatten_line_matrix , split_line
30- from .observations .tracking import TrackEddiesObservations
3129
3230
3331try :
@@ -65,10 +63,6 @@ def end_pan(self, *args, **kwargs):
6563register_projection (GUIAxes )
6664
6765
68- class A (TrackEddiesObservations ):
69- pass
70-
71-
7266def no (* args , ** kwargs ):
7367 return False
7468
@@ -81,6 +75,7 @@ class GUI:
8175 "time_ax" ,
8276 "param_ax" ,
8377 "settings" ,
78+ "d_indexs" ,
8479 "m" ,
8580 "last_event" ,
8681 )
@@ -89,6 +84,7 @@ class GUI:
8984
9085 def __init__ (self , ** datasets ):
9186 self .datasets = datasets
87+ self .d_indexs = dict ()
9288 self .m = dict ()
9389 self .set_initial_values ()
9490 self .setup ()
@@ -140,8 +136,9 @@ def setup(self):
140136 # map
141137 self .map = self .figure .add_axes ((0 , 0.25 , 1 , 0.75 ), projection = "full_axes" )
142138 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
145142 # time ax
146143 self .time_ax = self .figure .add_axes ((0 , 0.15 , 1 , 0.1 ), facecolor = ".95" )
147144 self .time_ax .can_pan
@@ -159,41 +156,65 @@ def setup(self):
159156 self .param_ax = self .figure .add_axes ((0 , 0 , 1 , 0.15 ), facecolor = "0.2" )
160157
161158 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 ()
162161 # map
163162 for i , (name , dataset ) in enumerate (self .datasets .items ()):
163+ kwargs = dict (color = self .COLORS [i ])
164164 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 ]
173170 )
174- self .m ["title" ] = self .map .set_title ("" )
175171 # 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+
176183 self .m ["time_vline" ] = self .time_ax .axvline (0 , color = "k" , lw = 1 )
177184 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" ,
179191 )
180192
181193 def update (self ):
182- # text = []
194+ time_text = [
195+ (timedelta (days = int (self .now )) + datetime (1950 , 1 , 1 )).strftime ("%d/%m/%Y" )
196+ ]
183197 # map
184198 xs , ys , ns = list (), list (), list ()
185199 for j , (name , dataset ) in enumerate (self .datasets .items ()):
186200 i = self .indexs (dataset )
201+ self .d_indexs [name ] = i
187202 self .m [name ]["contour_s" ].set_label (f"{ name } { len (i )} eddies" )
188203 if len (i ) == 0 :
189204 self .m [name ]["contour_s" ].set_data ([], [])
205+ self .m [name ]["contour_e" ].set_data ([], [])
190206 else :
191- if ' contour_lon_s' in dataset .elements :
207+ if " contour_lon_s" in dataset .elements :
192208 self .m [name ]["contour_s" ].set_data (
193209 flatten_line_matrix (dataset ["contour_lon_s" ][i ]),
194210 flatten_line_matrix (dataset ["contour_lat_s" ][i ]),
195211 )
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 ]} " )
197218 local_path = dataset .extract_ids (dataset ["track" ][i ])
198219 x , y , t , n , tr = (
199220 local_path .longitude ,
@@ -229,12 +250,11 @@ def update(self):
229250 self .map .text (x_ , y_ , n_ ) for x_ , y_ , n_ in zip (x , y , n ) if n_ >= n_min
230251 ]
231252
232- self .m ["title" ].set_text (self .now )
233253 self .map .legend ()
234254 # time ax
235255 x , y = self .m ["time_vline" ].get_data ()
236256 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 ))
238258 self .m ["time_text" ].set_position ((self .now , 0 ))
239259 # force update
240260 self .map .figure .canvas .draw ()
@@ -263,6 +283,30 @@ def press(self, event):
263283 self .time_ax .press = True
264284 self .time_ax .bg_cache = self .figure .canvas .copy_from_bbox (self .time_ax .bbox )
265285
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+
266310 def move (self , event ):
267311 if event .inaxes == self .time_ax and self .time_ax .press :
268312 x , y = self .m ["time_vline" ].get_data ()
@@ -271,6 +315,49 @@ def move(self, event):
271315 self .time_ax .draw_artist (self .m ["time_vline" ])
272316 self .figure .canvas .blit (self .time_ax .bbox )
273317
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+
274361 def release (self , event ):
275362 if self .time_ax .press :
276363 self .time_ax .press = False
@@ -293,21 +380,3 @@ def adjust(self, event=None):
293380 def show (self ):
294381 self .update ()
295382 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