3
3
Entry point of graphic user interface
4
4
"""
5
5
6
+ import logging
6
7
from datetime import datetime
8
+ from itertools import chain
7
9
8
10
from matplotlib import pyplot
9
11
from matplotlib .collections import LineCollection
10
- from numpy import arange , empty , where
12
+ from numpy import where
11
13
12
14
from .. import EddyParser
13
- from ..generic import flatten_line_matrix
14
15
from ..gui import GUI
15
16
from ..observations .tracking import TrackEddiesObservations
16
17
from ..poly import create_vertice
17
18
19
+ logger = logging .getLogger ("pet" )
20
+
18
21
19
22
class Anim :
23
+
20
24
def __init__ (
21
25
self , eddy , intern = False , sleep_event = 0.1 , graphic_information = False , ** kwargs
22
26
):
@@ -29,11 +33,32 @@ def __init__(
29
33
self .period = self .eddy .period
30
34
self .sleep_event = sleep_event
31
35
self .mappables = list ()
36
+ self .field_color = None
37
+ self .time_field = False
32
38
self .setup (** kwargs )
33
39
34
- def setup (self , cmap = "jet" , nb_step = 25 , figsize = (8 , 6 ), ** kwargs ):
35
- cmap = pyplot .get_cmap (cmap )
36
- self .colors = cmap (arange (nb_step + 1 ) / nb_step )
40
+ def setup (
41
+ self ,
42
+ cmap = "jet" ,
43
+ lut = None ,
44
+ field_color = "time" ,
45
+ range_color = (None , None ),
46
+ nb_step = 25 ,
47
+ figsize = (8 , 6 ),
48
+ ** kwargs ,
49
+ ):
50
+ self .field_color = self .eddy [field_color ].astype ("f4" )
51
+ rg = range_color
52
+ if rg [0 ] is None and rg [1 ] is None and field_color == "time" :
53
+ self .time_field = True
54
+ else :
55
+ rg = (
56
+ self .field_color .min () if rg [0 ] is None else rg [0 ],
57
+ self .field_color .max () if rg [1 ] is None else rg [1 ],
58
+ )
59
+ self .field_color = (self .field_color - rg [0 ]) / (rg [1 ] - rg [0 ])
60
+
61
+ self .colors = pyplot .get_cmap (cmap , lut = lut )
37
62
self .nb_step = nb_step
38
63
39
64
x_min , x_max = self .x_core .min () - 2 , self .x_core .max () + 2
@@ -51,6 +76,8 @@ def setup(self, cmap="jet", nb_step=25, figsize=(8, 6), **kwargs):
51
76
# init mappable
52
77
self .txt = self .ax .text (x_min + 0.05 * d_x , y_min + 0.05 * d_y , "" , zorder = 10 )
53
78
self .segs = list ()
79
+ self .t_segs = list ()
80
+ self .c_segs = list ()
54
81
self .contour = LineCollection ([], zorder = 1 )
55
82
self .ax .add_collection (self .contour )
56
83
@@ -89,8 +116,9 @@ def show(self, infinity_loop=False):
89
116
if dt < 0 :
90
117
# self.sleep_event = dt_draw * 1.01
91
118
dt = 1e-10
119
+ if dt == 0 :
120
+ dt = 1e-10
92
121
self .fig .canvas .start_event_loop (dt )
93
-
94
122
if self .now > t1 :
95
123
break
96
124
if infinity_loop :
@@ -118,20 +146,41 @@ def func_animation(self, frame):
118
146
def update (self ):
119
147
m = self .t == self .now
120
148
if m .sum ():
121
- self .segs .append (
122
- create_vertice (
123
- flatten_line_matrix (self .x [m ]), flatten_line_matrix (self .y [m ])
149
+ segs = list ()
150
+ t = list ()
151
+ c = list ()
152
+ for i in where (m )[0 ]:
153
+ segs .append (create_vertice (self .x [i ], self .y [i ]))
154
+ c .append (self .field_color [i ])
155
+ t .append (self .now )
156
+ self .segs .append (segs )
157
+ self .c_segs .append (c )
158
+ self .t_segs .append (t )
159
+ self .contour .set_paths (chain (* self .segs ))
160
+ if self .time_field :
161
+ self .contour .set_color (
162
+ self .colors (
163
+ [
164
+ (self .nb_step - self .now + i ) / self .nb_step
165
+ for i in chain (* self .c_segs )
166
+ ]
124
167
)
125
168
)
126
169
else :
127
- self .segs .append (empty ((0 , 2 )))
128
- self .contour .set_paths (self .segs )
129
- self .contour .set_color (self .colors [- len (self .segs ) :])
130
- self .contour .set_lw (arange (len (self .segs )) / len (self .segs ) * 2.5 )
170
+ self .contour .set_color (self .colors (list (chain (* self .c_segs ))))
171
+ # linewidth will be link to time delay
172
+ self .contour .set_lw (
173
+ [
174
+ (1 - (self .now - i ) / self .nb_step ) * 2.5 if i <= self .now else 0
175
+ for i in chain (* self .t_segs )
176
+ ]
177
+ )
178
+ # Update date txt and info
131
179
txt = f"{ self .now } "
132
180
if self .graphic_informations :
133
181
txt += f"- { 1 / self .sleep_event :.0f} frame/s"
134
182
self .txt .set_text (txt )
183
+ # Update id txt
135
184
for i in where (m )[0 ]:
136
185
mappable = self .ax .text (
137
186
self .x_core [i ], self .y_core [i ], self .track [i ], fontsize = 8
@@ -143,6 +192,8 @@ def update(self):
143
192
# Remove first segment to keep only T contour
144
193
if len (self .segs ) > self .nb_step :
145
194
self .segs .pop (0 )
195
+ self .t_segs .pop (0 )
196
+ self .c_segs .pop (0 )
146
197
147
198
def draw_contour (self ):
148
199
# select contour for this time step
@@ -165,8 +216,13 @@ def keyboard(self, event):
165
216
elif event .key == "right" and self .pause :
166
217
self .next ()
167
218
elif event .key == "left" and self .pause :
219
+ # we remove 2 step to add 1 so we rewind of only one
168
220
self .segs .pop (- 1 )
169
221
self .segs .pop (- 1 )
222
+ self .t_segs .pop (- 1 )
223
+ self .t_segs .pop (- 1 )
224
+ self .c_segs .pop (- 1 )
225
+ self .c_segs .pop (- 1 )
170
226
self .prev ()
171
227
172
228
@@ -197,11 +253,22 @@ def anim():
197
253
action = "store_true" ,
198
254
help = "Longitude will be centered on first obs, if there are only one group." ,
199
255
)
256
+ parser .add_argument (
257
+ "--field" , default = "time" , help = "Field use to color contour instead of time"
258
+ )
259
+ parser .add_argument (
260
+ "--vmin" , default = None , type = float , help = "Inferior bound to color contour"
261
+ )
262
+ parser .add_argument (
263
+ "--vmax" , default = None , type = float , help = "Upper bound to color contour"
264
+ )
200
265
args = parser .parse_args ()
201
- variables = ["time" , "track" , "longitude" , "latitude" ]
266
+ variables = ["time" , "track" , "longitude" , "latitude" , args . field ]
202
267
variables .extend (TrackEddiesObservations .intern (args .intern , public_label = True ))
203
268
204
- eddies = TrackEddiesObservations .load_file (args .filename , include_vars = variables )
269
+ eddies = TrackEddiesObservations .load_file (
270
+ args .filename , include_vars = set (variables )
271
+ )
205
272
if not args .all :
206
273
if len (args .id ) == 0 :
207
274
raise Exception (
@@ -222,6 +289,9 @@ def anim():
222
289
sleep_event = args .time_sleep ,
223
290
cmap = args .cmap ,
224
291
nb_step = args .keep_step ,
292
+ field_color = args .field ,
293
+ range_color = (args .vmin , args .vmax ),
294
+ graphic_information = logger .getEffectiveLevel () == logging .DEBUG ,
225
295
)
226
296
a .show (infinity_loop = args .infinity_loop )
227
297
0 commit comments