##// END OF EJS Templates
Now alarm is a process, add SchainWarning exception for handling non-stop exceptions
jespinoza -
r1129:986a05a7d203
parent child
Show More
@@ -1,477 +1,498
1 """The admin module contains all administrative classes relating to the schain python api.
1 """The admin module contains all administrative classes relating to the schain python api.
2
2
3 The main role of this module is to send some reports. It contains a
3 The main role of this module is to send some reports. It contains a
4 notification class and a standard error handing class.
4 notification class and a standard error handing class.
5
5
6 $Id: admin.py 3966 2015-12-01 14:32:29Z miguel.urco $
6 $Id: admin.py 3966 2015-12-01 14:32:29Z miguel.urco $
7 """
7 """
8 import os
8 import os
9 import sys
9 import sys
10 import time
10 import time
11 import traceback
11 import traceback
12 import smtplib
12 import smtplib
13 import ConfigParser
13 import ConfigParser
14 import StringIO
14 import StringIO
15 from threading import Thread
15 from threading import Thread
16 from multiprocessing import Process
16 from email.mime.text import MIMEText
17 from email.mime.text import MIMEText
17 from email.mime.application import MIMEApplication
18 from email.mime.application import MIMEApplication
18 from email.mime.multipart import MIMEMultipart
19 from email.mime.multipart import MIMEMultipart
19
20
20 from schainpy.utils import log
21 from schainpy.utils import log
21 from schainpy.model.graphics.jroplot_data import popup
22 from schainpy.model.graphics.jroplot_data import popup
22
23
23 def get_path():
24 def get_path():
24 '''
25 '''
25 Return schainpy path
26 Return schainpy path
26 '''
27 '''
27
28
28 try:
29 try:
29 root = __file__
30 root = __file__
30 if os.path.islink(root):
31 if os.path.islink(root):
31 root = os.path.realpath(root)
32 root = os.path.realpath(root)
32
33
33 return os.path.dirname(os.path.abspath(root))
34 return os.path.dirname(os.path.abspath(root))
34 except:
35 except:
35 log.error('I am sorry, but something is wrong... __file__ not found')
36 log.error('I am sorry, but something is wrong... __file__ not found')
36
37
37 def alarm(modes=[1], **kwargs):
38 class Alarm(Process):
38 '''
39 '''
39 modes:
40 modes:
40 0 - All
41 0 - All
41 1 - Sound alarm
42 1 - Sound alarm
42 2 - Send email
43 2 - Send email
43 3 - Popup message
44 3 - Popup message
44 4 - Send to alarm system TODO
45 4 - Send to alarm system TODO
45 '''
46 '''
46
47
48 def __init__(self, modes=[1], **kwargs):
49 Process.__init__(self)
50 self.modes = modes
51 self.kwargs = kwargs
52
53 @staticmethod
47 def play_sound():
54 def play_sound():
48 sound = os.path.join(get_path(), 'alarm1.oga')
55 sound = os.path.join(get_path(), 'alarm1.oga')
49 if os.path.exists(sound):
56 if os.path.exists(sound):
50 for __ in range(2):
57 for __ in range(2):
51 os.system('paplay {}'.format(sound))
58 os.system('paplay {}'.format(sound))
52 time.sleep(0.5)
59 time.sleep(0.5)
53 else:
60 else:
54 log.warning('Unable to play alarm, sound file not found', 'ADMIN')
61 log.warning('Unable to play alarm, sound file not found', 'ADMIN')
55
62
63 @staticmethod
56 def send_email(**kwargs):
64 def send_email(**kwargs):
57 notifier = SchainNotify()
65 notifier = SchainNotify()
58 notifier.notify(**kwargs)
66 notifier.notify(**kwargs)
59
67
68 @staticmethod
60 def show_popup(message='Error'):
69 def show_popup(message='Error'):
61 popup(message)
70 popup(message)
62
71
72 @staticmethod
63 def send_alarm():
73 def send_alarm():
64 pass
74 pass
65
75
76 @staticmethod
66 def get_kwargs(kwargs, keys):
77 def get_kwargs(kwargs, keys):
67 ret = {}
78 ret = {}
68 for key in keys:
79 for key in keys:
69 ret[key] = kwargs[key]
80 ret[key] = kwargs[key]
70 return ret
81 return ret
71
82
72 tasks = {
83 def run(self):
73 1 : send_email,
84 tasks = {
74 2 : play_sound,
85 1 : self.send_email,
75 3 : show_popup,
86 2 : self.play_sound,
76 4 : send_alarm,
87 3 : self.show_popup,
77 }
88 4 : self.send_alarm,
78
89 }
79 tasks_args = {
90
80 1: ['email', 'message', 'subject', 'subtitle', 'filename'],
91 tasks_args = {
81 2: [],
92 1: ['email', 'message', 'subject', 'subtitle', 'filename'],
82 3: ['message'],
93 2: [],
83 4: [],
94 3: ['message'],
84 }
95 4: [],
85
96 }
86 for mode in modes:
97 procs = []
87 if mode == 0:
98 for mode in self.modes:
88 for x in tasks:
99 if 0 in self.modes:
89 t = Thread(target=tasks[x], kwargs=get_kwargs(kwargs, tasks_args[x]))
100 for x in tasks:
101 t = Thread(target=tasks[x], kwargs=self.get_kwargs(self.kwargs, tasks_args[x]))
102 t.start()
103 procs.append(t)
104 break
105 else:
106 t = Thread(target=tasks[mode], kwargs=self.get_kwargs(self.kwargs, tasks_args[mode]))
90 t.start()
107 t.start()
91 break
108 procs.append(t)
92 else:
109 for t in procs:
93 t = Thread(target=tasks[mode], kwargs=get_kwargs(kwargs, tasks_args[x]))
110 t.join()
94 t.start()
95
111
96
112
97 class SchainConfigure():
113 class SchainConfigure():
98
114
99 __DEFAULT_ADMINISTRATOR_EMAIL = "juan.espinoza@jro.igp.gob.pe"
115 __DEFAULT_ADMINISTRATOR_EMAIL = "juan.espinoza@jro.igp.gob.pe"
100 __DEFAULT_EMAIL_SERVER = "jro-zimbra.igp.gob.pe"
116 __DEFAULT_EMAIL_SERVER = "jro-zimbra.igp.gob.pe"
101 __DEFAULT_SENDER_EMAIL = "notifier-schain@jro.igp.gob.pe"
117 __DEFAULT_SENDER_EMAIL = "notifier-schain@jro.igp.gob.pe"
102 __DEFAULT_SENDER_PASS = ""
118 __DEFAULT_SENDER_PASS = ""
103
119
104 __SCHAIN_ADMINISTRATOR_EMAIL = "CONTACT"
120 __SCHAIN_ADMINISTRATOR_EMAIL = "CONTACT"
105 __SCHAIN_EMAIL_SERVER = "MAILSERVER"
121 __SCHAIN_EMAIL_SERVER = "MAILSERVER"
106 __SCHAIN_SENDER_EMAIL = "MAILSERVER_ACCOUNT"
122 __SCHAIN_SENDER_EMAIL = "MAILSERVER_ACCOUNT"
107 __SCHAIN_SENDER_PASS = "MAILSERVER_PASSWORD"
123 __SCHAIN_SENDER_PASS = "MAILSERVER_PASSWORD"
108
124
109 def __init__(self, initFile = None):
125 def __init__(self, initFile = None):
110
126
111 # Set configuration file
127 # Set configuration file
112 if (initFile == None):
128 if (initFile == None):
113 self.__confFilePath = "/etc/schain.conf"
129 self.__confFilePath = "/etc/schain.conf"
114 else:
130 else:
115 self.__confFilePath = initFile
131 self.__confFilePath = initFile
116
132
117 # open configuration file
133 # open configuration file
118 try:
134 try:
119 self.__confFile = open(self.__confFilePath, "r")
135 self.__confFile = open(self.__confFilePath, "r")
120 except IOError:
136 except IOError:
121 # can't read from file - use all hard-coded values
137 # can't read from file - use all hard-coded values
122 self.__initFromHardCode()
138 self.__initFromHardCode()
123 return
139 return
124
140
125 # create Parser using standard module ConfigParser
141 # create Parser using standard module ConfigParser
126 self.__parser = ConfigParser.ConfigParser()
142 self.__parser = ConfigParser.ConfigParser()
127
143
128 # read conf file into a StringIO with "[madrigal]\n" section heading prepended
144 # read conf file into a StringIO with "[madrigal]\n" section heading prepended
129 strConfFile = StringIO.StringIO("[schain]\n" + self.__confFile.read())
145 strConfFile = StringIO.StringIO("[schain]\n" + self.__confFile.read())
130
146
131 # parse StringIO configuration file
147 # parse StringIO configuration file
132 self.__parser.readfp(strConfFile)
148 self.__parser.readfp(strConfFile)
133
149
134 # read information from configuration file
150 # read information from configuration file
135 self.__readConfFile()
151 self.__readConfFile()
136
152
137 # close conf file
153 # close conf file
138 self.__confFile.close()
154 self.__confFile.close()
139
155
140
156
141 def __initFromHardCode(self):
157 def __initFromHardCode(self):
142
158
143 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
159 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
144 self.__sender_pass = self.__DEFAULT_SENDER_PASS
160 self.__sender_pass = self.__DEFAULT_SENDER_PASS
145 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
161 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
146 self.__email_server = self.__DEFAULT_EMAIL_SERVER
162 self.__email_server = self.__DEFAULT_EMAIL_SERVER
147
163
148 def __readConfFile(self):
164 def __readConfFile(self):
149 """__readConfFile is a private helper function that reads information from the parsed config file.
165 """__readConfFile is a private helper function that reads information from the parsed config file.
150
166
151 Inputs: None
167 Inputs: None
152
168
153 Returns: Void.
169 Returns: Void.
154
170
155 Affects: Initializes class member variables that are found in the config file.
171 Affects: Initializes class member variables that are found in the config file.
156
172
157 Exceptions: MadrigalError thrown if any key not found.
173 Exceptions: MadrigalError thrown if any key not found.
158 """
174 """
159
175
160 # get the sender email
176 # get the sender email
161 try:
177 try:
162 self.__sender_email = self.__parser.get("schain", self.__SCHAIN_SENDER_EMAIL)
178 self.__sender_email = self.__parser.get("schain", self.__SCHAIN_SENDER_EMAIL)
163 except:
179 except:
164 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
180 self.__sender_email = self.__DEFAULT_SENDER_EMAIL
165
181
166 # get the sender password
182 # get the sender password
167 try:
183 try:
168 self.__sender_pass = self.__parser.get("schain", self.__SCHAIN_SENDER_PASS)
184 self.__sender_pass = self.__parser.get("schain", self.__SCHAIN_SENDER_PASS)
169 except:
185 except:
170 self.__sender_pass = self.__DEFAULT_SENDER_PASS
186 self.__sender_pass = self.__DEFAULT_SENDER_PASS
171
187
172 # get the administrator email
188 # get the administrator email
173 try:
189 try:
174 self.__admin_email = self.__parser.get("schain", self.__SCHAIN_ADMINISTRATOR_EMAIL)
190 self.__admin_email = self.__parser.get("schain", self.__SCHAIN_ADMINISTRATOR_EMAIL)
175 except:
191 except:
176 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
192 self.__admin_email = self.__DEFAULT_ADMINISTRATOR_EMAIL
177
193
178 # get the server email
194 # get the server email
179 try:
195 try:
180 self.__email_server = self.__parser.get("schain", self.__SCHAIN_EMAIL_SERVER)
196 self.__email_server = self.__parser.get("schain", self.__SCHAIN_EMAIL_SERVER)
181 except:
197 except:
182 self.__email_server = self.__DEFAULT_EMAIL_SERVER
198 self.__email_server = self.__DEFAULT_EMAIL_SERVER
183
199
184 def getEmailServer(self):
200 def getEmailServer(self):
185
201
186 return self.__email_server
202 return self.__email_server
187
203
188 def getSenderEmail(self):
204 def getSenderEmail(self):
189
205
190 return self.__sender_email
206 return self.__sender_email
191
207
192 def getSenderPass(self):
208 def getSenderPass(self):
193
209
194 return self.__sender_pass
210 return self.__sender_pass
195
211
196 def getAdminEmail(self):
212 def getAdminEmail(self):
197
213
198 return self.__admin_email
214 return self.__admin_email
199
215
200 class SchainNotify:
216 class SchainNotify:
201 """SchainNotify is an object used to send messages to an administrator about a Schain software.
217 """SchainNotify is an object used to send messages to an administrator about a Schain software.
202
218
203 This object provides functions needed to send messages to an administrator about a Schain , for now
219 This object provides functions needed to send messages to an administrator about a Schain , for now
204 only sendAlert, which sends an email to the site administrator found is ADMIN_EMAIL
220 only sendAlert, which sends an email to the site administrator found is ADMIN_EMAIL
205
221
206 Usage example:
222 Usage example:
207
223
208 import schainpy.admin
224 import schainpy.admin
209
225
210 try:
226 try:
211
227
212 adminObj = schainpy.admin.SchainNotify()
228 adminObj = schainpy.admin.SchainNotify()
213 adminObj.sendAlert('This is important!', 'Important Message')
229 adminObj.sendAlert('This is important!', 'Important Message')
214
230
215 except schainpy.admin.SchainError, e:
231 except schainpy.admin.SchainError, e:
216
232
217 print e.getExceptionStr()
233 print e.getExceptionStr()
218
234
219
235
220 Non-standard Python modules used:
236 Non-standard Python modules used:
221 None
237 None
222
238
223 Exceptions thrown: None - Note that SchainNotify tries every trick it knows to avoid
239 Exceptions thrown: None - Note that SchainNotify tries every trick it knows to avoid
224 throwing exceptions, since this is the class that will generally be called when there is a problem.
240 throwing exceptions, since this is the class that will generally be called when there is a problem.
225
241
226 Change history:
242 Change history:
227
243
228 Written by "Miguel Urco":mailto:miguel.urco@jro.igp.gob.pe Dec. 1, 2015
244 Written by "Miguel Urco":mailto:miguel.urco@jro.igp.gob.pe Dec. 1, 2015
229 """
245 """
230
246
231 #constants
247 #constants
232
248
233 def __init__(self):
249 def __init__(self):
234 """__init__ initializes SchainNotify by getting some basic information from SchainDB and SchainSite.
250 """__init__ initializes SchainNotify by getting some basic information from SchainDB and SchainSite.
235
251
236 Note that SchainNotify tries every trick it knows to avoid throwing exceptions, since
252 Note that SchainNotify tries every trick it knows to avoid throwing exceptions, since
237 this is the class that will generally be called when there is a problem.
253 this is the class that will generally be called when there is a problem.
238
254
239 Inputs: Existing SchainDB object, by default = None.
255 Inputs: Existing SchainDB object, by default = None.
240
256
241 Returns: void
257 Returns: void
242
258
243 Affects: Initializes self.__binDir.
259 Affects: Initializes self.__binDir.
244
260
245 Exceptions: None.
261 Exceptions: None.
246 """
262 """
247
263
248 # note that the main configuration file is unavailable
264 # note that the main configuration file is unavailable
249 # the best that can be done is send an email to root using localhost mailserver
265 # the best that can be done is send an email to root using localhost mailserver
250 confObj = SchainConfigure()
266 confObj = SchainConfigure()
251
267
252 self.__emailFromAddress = confObj.getSenderEmail()
268 self.__emailFromAddress = confObj.getSenderEmail()
253 self.__emailPass = confObj.getSenderPass()
269 self.__emailPass = confObj.getSenderPass()
254 self.__emailToAddress = confObj.getAdminEmail()
270 self.__emailToAddress = confObj.getAdminEmail()
255 self.__emailServer = confObj.getEmailServer()
271 self.__emailServer = confObj.getEmailServer()
256
272
257 def sendEmail(self, email_from, email_to, subject='Error running ...', message="", subtitle="", filename="", html_format=True):
273 def sendEmail(self, email_from, email_to, subject='Error running ...', message="", subtitle="", filename="", html_format=True):
258
274
259 if not email_to:
275 if not email_to:
260 return 0
276 return 0
261
277
262 if not self.__emailServer:
278 if not self.__emailServer:
263 return 0
279 return 0
264
280
281 log.success('Sending email to {}...'.format(email_to), 'System')
282
265 msg = MIMEMultipart()
283 msg = MIMEMultipart()
266 msg['Subject'] = subject
284 msg['Subject'] = subject
267 msg['From'] = "(Python SChain API): " + email_from
285 msg['From'] = "(Python SChain API): " + email_from
268 msg['Reply-to'] = email_from
286 msg['Reply-to'] = email_from
269 msg['To'] = email_to
287 msg['To'] = email_to
270
288
271 # That is what u see if dont have an email reader:
289 # That is what u see if dont have an email reader:
272 msg.preamble = 'SChainPy'
290 msg.preamble = 'SChainPy'
273
291
274 if html_format:
292 if html_format:
275 message = "<h1> %s </h1>" %subject + "<h3>" + subtitle.replace("\n", "</h3><h3>\n") + "</h3>" + message.replace("\n", "<br>\n")
293 message = "<h1> %s </h1>" %subject + "<h3>" + subtitle.replace("\n", "</h3><h3>\n") + "</h3>" + message.replace("\n", "<br>\n")
276 message = "<html>\n" + message + '</html>'
294 message = "<html>\n" + message + '</html>'
277
295
278 # This is the textual part:
296 # This is the textual part:
279 part = MIMEText(message, "html")
297 part = MIMEText(message, "html")
280 else:
298 else:
281 message = subject + "\n" + subtitle + "\n" + message
299 message = subject + "\n" + subtitle + "\n" + message
282 part = MIMEText(message)
300 part = MIMEText(message)
283
301
284 msg.attach(part)
302 msg.attach(part)
285
303
286 if filename and os.path.isfile(filename):
304 if filename and os.path.isfile(filename):
287 # This is the binary part(The Attachment):
305 # This is the binary part(The Attachment):
288 part = MIMEApplication(open(filename,"rb").read())
306 part = MIMEApplication(open(filename,"rb").read())
289 part.add_header('Content-Disposition',
307 part.add_header('Content-Disposition',
290 'attachment',
308 'attachment',
291 filename=os.path.basename(filename))
309 filename=os.path.basename(filename))
292 msg.attach(part)
310 msg.attach(part)
293
311
294 # Create an instance in SMTP server
312 # Create an instance in SMTP server
295 try:
313 try:
296 smtp = smtplib.SMTP(self.__emailServer)
314 smtp = smtplib.SMTP(self.__emailServer)
297 except:
315 except:
298 print "***** Could not connect to server %s *****" %self.__emailServer
316 log.error('Could not connect to server {}'.format(self.__emailServer), 'System')
299 return 0
317 return 0
300
318
301 # Start the server:
319 # Start the server:
302 # smtp.ehlo()
320 # smtp.ehlo()
303 if self.__emailPass:
321 if self.__emailPass:
304 smtp.login(self.__emailFromAddress, self.__emailPass)
322 smtp.login(self.__emailFromAddress, self.__emailPass)
305
323
306 # Send the email
324 # Send the email
307 try:
325 try:
308 smtp.sendmail(msg['From'], msg['To'], msg.as_string())
326 smtp.sendmail(msg['From'], msg['To'], msg.as_string())
309 except:
327 except:
310 print "***** Could not send the email to %s *****" %msg['To']
328 log.error('Could not send the email to {}'.format(msg['To']), 'System')
311 smtp.quit()
329 smtp.quit()
312 return 0
330 return 0
313
331
314 smtp.quit()
332 smtp.quit()
333
334 log.success('Email sent ', 'System')
315
335
316 return 1
336 return 1
317
337
318 def sendAlert(self, message, subject = "", subtitle="", filename=""):
338 def sendAlert(self, message, subject = "", subtitle="", filename=""):
319 """sendAlert sends an email with the given message and optional title.
339 """sendAlert sends an email with the given message and optional title.
320
340
321 Inputs: message (string), and optional title (string)
341 Inputs: message (string), and optional title (string)
322
342
323 Returns: void
343 Returns: void
324
344
325 Affects: none
345 Affects: none
326
346
327 Exceptions: None.
347 Exceptions: None.
328 """
348 """
329
349
330 if not self.__emailToAddress:
350 if not self.__emailToAddress:
331 return 0
351 return 0
332
352
333 print "***** Sending alert to %s *****" %self.__emailToAddress
353 print "***** Sending alert to %s *****" %self.__emailToAddress
334 # set up message
354 # set up message
335
355
336 sent=self.sendEmail(email_from=self.__emailFromAddress,
356 sent=self.sendEmail(email_from=self.__emailFromAddress,
337 email_to=self.__emailToAddress,
357 email_to=self.__emailToAddress,
338 subject=subject,
358 subject=subject,
339 message=message,
359 message=message,
340 subtitle=subtitle,
360 subtitle=subtitle,
341 filename=filename)
361 filename=filename)
342
362
343 if not sent:
363 if not sent:
344 return 0
364 return 0
345
365
346 print "***** Your system administrator has been notified *****"
347
348 return 1
366 return 1
349
367
350 def notify(self, email, message, subject = "", subtitle="", filename=""):
368 def notify(self, email, message, subject = "", subtitle="", filename=""):
351 """notify sends an email with the given message and title to email.
369 """notify sends an email with the given message and title to email.
352
370
353 Inputs: email (string), message (string), and subject (string)
371 Inputs: email (string), message (string), and subject (string)
354
372
355 Returns: void
373 Returns: void
356
374
357 Affects: none
375 Affects: none
358
376
359 Exceptions: None.
377 Exceptions: None.
360 """
378 """
361
379
362 if email is None:
380 if email is None:
363 email = self.__emailToAddress
381 email = self.__emailToAddress
364
365 log.success('Notifying to %s ...'.format(email), 'ADMIN')
366
367 self.sendEmail(email_from=self.__emailFromAddress,
368 email_to=email,
369 subject=subject,
370 message=message,
371 subtitle=subtitle,
372 filename=filename)
373
382
374 log.success('Email sent', 'ADMIN')
383 self.sendEmail(
384 email_from=self.__emailFromAddress,
385 email_to=email,
386 subject=subject,
387 message=message,
388 subtitle=subtitle,
389 filename=filename
390 )
391
375
392
376 class SchainError(Exception):
393 class SchainError(Exception):
377 """SchainError is an exception class that is thrown for all known errors using Schain Py lib.
394 """SchainError is an exception class that is thrown for all known errors using Schain Py lib.
378
395
379 Usage example:
396 Usage example:
380
397
381 import sys, traceback
398 import sys, traceback
382 import schainpy.admin
399 import schainpy.admin
383
400
384 try:
401 try:
385
402
386 test = open('ImportantFile.txt', 'r')
403 test = open('ImportantFile.txt', 'r')
387
404
388 except:
405 except:
389
406
390 raise schainpy.admin.SchainError('ImportantFile.txt not opened!',
407 raise schainpy.admin.SchainError('ImportantFile.txt not opened!',
391 traceback.format_exception(sys.exc_info()[0],
408 traceback.format_exception(sys.exc_info()[0],
392 sys.exc_info()[1],
409 sys.exc_info()[1],
393 sys.exc_info()[2]))
410 sys.exc_info()[2]))
394 """
411 """
395
412
396
413
397 def __init__(self, strInterpretation, exceptionList=None):
414 def __init__(self, strInterpretation, exceptionList=None):
398 """ __init__ gathers the interpretation string along with all information from sys.exc_info().
415 """ __init__ gathers the interpretation string along with all information from sys.exc_info().
399
416
400 Inputs:
417 Inputs:
401 strIntepretation - A string representing the programmer's interpretation of
418 strIntepretation - A string representing the programmer's interpretation of
402 why the exception occurred
419 why the exception occurred
403
420
404 exceptionList - a list of strings completely describing the exception.
421 exceptionList - a list of strings completely describing the exception.
405 Generated by traceback.format_exception(sys.exc_info()[0],
422 Generated by traceback.format_exception(sys.exc_info()[0],
406 sys.exc_info()[1],
423 sys.exc_info()[1],
407 sys.exc_info()[2])
424 sys.exc_info()[2])
408
425
409 Returns: Void.
426 Returns: Void.
410
427
411 Affects: Initializes class member variables _strInterp, _strExcList.
428 Affects: Initializes class member variables _strInterp, _strExcList.
412
429
413 Exceptions: None.
430 Exceptions: None.
414 """
431 """
415
432
416 if not exceptionList:
433 if not exceptionList:
417 exceptionList = traceback.format_exception(sys.exc_info()[0],
434 exceptionList = traceback.format_exception(sys.exc_info()[0],
418 sys.exc_info()[1],
435 sys.exc_info()[1],
419 sys.exc_info()[2])
436 sys.exc_info()[2])
420
437
421 self._strInterp = strInterpretation
438 self._strInterp = strInterpretation
422 self._strExcList = exceptionList
439 self._strExcList = exceptionList
423
440
424
441
425 def getExceptionStr(self):
442 def getExceptionStr(self):
426 """ getExceptionStr returns a formatted string ready for printing completely describing the exception.
443 """ getExceptionStr returns a formatted string ready for printing completely describing the exception.
427
444
428 Inputs: None
445 Inputs: None
429
446
430 Returns: A formatted string ready for printing completely describing the exception.
447 Returns: A formatted string ready for printing completely describing the exception.
431
448
432 Affects: None
449 Affects: None
433
450
434 Exceptions: None.
451 Exceptions: None.
435 """
452 """
436 excStr = ''
453 excStr = ''
437 excStr = excStr + self._strInterp + '\n\n'
454 excStr = excStr + self._strInterp + '\n\n'
438
455
439 if self._strExcList != None:
456 if self._strExcList != None:
440 for item in self._strExcList:
457 for item in self._strExcList:
441 excStr = excStr + str(item) + '\n'
458 excStr = excStr + str(item) + '\n'
442
459
443 return excStr
460 return excStr
444
461
445 def __str__(self):
462 def __str__(self):
446
463
447 return(self.getExceptionStr())
464 return(self.getExceptionStr())
448
465
449
466
450 def getExceptionHtml(self):
467 def getExceptionHtml(self):
451 """ getExceptionHtml returns an Html formatted string completely describing the exception.
468 """ getExceptionHtml returns an Html formatted string completely describing the exception.
452
469
453 Inputs: None
470 Inputs: None
454
471
455 Returns: A formatted string ready for printing completely describing the exception.
472 Returns: A formatted string ready for printing completely describing the exception.
456
473
457 Affects: None
474 Affects: None
458
475
459 Exceptions: None.
476 Exceptions: None.
460 """
477 """
461
478
462 excStr = '<BR>The following Schain Python exception has occurred:\n<BR>'
479 excStr = '<BR>The following Schain Python exception has occurred:\n<BR>'
463 excStr = excStr + self._strInterp + '\n<BR>\n'
480 excStr = excStr + self._strInterp + '\n<BR>\n'
464
481
465 if self._strExcList != None:
482 if self._strExcList != None:
466 for item in self._strExcList:
483 for item in self._strExcList:
467 excStr = excStr + str(item) + '\n<BR>'
484 excStr = excStr + str(item) + '\n<BR>'
468
485
469 return excStr
486 return excStr
470
487
488 class SchainWarning(Exception):
489 pass
490
491
471 if __name__ == '__main__':
492 if __name__ == '__main__':
472
493
473 test = SchainNotify()
494 test = SchainNotify()
474
495
475 test.sendAlert('This is a message from the python module SchainNotify', 'Test from SchainNotify')
496 test.sendAlert('This is a message from the python module SchainNotify', 'Test from SchainNotify')
476
497
477 print 'Hopefully message sent - check.'
498 print 'Hopefully message sent - check.'
@@ -1,1324 +1,1330
1 '''
1 '''
2 Created on September , 2012
2 Created on September , 2012
3 @author:
3 @author:
4 '''
4 '''
5
5
6 import sys
6 import sys
7 import ast
7 import ast
8 import datetime
8 import datetime
9 import traceback
9 import traceback
10 import math
10 import math
11 import time
11 import time
12 from multiprocessing import Process, cpu_count
12 from multiprocessing import Process, cpu_count
13
13
14 from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring
14 from xml.etree.ElementTree import ElementTree, Element, SubElement, tostring
15 from xml.dom import minidom
15 from xml.dom import minidom
16
16
17 import schainpy
17 import schainpy
18 import schainpy.admin
18 from schainpy.admin import Alarm, SchainWarning
19 from schainpy.model import *
19 from schainpy.model import *
20 from schainpy.utils import log
20 from schainpy.utils import log
21
21
22 DTYPES = {
22 DTYPES = {
23 'Voltage': '.r',
23 'Voltage': '.r',
24 'Spectra': '.pdata'
24 'Spectra': '.pdata'
25 }
25 }
26
26
27
27
28 def MPProject(project, n=cpu_count()):
28 def MPProject(project, n=cpu_count()):
29 '''
29 '''
30 Project wrapper to run schain in n processes
30 Project wrapper to run schain in n processes
31 '''
31 '''
32
32
33 rconf = project.getReadUnitObj()
33 rconf = project.getReadUnitObj()
34 op = rconf.getOperationObj('run')
34 op = rconf.getOperationObj('run')
35 dt1 = op.getParameterValue('startDate')
35 dt1 = op.getParameterValue('startDate')
36 dt2 = op.getParameterValue('endDate')
36 dt2 = op.getParameterValue('endDate')
37 tm1 = op.getParameterValue('startTime')
37 tm1 = op.getParameterValue('startTime')
38 tm2 = op.getParameterValue('endTime')
38 tm2 = op.getParameterValue('endTime')
39 days = (dt2 - dt1).days
39 days = (dt2 - dt1).days
40
40
41 for day in range(days + 1):
41 for day in range(days + 1):
42 skip = 0
42 skip = 0
43 cursor = 0
43 cursor = 0
44 processes = []
44 processes = []
45 dt = dt1 + datetime.timedelta(day)
45 dt = dt1 + datetime.timedelta(day)
46 dt_str = dt.strftime('%Y/%m/%d')
46 dt_str = dt.strftime('%Y/%m/%d')
47 reader = JRODataReader()
47 reader = JRODataReader()
48 paths, files = reader.searchFilesOffLine(path=rconf.path,
48 paths, files = reader.searchFilesOffLine(path=rconf.path,
49 startDate=dt,
49 startDate=dt,
50 endDate=dt,
50 endDate=dt,
51 startTime=tm1,
51 startTime=tm1,
52 endTime=tm2,
52 endTime=tm2,
53 ext=DTYPES[rconf.datatype])
53 ext=DTYPES[rconf.datatype])
54 nFiles = len(files)
54 nFiles = len(files)
55 if nFiles == 0:
55 if nFiles == 0:
56 continue
56 continue
57 skip = int(math.ceil(nFiles / n))
57 skip = int(math.ceil(nFiles / n))
58 while nFiles > cursor * skip:
58 while nFiles > cursor * skip:
59 rconf.update(startDate=dt_str, endDate=dt_str, cursor=cursor,
59 rconf.update(startDate=dt_str, endDate=dt_str, cursor=cursor,
60 skip=skip)
60 skip=skip)
61 p = project.clone()
61 p = project.clone()
62 p.start()
62 p.start()
63 processes.append(p)
63 processes.append(p)
64 cursor += 1
64 cursor += 1
65
65
66 def beforeExit(exctype, value, trace):
66 def beforeExit(exctype, value, trace):
67 for process in processes:
67 for process in processes:
68 process.terminate()
68 process.terminate()
69 process.join()
69 process.join()
70 print traceback.print_tb(trace)
70 print traceback.print_tb(trace)
71
71
72 sys.excepthook = beforeExit
72 sys.excepthook = beforeExit
73
73
74 for process in processes:
74 for process in processes:
75 process.join()
75 process.join()
76 process.terminate()
76 process.terminate()
77
77
78 time.sleep(3)
78 time.sleep(3)
79
79
80
80
81 class ParameterConf():
81 class ParameterConf():
82
82
83 id = None
83 id = None
84 name = None
84 name = None
85 value = None
85 value = None
86 format = None
86 format = None
87
87
88 __formated_value = None
88 __formated_value = None
89
89
90 ELEMENTNAME = 'Parameter'
90 ELEMENTNAME = 'Parameter'
91
91
92 def __init__(self):
92 def __init__(self):
93
93
94 self.format = 'str'
94 self.format = 'str'
95
95
96 def getElementName(self):
96 def getElementName(self):
97
97
98 return self.ELEMENTNAME
98 return self.ELEMENTNAME
99
99
100 def getValue(self):
100 def getValue(self):
101
101
102 value = self.value
102 value = self.value
103 format = self.format
103 format = self.format
104
104
105 if self.__formated_value != None:
105 if self.__formated_value != None:
106
106
107 return self.__formated_value
107 return self.__formated_value
108
108
109 if format == 'obj':
109 if format == 'obj':
110 return value
110 return value
111
111
112 if format == 'str':
112 if format == 'str':
113 self.__formated_value = str(value)
113 self.__formated_value = str(value)
114 return self.__formated_value
114 return self.__formated_value
115
115
116 if value == '':
116 if value == '':
117 raise ValueError, '%s: This parameter value is empty' % self.name
117 raise ValueError, '%s: This parameter value is empty' % self.name
118
118
119 if format == 'list':
119 if format == 'list':
120 strList = value.split(',')
120 strList = value.split(',')
121
121
122 self.__formated_value = strList
122 self.__formated_value = strList
123
123
124 return self.__formated_value
124 return self.__formated_value
125
125
126 if format == 'intlist':
126 if format == 'intlist':
127 '''
127 '''
128 Example:
128 Example:
129 value = (0,1,2)
129 value = (0,1,2)
130 '''
130 '''
131
131
132 new_value = ast.literal_eval(value)
132 new_value = ast.literal_eval(value)
133
133
134 if type(new_value) not in (tuple, list):
134 if type(new_value) not in (tuple, list):
135 new_value = [int(new_value)]
135 new_value = [int(new_value)]
136
136
137 self.__formated_value = new_value
137 self.__formated_value = new_value
138
138
139 return self.__formated_value
139 return self.__formated_value
140
140
141 if format == 'floatlist':
141 if format == 'floatlist':
142 '''
142 '''
143 Example:
143 Example:
144 value = (0.5, 1.4, 2.7)
144 value = (0.5, 1.4, 2.7)
145 '''
145 '''
146
146
147 new_value = ast.literal_eval(value)
147 new_value = ast.literal_eval(value)
148
148
149 if type(new_value) not in (tuple, list):
149 if type(new_value) not in (tuple, list):
150 new_value = [float(new_value)]
150 new_value = [float(new_value)]
151
151
152 self.__formated_value = new_value
152 self.__formated_value = new_value
153
153
154 return self.__formated_value
154 return self.__formated_value
155
155
156 if format == 'date':
156 if format == 'date':
157 strList = value.split('/')
157 strList = value.split('/')
158 intList = [int(x) for x in strList]
158 intList = [int(x) for x in strList]
159 date = datetime.date(intList[0], intList[1], intList[2])
159 date = datetime.date(intList[0], intList[1], intList[2])
160
160
161 self.__formated_value = date
161 self.__formated_value = date
162
162
163 return self.__formated_value
163 return self.__formated_value
164
164
165 if format == 'time':
165 if format == 'time':
166 strList = value.split(':')
166 strList = value.split(':')
167 intList = [int(x) for x in strList]
167 intList = [int(x) for x in strList]
168 time = datetime.time(intList[0], intList[1], intList[2])
168 time = datetime.time(intList[0], intList[1], intList[2])
169
169
170 self.__formated_value = time
170 self.__formated_value = time
171
171
172 return self.__formated_value
172 return self.__formated_value
173
173
174 if format == 'pairslist':
174 if format == 'pairslist':
175 '''
175 '''
176 Example:
176 Example:
177 value = (0,1),(1,2)
177 value = (0,1),(1,2)
178 '''
178 '''
179
179
180 new_value = ast.literal_eval(value)
180 new_value = ast.literal_eval(value)
181
181
182 if type(new_value) not in (tuple, list):
182 if type(new_value) not in (tuple, list):
183 raise ValueError, '%s has to be a tuple or list of pairs' % value
183 raise ValueError, '%s has to be a tuple or list of pairs' % value
184
184
185 if type(new_value[0]) not in (tuple, list):
185 if type(new_value[0]) not in (tuple, list):
186 if len(new_value) != 2:
186 if len(new_value) != 2:
187 raise ValueError, '%s has to be a tuple or list of pairs' % value
187 raise ValueError, '%s has to be a tuple or list of pairs' % value
188 new_value = [new_value]
188 new_value = [new_value]
189
189
190 for thisPair in new_value:
190 for thisPair in new_value:
191 if len(thisPair) != 2:
191 if len(thisPair) != 2:
192 raise ValueError, '%s has to be a tuple or list of pairs' % value
192 raise ValueError, '%s has to be a tuple or list of pairs' % value
193
193
194 self.__formated_value = new_value
194 self.__formated_value = new_value
195
195
196 return self.__formated_value
196 return self.__formated_value
197
197
198 if format == 'multilist':
198 if format == 'multilist':
199 '''
199 '''
200 Example:
200 Example:
201 value = (0,1,2),(3,4,5)
201 value = (0,1,2),(3,4,5)
202 '''
202 '''
203 multiList = ast.literal_eval(value)
203 multiList = ast.literal_eval(value)
204
204
205 if type(multiList[0]) == int:
205 if type(multiList[0]) == int:
206 multiList = ast.literal_eval('(' + value + ')')
206 multiList = ast.literal_eval('(' + value + ')')
207
207
208 self.__formated_value = multiList
208 self.__formated_value = multiList
209
209
210 return self.__formated_value
210 return self.__formated_value
211
211
212 if format == 'bool':
212 if format == 'bool':
213 value = int(value)
213 value = int(value)
214
214
215 if format == 'int':
215 if format == 'int':
216 value = float(value)
216 value = float(value)
217
217
218 format_func = eval(format)
218 format_func = eval(format)
219
219
220 self.__formated_value = format_func(value)
220 self.__formated_value = format_func(value)
221
221
222 return self.__formated_value
222 return self.__formated_value
223
223
224 def updateId(self, new_id):
224 def updateId(self, new_id):
225
225
226 self.id = str(new_id)
226 self.id = str(new_id)
227
227
228 def setup(self, id, name, value, format='str'):
228 def setup(self, id, name, value, format='str'):
229 self.id = str(id)
229 self.id = str(id)
230 self.name = name
230 self.name = name
231 if format == 'obj':
231 if format == 'obj':
232 self.value = value
232 self.value = value
233 else:
233 else:
234 self.value = str(value)
234 self.value = str(value)
235 self.format = str.lower(format)
235 self.format = str.lower(format)
236
236
237 self.getValue()
237 self.getValue()
238
238
239 return 1
239 return 1
240
240
241 def update(self, name, value, format='str'):
241 def update(self, name, value, format='str'):
242
242
243 self.name = name
243 self.name = name
244 self.value = str(value)
244 self.value = str(value)
245 self.format = format
245 self.format = format
246
246
247 def makeXml(self, opElement):
247 def makeXml(self, opElement):
248 if self.name not in ('queue',):
248 if self.name not in ('queue',):
249 parmElement = SubElement(opElement, self.ELEMENTNAME)
249 parmElement = SubElement(opElement, self.ELEMENTNAME)
250 parmElement.set('id', str(self.id))
250 parmElement.set('id', str(self.id))
251 parmElement.set('name', self.name)
251 parmElement.set('name', self.name)
252 parmElement.set('value', self.value)
252 parmElement.set('value', self.value)
253 parmElement.set('format', self.format)
253 parmElement.set('format', self.format)
254
254
255 def readXml(self, parmElement):
255 def readXml(self, parmElement):
256
256
257 self.id = parmElement.get('id')
257 self.id = parmElement.get('id')
258 self.name = parmElement.get('name')
258 self.name = parmElement.get('name')
259 self.value = parmElement.get('value')
259 self.value = parmElement.get('value')
260 self.format = str.lower(parmElement.get('format'))
260 self.format = str.lower(parmElement.get('format'))
261
261
262 # Compatible with old signal chain version
262 # Compatible with old signal chain version
263 if self.format == 'int' and self.name == 'idfigure':
263 if self.format == 'int' and self.name == 'idfigure':
264 self.name = 'id'
264 self.name = 'id'
265
265
266 def printattr(self):
266 def printattr(self):
267
267
268 print 'Parameter[%s]: name = %s, value = %s, format = %s' % (self.id, self.name, self.value, self.format)
268 print 'Parameter[%s]: name = %s, value = %s, format = %s' % (self.id, self.name, self.value, self.format)
269
269
270
270
271 class OperationConf():
271 class OperationConf():
272
272
273 id = None
273 id = None
274 name = None
274 name = None
275 priority = None
275 priority = None
276 type = None
276 type = None
277
277
278 parmConfObjList = []
278 parmConfObjList = []
279
279
280 ELEMENTNAME = 'Operation'
280 ELEMENTNAME = 'Operation'
281
281
282 def __init__(self):
282 def __init__(self):
283
283
284 self.id = '0'
284 self.id = '0'
285 self.name = None
285 self.name = None
286 self.priority = None
286 self.priority = None
287 self.type = 'self'
287 self.type = 'self'
288
288
289 def __getNewId(self):
289 def __getNewId(self):
290
290
291 return int(self.id) * 10 + len(self.parmConfObjList) + 1
291 return int(self.id) * 10 + len(self.parmConfObjList) + 1
292
292
293 def updateId(self, new_id):
293 def updateId(self, new_id):
294
294
295 self.id = str(new_id)
295 self.id = str(new_id)
296
296
297 n = 1
297 n = 1
298 for parmObj in self.parmConfObjList:
298 for parmObj in self.parmConfObjList:
299
299
300 idParm = str(int(new_id) * 10 + n)
300 idParm = str(int(new_id) * 10 + n)
301 parmObj.updateId(idParm)
301 parmObj.updateId(idParm)
302
302
303 n += 1
303 n += 1
304
304
305 def getElementName(self):
305 def getElementName(self):
306
306
307 return self.ELEMENTNAME
307 return self.ELEMENTNAME
308
308
309 def getParameterObjList(self):
309 def getParameterObjList(self):
310
310
311 return self.parmConfObjList
311 return self.parmConfObjList
312
312
313 def getParameterObj(self, parameterName):
313 def getParameterObj(self, parameterName):
314
314
315 for parmConfObj in self.parmConfObjList:
315 for parmConfObj in self.parmConfObjList:
316
316
317 if parmConfObj.name != parameterName:
317 if parmConfObj.name != parameterName:
318 continue
318 continue
319
319
320 return parmConfObj
320 return parmConfObj
321
321
322 return None
322 return None
323
323
324 def getParameterObjfromValue(self, parameterValue):
324 def getParameterObjfromValue(self, parameterValue):
325
325
326 for parmConfObj in self.parmConfObjList:
326 for parmConfObj in self.parmConfObjList:
327
327
328 if parmConfObj.getValue() != parameterValue:
328 if parmConfObj.getValue() != parameterValue:
329 continue
329 continue
330
330
331 return parmConfObj.getValue()
331 return parmConfObj.getValue()
332
332
333 return None
333 return None
334
334
335 def getParameterValue(self, parameterName):
335 def getParameterValue(self, parameterName):
336
336
337 parameterObj = self.getParameterObj(parameterName)
337 parameterObj = self.getParameterObj(parameterName)
338
338
339 # if not parameterObj:
339 # if not parameterObj:
340 # return None
340 # return None
341
341
342 value = parameterObj.getValue()
342 value = parameterObj.getValue()
343
343
344 return value
344 return value
345
345
346 def getKwargs(self):
346 def getKwargs(self):
347
347
348 kwargs = {}
348 kwargs = {}
349
349
350 for parmConfObj in self.parmConfObjList:
350 for parmConfObj in self.parmConfObjList:
351 if self.name == 'run' and parmConfObj.name == 'datatype':
351 if self.name == 'run' and parmConfObj.name == 'datatype':
352 continue
352 continue
353
353
354 kwargs[parmConfObj.name] = parmConfObj.getValue()
354 kwargs[parmConfObj.name] = parmConfObj.getValue()
355
355
356 return kwargs
356 return kwargs
357
357
358 def setup(self, id, name, priority, type):
358 def setup(self, id, name, priority, type):
359
359
360 self.id = str(id)
360 self.id = str(id)
361 self.name = name
361 self.name = name
362 self.type = type
362 self.type = type
363 self.priority = priority
363 self.priority = priority
364
364
365 self.parmConfObjList = []
365 self.parmConfObjList = []
366
366
367 def removeParameters(self):
367 def removeParameters(self):
368
368
369 for obj in self.parmConfObjList:
369 for obj in self.parmConfObjList:
370 del obj
370 del obj
371
371
372 self.parmConfObjList = []
372 self.parmConfObjList = []
373
373
374 def addParameter(self, name, value, format='str'):
374 def addParameter(self, name, value, format='str'):
375
375
376 if value is None:
376 if value is None:
377 return None
377 return None
378 id = self.__getNewId()
378 id = self.__getNewId()
379
379
380 parmConfObj = ParameterConf()
380 parmConfObj = ParameterConf()
381 if not parmConfObj.setup(id, name, value, format):
381 if not parmConfObj.setup(id, name, value, format):
382 return None
382 return None
383
383
384 self.parmConfObjList.append(parmConfObj)
384 self.parmConfObjList.append(parmConfObj)
385
385
386 return parmConfObj
386 return parmConfObj
387
387
388 def changeParameter(self, name, value, format='str'):
388 def changeParameter(self, name, value, format='str'):
389
389
390 parmConfObj = self.getParameterObj(name)
390 parmConfObj = self.getParameterObj(name)
391 parmConfObj.update(name, value, format)
391 parmConfObj.update(name, value, format)
392
392
393 return parmConfObj
393 return parmConfObj
394
394
395 def makeXml(self, procUnitElement):
395 def makeXml(self, procUnitElement):
396
396
397 opElement = SubElement(procUnitElement, self.ELEMENTNAME)
397 opElement = SubElement(procUnitElement, self.ELEMENTNAME)
398 opElement.set('id', str(self.id))
398 opElement.set('id', str(self.id))
399 opElement.set('name', self.name)
399 opElement.set('name', self.name)
400 opElement.set('type', self.type)
400 opElement.set('type', self.type)
401 opElement.set('priority', str(self.priority))
401 opElement.set('priority', str(self.priority))
402
402
403 for parmConfObj in self.parmConfObjList:
403 for parmConfObj in self.parmConfObjList:
404 parmConfObj.makeXml(opElement)
404 parmConfObj.makeXml(opElement)
405
405
406 def readXml(self, opElement):
406 def readXml(self, opElement):
407
407
408 self.id = opElement.get('id')
408 self.id = opElement.get('id')
409 self.name = opElement.get('name')
409 self.name = opElement.get('name')
410 self.type = opElement.get('type')
410 self.type = opElement.get('type')
411 self.priority = opElement.get('priority')
411 self.priority = opElement.get('priority')
412
412
413 # Compatible with old signal chain version
413 # Compatible with old signal chain version
414 # Use of 'run' method instead 'init'
414 # Use of 'run' method instead 'init'
415 if self.type == 'self' and self.name == 'init':
415 if self.type == 'self' and self.name == 'init':
416 self.name = 'run'
416 self.name = 'run'
417
417
418 self.parmConfObjList = []
418 self.parmConfObjList = []
419
419
420 parmElementList = opElement.iter(ParameterConf().getElementName())
420 parmElementList = opElement.iter(ParameterConf().getElementName())
421
421
422 for parmElement in parmElementList:
422 for parmElement in parmElementList:
423 parmConfObj = ParameterConf()
423 parmConfObj = ParameterConf()
424 parmConfObj.readXml(parmElement)
424 parmConfObj.readXml(parmElement)
425
425
426 # Compatible with old signal chain version
426 # Compatible with old signal chain version
427 # If an 'plot' OPERATION is found, changes name operation by the value of its type PARAMETER
427 # If an 'plot' OPERATION is found, changes name operation by the value of its type PARAMETER
428 if self.type != 'self' and self.name == 'Plot':
428 if self.type != 'self' and self.name == 'Plot':
429 if parmConfObj.format == 'str' and parmConfObj.name == 'type':
429 if parmConfObj.format == 'str' and parmConfObj.name == 'type':
430 self.name = parmConfObj.value
430 self.name = parmConfObj.value
431 continue
431 continue
432
432
433 self.parmConfObjList.append(parmConfObj)
433 self.parmConfObjList.append(parmConfObj)
434
434
435 def printattr(self):
435 def printattr(self):
436
436
437 print '%s[%s]: name = %s, type = %s, priority = %s' % (self.ELEMENTNAME,
437 print '%s[%s]: name = %s, type = %s, priority = %s' % (self.ELEMENTNAME,
438 self.id,
438 self.id,
439 self.name,
439 self.name,
440 self.type,
440 self.type,
441 self.priority)
441 self.priority)
442
442
443 for parmConfObj in self.parmConfObjList:
443 for parmConfObj in self.parmConfObjList:
444 parmConfObj.printattr()
444 parmConfObj.printattr()
445
445
446 def createObject(self, plotter_queue=None):
446 def createObject(self, plotter_queue=None):
447
447
448 if self.type == 'self':
448 if self.type == 'self':
449 raise ValueError, 'This operation type cannot be created'
449 raise ValueError, 'This operation type cannot be created'
450
450
451 if self.type == 'plotter':
451 if self.type == 'plotter':
452 if not plotter_queue:
452 if not plotter_queue:
453 raise ValueError, 'plotter_queue is not defined. Use:\nmyProject = Project()\nmyProject.setPlotterQueue(plotter_queue)'
453 raise ValueError, 'plotter_queue is not defined. Use:\nmyProject = Project()\nmyProject.setPlotterQueue(plotter_queue)'
454
454
455 opObj = Plotter(self.name, plotter_queue)
455 opObj = Plotter(self.name, plotter_queue)
456
456
457 if self.type == 'external' or self.type == 'other':
457 if self.type == 'external' or self.type == 'other':
458
458
459 className = eval(self.name)
459 className = eval(self.name)
460 kwargs = self.getKwargs()
460 kwargs = self.getKwargs()
461
461
462 opObj = className(**kwargs)
462 opObj = className(**kwargs)
463
463
464 return opObj
464 return opObj
465
465
466
466
467 class ProcUnitConf():
467 class ProcUnitConf():
468
468
469 id = None
469 id = None
470 name = None
470 name = None
471 datatype = None
471 datatype = None
472 inputId = None
472 inputId = None
473 parentId = None
473 parentId = None
474
474
475 opConfObjList = []
475 opConfObjList = []
476
476
477 procUnitObj = None
477 procUnitObj = None
478 opObjList = []
478 opObjList = []
479
479
480 ELEMENTNAME = 'ProcUnit'
480 ELEMENTNAME = 'ProcUnit'
481
481
482 def __init__(self):
482 def __init__(self):
483
483
484 self.id = None
484 self.id = None
485 self.datatype = None
485 self.datatype = None
486 self.name = None
486 self.name = None
487 self.inputId = None
487 self.inputId = None
488
488
489 self.opConfObjList = []
489 self.opConfObjList = []
490
490
491 self.procUnitObj = None
491 self.procUnitObj = None
492 self.opObjDict = {}
492 self.opObjDict = {}
493
493
494 def __getPriority(self):
494 def __getPriority(self):
495
495
496 return len(self.opConfObjList) + 1
496 return len(self.opConfObjList) + 1
497
497
498 def __getNewId(self):
498 def __getNewId(self):
499
499
500 return int(self.id) * 10 + len(self.opConfObjList) + 1
500 return int(self.id) * 10 + len(self.opConfObjList) + 1
501
501
502 def getElementName(self):
502 def getElementName(self):
503
503
504 return self.ELEMENTNAME
504 return self.ELEMENTNAME
505
505
506 def getId(self):
506 def getId(self):
507
507
508 return self.id
508 return self.id
509
509
510 def updateId(self, new_id, parentId=parentId):
510 def updateId(self, new_id, parentId=parentId):
511
511
512 new_id = int(parentId) * 10 + (int(self.id) % 10)
512 new_id = int(parentId) * 10 + (int(self.id) % 10)
513 new_inputId = int(parentId) * 10 + (int(self.inputId) % 10)
513 new_inputId = int(parentId) * 10 + (int(self.inputId) % 10)
514
514
515 # If this proc unit has not inputs
515 # If this proc unit has not inputs
516 if self.inputId == '0':
516 if self.inputId == '0':
517 new_inputId = 0
517 new_inputId = 0
518
518
519 n = 1
519 n = 1
520 for opConfObj in self.opConfObjList:
520 for opConfObj in self.opConfObjList:
521
521
522 idOp = str(int(new_id) * 10 + n)
522 idOp = str(int(new_id) * 10 + n)
523 opConfObj.updateId(idOp)
523 opConfObj.updateId(idOp)
524
524
525 n += 1
525 n += 1
526
526
527 self.parentId = str(parentId)
527 self.parentId = str(parentId)
528 self.id = str(new_id)
528 self.id = str(new_id)
529 self.inputId = str(new_inputId)
529 self.inputId = str(new_inputId)
530
530
531 def getInputId(self):
531 def getInputId(self):
532
532
533 return self.inputId
533 return self.inputId
534
534
535 def getOperationObjList(self):
535 def getOperationObjList(self):
536
536
537 return self.opConfObjList
537 return self.opConfObjList
538
538
539 def getOperationObj(self, name=None):
539 def getOperationObj(self, name=None):
540
540
541 for opConfObj in self.opConfObjList:
541 for opConfObj in self.opConfObjList:
542
542
543 if opConfObj.name != name:
543 if opConfObj.name != name:
544 continue
544 continue
545
545
546 return opConfObj
546 return opConfObj
547
547
548 return None
548 return None
549
549
550 def getOpObjfromParamValue(self, value=None):
550 def getOpObjfromParamValue(self, value=None):
551
551
552 for opConfObj in self.opConfObjList:
552 for opConfObj in self.opConfObjList:
553 if opConfObj.getParameterObjfromValue(parameterValue=value) != value:
553 if opConfObj.getParameterObjfromValue(parameterValue=value) != value:
554 continue
554 continue
555 return opConfObj
555 return opConfObj
556 return None
556 return None
557
557
558 def getProcUnitObj(self):
558 def getProcUnitObj(self):
559
559
560 return self.procUnitObj
560 return self.procUnitObj
561
561
562 def setup(self, id, name, datatype, inputId, parentId=None):
562 def setup(self, id, name, datatype, inputId, parentId=None):
563
563
564 # Compatible with old signal chain version
564 # Compatible with old signal chain version
565 if datatype == None and name == None:
565 if datatype == None and name == None:
566 raise ValueError, 'datatype or name should be defined'
566 raise ValueError, 'datatype or name should be defined'
567
567
568 if name == None:
568 if name == None:
569 if 'Proc' in datatype:
569 if 'Proc' in datatype:
570 name = datatype
570 name = datatype
571 else:
571 else:
572 name = '%sProc' % (datatype)
572 name = '%sProc' % (datatype)
573
573
574 if datatype == None:
574 if datatype == None:
575 datatype = name.replace('Proc', '')
575 datatype = name.replace('Proc', '')
576
576
577 self.id = str(id)
577 self.id = str(id)
578 self.name = name
578 self.name = name
579 self.datatype = datatype
579 self.datatype = datatype
580 self.inputId = inputId
580 self.inputId = inputId
581 self.parentId = parentId
581 self.parentId = parentId
582
582
583 self.opConfObjList = []
583 self.opConfObjList = []
584
584
585 self.addOperation(name='run', optype='self')
585 self.addOperation(name='run', optype='self')
586
586
587 def removeOperations(self):
587 def removeOperations(self):
588
588
589 for obj in self.opConfObjList:
589 for obj in self.opConfObjList:
590 del obj
590 del obj
591
591
592 self.opConfObjList = []
592 self.opConfObjList = []
593 self.addOperation(name='run')
593 self.addOperation(name='run')
594
594
595 def addParameter(self, **kwargs):
595 def addParameter(self, **kwargs):
596 '''
596 '''
597 Add parameters to 'run' operation
597 Add parameters to 'run' operation
598 '''
598 '''
599 opObj = self.opConfObjList[0]
599 opObj = self.opConfObjList[0]
600
600
601 opObj.addParameter(**kwargs)
601 opObj.addParameter(**kwargs)
602
602
603 return opObj
603 return opObj
604
604
605 def addOperation(self, name, optype='self'):
605 def addOperation(self, name, optype='self'):
606
606
607 id = self.__getNewId()
607 id = self.__getNewId()
608 priority = self.__getPriority()
608 priority = self.__getPriority()
609
609
610 opConfObj = OperationConf()
610 opConfObj = OperationConf()
611 opConfObj.setup(id, name=name, priority=priority, type=optype)
611 opConfObj.setup(id, name=name, priority=priority, type=optype)
612
612
613 self.opConfObjList.append(opConfObj)
613 self.opConfObjList.append(opConfObj)
614
614
615 return opConfObj
615 return opConfObj
616
616
617 def makeXml(self, projectElement):
617 def makeXml(self, projectElement):
618
618
619 procUnitElement = SubElement(projectElement, self.ELEMENTNAME)
619 procUnitElement = SubElement(projectElement, self.ELEMENTNAME)
620 procUnitElement.set('id', str(self.id))
620 procUnitElement.set('id', str(self.id))
621 procUnitElement.set('name', self.name)
621 procUnitElement.set('name', self.name)
622 procUnitElement.set('datatype', self.datatype)
622 procUnitElement.set('datatype', self.datatype)
623 procUnitElement.set('inputId', str(self.inputId))
623 procUnitElement.set('inputId', str(self.inputId))
624
624
625 for opConfObj in self.opConfObjList:
625 for opConfObj in self.opConfObjList:
626 opConfObj.makeXml(procUnitElement)
626 opConfObj.makeXml(procUnitElement)
627
627
628 def readXml(self, upElement):
628 def readXml(self, upElement):
629
629
630 self.id = upElement.get('id')
630 self.id = upElement.get('id')
631 self.name = upElement.get('name')
631 self.name = upElement.get('name')
632 self.datatype = upElement.get('datatype')
632 self.datatype = upElement.get('datatype')
633 self.inputId = upElement.get('inputId')
633 self.inputId = upElement.get('inputId')
634
634
635 if self.ELEMENTNAME == 'ReadUnit':
635 if self.ELEMENTNAME == 'ReadUnit':
636 self.datatype = self.datatype.replace('Reader', '')
636 self.datatype = self.datatype.replace('Reader', '')
637
637
638 if self.ELEMENTNAME == 'ProcUnit':
638 if self.ELEMENTNAME == 'ProcUnit':
639 self.datatype = self.datatype.replace('Proc', '')
639 self.datatype = self.datatype.replace('Proc', '')
640
640
641 if self.inputId == 'None':
641 if self.inputId == 'None':
642 self.inputId = '0'
642 self.inputId = '0'
643
643
644 self.opConfObjList = []
644 self.opConfObjList = []
645
645
646 opElementList = upElement.iter(OperationConf().getElementName())
646 opElementList = upElement.iter(OperationConf().getElementName())
647
647
648 for opElement in opElementList:
648 for opElement in opElementList:
649 opConfObj = OperationConf()
649 opConfObj = OperationConf()
650 opConfObj.readXml(opElement)
650 opConfObj.readXml(opElement)
651 self.opConfObjList.append(opConfObj)
651 self.opConfObjList.append(opConfObj)
652
652
653 def printattr(self):
653 def printattr(self):
654
654
655 print '%s[%s]: name = %s, datatype = %s, inputId = %s' % (self.ELEMENTNAME,
655 print '%s[%s]: name = %s, datatype = %s, inputId = %s' % (self.ELEMENTNAME,
656 self.id,
656 self.id,
657 self.name,
657 self.name,
658 self.datatype,
658 self.datatype,
659 self.inputId)
659 self.inputId)
660
660
661 for opConfObj in self.opConfObjList:
661 for opConfObj in self.opConfObjList:
662 opConfObj.printattr()
662 opConfObj.printattr()
663
663
664 def getKwargs(self):
664 def getKwargs(self):
665
665
666 opObj = self.opConfObjList[0]
666 opObj = self.opConfObjList[0]
667 kwargs = opObj.getKwargs()
667 kwargs = opObj.getKwargs()
668
668
669 return kwargs
669 return kwargs
670
670
671 def createObjects(self, plotter_queue=None):
671 def createObjects(self, plotter_queue=None):
672
672
673 className = eval(self.name)
673 className = eval(self.name)
674 kwargs = self.getKwargs()
674 kwargs = self.getKwargs()
675 procUnitObj = className(**kwargs)
675 procUnitObj = className(**kwargs)
676
676
677 for opConfObj in self.opConfObjList:
677 for opConfObj in self.opConfObjList:
678
678
679 if opConfObj.type == 'self' and self.name == 'run':
679 if opConfObj.type == 'self' and self.name == 'run':
680 continue
680 continue
681 elif opConfObj.type == 'self':
681 elif opConfObj.type == 'self':
682 procUnitObj.addOperationKwargs(
682 procUnitObj.addOperationKwargs(
683 opConfObj.id, **opConfObj.getKwargs())
683 opConfObj.id, **opConfObj.getKwargs())
684 continue
684 continue
685
685
686 opObj = opConfObj.createObject(plotter_queue)
686 opObj = opConfObj.createObject(plotter_queue)
687
687
688 self.opObjDict[opConfObj.id] = opObj
688 self.opObjDict[opConfObj.id] = opObj
689
689
690 procUnitObj.addOperation(opObj, opConfObj.id)
690 procUnitObj.addOperation(opObj, opConfObj.id)
691
691
692 self.procUnitObj = procUnitObj
692 self.procUnitObj = procUnitObj
693
693
694 return procUnitObj
694 return procUnitObj
695
695
696 def run(self):
696 def run(self):
697
697
698 is_ok = False
698 is_ok = False
699
699
700 for opConfObj in self.opConfObjList:
700 for opConfObj in self.opConfObjList:
701
701
702 kwargs = {}
702 kwargs = {}
703 for parmConfObj in opConfObj.getParameterObjList():
703 for parmConfObj in opConfObj.getParameterObjList():
704 if opConfObj.name == 'run' and parmConfObj.name == 'datatype':
704 if opConfObj.name == 'run' and parmConfObj.name == 'datatype':
705 continue
705 continue
706
706
707 kwargs[parmConfObj.name] = parmConfObj.getValue()
707 kwargs[parmConfObj.name] = parmConfObj.getValue()
708
708
709 sts = self.procUnitObj.call(opType=opConfObj.type,
709 sts = self.procUnitObj.call(opType=opConfObj.type,
710 opName=opConfObj.name,
710 opName=opConfObj.name,
711 opId=opConfObj.id)
711 opId=opConfObj.id)
712
712
713 is_ok = is_ok or sts
713 is_ok = is_ok or sts
714
714
715 return is_ok
715 return is_ok
716
716
717 def close(self):
717 def close(self):
718
718
719 for opConfObj in self.opConfObjList:
719 for opConfObj in self.opConfObjList:
720 if opConfObj.type == 'self':
720 if opConfObj.type == 'self':
721 continue
721 continue
722
722
723 opObj = self.procUnitObj.getOperationObj(opConfObj.id)
723 opObj = self.procUnitObj.getOperationObj(opConfObj.id)
724 opObj.close()
724 opObj.close()
725
725
726 self.procUnitObj.close()
726 self.procUnitObj.close()
727
727
728 return
728 return
729
729
730
730
731 class ReadUnitConf(ProcUnitConf):
731 class ReadUnitConf(ProcUnitConf):
732
732
733 path = None
733 path = None
734 startDate = None
734 startDate = None
735 endDate = None
735 endDate = None
736 startTime = None
736 startTime = None
737 endTime = None
737 endTime = None
738
738
739 ELEMENTNAME = 'ReadUnit'
739 ELEMENTNAME = 'ReadUnit'
740
740
741 def __init__(self):
741 def __init__(self):
742
742
743 self.id = None
743 self.id = None
744 self.datatype = None
744 self.datatype = None
745 self.name = None
745 self.name = None
746 self.inputId = None
746 self.inputId = None
747
747
748 self.parentId = None
748 self.parentId = None
749
749
750 self.opConfObjList = []
750 self.opConfObjList = []
751 self.opObjList = []
751 self.opObjList = []
752
752
753 def getElementName(self):
753 def getElementName(self):
754
754
755 return self.ELEMENTNAME
755 return self.ELEMENTNAME
756
756
757 def setup(self, id, name, datatype, path='', startDate='', endDate='',
757 def setup(self, id, name, datatype, path='', startDate='', endDate='',
758 startTime='', endTime='', parentId=None, server=None, **kwargs):
758 startTime='', endTime='', parentId=None, server=None, **kwargs):
759
759
760 # Compatible with old signal chain version
760 # Compatible with old signal chain version
761 if datatype == None and name == None:
761 if datatype == None and name == None:
762 raise ValueError, 'datatype or name should be defined'
762 raise ValueError, 'datatype or name should be defined'
763 if name == None:
763 if name == None:
764 if 'Reader' in datatype:
764 if 'Reader' in datatype:
765 name = datatype
765 name = datatype
766 datatype = name.replace('Reader','')
766 datatype = name.replace('Reader','')
767 else:
767 else:
768 name = '{}Reader'.format(datatype)
768 name = '{}Reader'.format(datatype)
769 if datatype == None:
769 if datatype == None:
770 if 'Reader' in name:
770 if 'Reader' in name:
771 datatype = name.replace('Reader','')
771 datatype = name.replace('Reader','')
772 else:
772 else:
773 datatype = name
773 datatype = name
774 name = '{}Reader'.format(name)
774 name = '{}Reader'.format(name)
775
775
776 self.id = id
776 self.id = id
777 self.name = name
777 self.name = name
778 self.datatype = datatype
778 self.datatype = datatype
779 if path != '':
779 if path != '':
780 self.path = os.path.abspath(path)
780 self.path = os.path.abspath(path)
781 self.startDate = startDate
781 self.startDate = startDate
782 self.endDate = endDate
782 self.endDate = endDate
783 self.startTime = startTime
783 self.startTime = startTime
784 self.endTime = endTime
784 self.endTime = endTime
785 self.inputId = '0'
785 self.inputId = '0'
786 self.parentId = parentId
786 self.parentId = parentId
787 self.server = server
787 self.server = server
788 self.addRunOperation(**kwargs)
788 self.addRunOperation(**kwargs)
789
789
790 def update(self, **kwargs):
790 def update(self, **kwargs):
791
791
792 if 'datatype' in kwargs:
792 if 'datatype' in kwargs:
793 datatype = kwargs.pop('datatype')
793 datatype = kwargs.pop('datatype')
794 if 'Reader' in datatype:
794 if 'Reader' in datatype:
795 self.name = datatype
795 self.name = datatype
796 else:
796 else:
797 self.name = '%sReader' % (datatype)
797 self.name = '%sReader' % (datatype)
798 self.datatype = self.name.replace('Reader', '')
798 self.datatype = self.name.replace('Reader', '')
799
799
800 attrs = ('path', 'startDate', 'endDate',
800 attrs = ('path', 'startDate', 'endDate',
801 'startTime', 'endTime', 'parentId')
801 'startTime', 'endTime', 'parentId')
802
802
803 for attr in attrs:
803 for attr in attrs:
804 if attr in kwargs:
804 if attr in kwargs:
805 setattr(self, attr, kwargs.pop(attr))
805 setattr(self, attr, kwargs.pop(attr))
806
806
807 self.inputId = '0'
807 self.inputId = '0'
808 self.updateRunOperation(**kwargs)
808 self.updateRunOperation(**kwargs)
809
809
810 def removeOperations(self):
810 def removeOperations(self):
811
811
812 for obj in self.opConfObjList:
812 for obj in self.opConfObjList:
813 del obj
813 del obj
814
814
815 self.opConfObjList = []
815 self.opConfObjList = []
816
816
817 def addRunOperation(self, **kwargs):
817 def addRunOperation(self, **kwargs):
818
818
819 opObj = self.addOperation(name='run', optype='self')
819 opObj = self.addOperation(name='run', optype='self')
820
820
821 if self.server is None:
821 if self.server is None:
822 opObj.addParameter(
822 opObj.addParameter(
823 name='datatype', value=self.datatype, format='str')
823 name='datatype', value=self.datatype, format='str')
824 opObj.addParameter(name='path', value=self.path, format='str')
824 opObj.addParameter(name='path', value=self.path, format='str')
825 opObj.addParameter(
825 opObj.addParameter(
826 name='startDate', value=self.startDate, format='date')
826 name='startDate', value=self.startDate, format='date')
827 opObj.addParameter(
827 opObj.addParameter(
828 name='endDate', value=self.endDate, format='date')
828 name='endDate', value=self.endDate, format='date')
829 opObj.addParameter(
829 opObj.addParameter(
830 name='startTime', value=self.startTime, format='time')
830 name='startTime', value=self.startTime, format='time')
831 opObj.addParameter(
831 opObj.addParameter(
832 name='endTime', value=self.endTime, format='time')
832 name='endTime', value=self.endTime, format='time')
833
833
834 for key, value in kwargs.items():
834 for key, value in kwargs.items():
835 opObj.addParameter(name=key, value=value,
835 opObj.addParameter(name=key, value=value,
836 format=type(value).__name__)
836 format=type(value).__name__)
837 else:
837 else:
838 opObj.addParameter(name='server', value=self.server, format='str')
838 opObj.addParameter(name='server', value=self.server, format='str')
839
839
840 return opObj
840 return opObj
841
841
842 def updateRunOperation(self, **kwargs):
842 def updateRunOperation(self, **kwargs):
843
843
844 opObj = self.getOperationObj(name='run')
844 opObj = self.getOperationObj(name='run')
845 opObj.removeParameters()
845 opObj.removeParameters()
846
846
847 opObj.addParameter(name='datatype', value=self.datatype, format='str')
847 opObj.addParameter(name='datatype', value=self.datatype, format='str')
848 opObj.addParameter(name='path', value=self.path, format='str')
848 opObj.addParameter(name='path', value=self.path, format='str')
849 opObj.addParameter(
849 opObj.addParameter(
850 name='startDate', value=self.startDate, format='date')
850 name='startDate', value=self.startDate, format='date')
851 opObj.addParameter(name='endDate', value=self.endDate, format='date')
851 opObj.addParameter(name='endDate', value=self.endDate, format='date')
852 opObj.addParameter(
852 opObj.addParameter(
853 name='startTime', value=self.startTime, format='time')
853 name='startTime', value=self.startTime, format='time')
854 opObj.addParameter(name='endTime', value=self.endTime, format='time')
854 opObj.addParameter(name='endTime', value=self.endTime, format='time')
855
855
856 for key, value in kwargs.items():
856 for key, value in kwargs.items():
857 opObj.addParameter(name=key, value=value,
857 opObj.addParameter(name=key, value=value,
858 format=type(value).__name__)
858 format=type(value).__name__)
859
859
860 return opObj
860 return opObj
861
861
862 def readXml(self, upElement):
862 def readXml(self, upElement):
863
863
864 self.id = upElement.get('id')
864 self.id = upElement.get('id')
865 self.name = upElement.get('name')
865 self.name = upElement.get('name')
866 self.datatype = upElement.get('datatype')
866 self.datatype = upElement.get('datatype')
867 self.inputId = upElement.get('inputId')
867 self.inputId = upElement.get('inputId')
868
868
869 if self.ELEMENTNAME == 'ReadUnit':
869 if self.ELEMENTNAME == 'ReadUnit':
870 self.datatype = self.datatype.replace('Reader', '')
870 self.datatype = self.datatype.replace('Reader', '')
871
871
872 if self.inputId == 'None':
872 if self.inputId == 'None':
873 self.inputId = '0'
873 self.inputId = '0'
874
874
875 self.opConfObjList = []
875 self.opConfObjList = []
876
876
877 opElementList = upElement.iter(OperationConf().getElementName())
877 opElementList = upElement.iter(OperationConf().getElementName())
878
878
879 for opElement in opElementList:
879 for opElement in opElementList:
880 opConfObj = OperationConf()
880 opConfObj = OperationConf()
881 opConfObj.readXml(opElement)
881 opConfObj.readXml(opElement)
882 self.opConfObjList.append(opConfObj)
882 self.opConfObjList.append(opConfObj)
883
883
884 if opConfObj.name == 'run':
884 if opConfObj.name == 'run':
885 self.path = opConfObj.getParameterValue('path')
885 self.path = opConfObj.getParameterValue('path')
886 self.startDate = opConfObj.getParameterValue('startDate')
886 self.startDate = opConfObj.getParameterValue('startDate')
887 self.endDate = opConfObj.getParameterValue('endDate')
887 self.endDate = opConfObj.getParameterValue('endDate')
888 self.startTime = opConfObj.getParameterValue('startTime')
888 self.startTime = opConfObj.getParameterValue('startTime')
889 self.endTime = opConfObj.getParameterValue('endTime')
889 self.endTime = opConfObj.getParameterValue('endTime')
890
890
891
891
892 class Project(Process):
892 class Project(Process):
893
893
894 id = None
894 id = None
895 # name = None
895 # name = None
896 description = None
896 description = None
897 filename = None
897 filename = None
898
898
899 procUnitConfObjDict = None
899 procUnitConfObjDict = None
900
900
901 ELEMENTNAME = 'Project'
901 ELEMENTNAME = 'Project'
902
902
903 plotterQueue = None
903 plotterQueue = None
904
904
905 def __init__(self, plotter_queue=None):
905 def __init__(self, plotter_queue=None):
906
906
907 Process.__init__(self)
907 Process.__init__(self)
908 self.id = None
908 self.id = None
909 self.description = None
909 self.description = None
910 self.email = None
910 self.email = None
911 self.alarm = [0]
911 self.alarm = [0]
912 self.plotterQueue = plotter_queue
912 self.plotterQueue = plotter_queue
913 self.procUnitConfObjDict = {}
913 self.procUnitConfObjDict = {}
914
914
915 def __getNewId(self):
915 def __getNewId(self):
916
916
917 idList = self.procUnitConfObjDict.keys()
917 idList = self.procUnitConfObjDict.keys()
918
918
919 id = int(self.id) * 10
919 id = int(self.id) * 10
920
920
921 while True:
921 while True:
922 id += 1
922 id += 1
923
923
924 if str(id) in idList:
924 if str(id) in idList:
925 continue
925 continue
926
926
927 break
927 break
928
928
929 return str(id)
929 return str(id)
930
930
931 def getElementName(self):
931 def getElementName(self):
932
932
933 return self.ELEMENTNAME
933 return self.ELEMENTNAME
934
934
935 def getId(self):
935 def getId(self):
936
936
937 return self.id
937 return self.id
938
938
939 def updateId(self, new_id):
939 def updateId(self, new_id):
940
940
941 self.id = str(new_id)
941 self.id = str(new_id)
942
942
943 keyList = self.procUnitConfObjDict.keys()
943 keyList = self.procUnitConfObjDict.keys()
944 keyList.sort()
944 keyList.sort()
945
945
946 n = 1
946 n = 1
947 newProcUnitConfObjDict = {}
947 newProcUnitConfObjDict = {}
948
948
949 for procKey in keyList:
949 for procKey in keyList:
950
950
951 procUnitConfObj = self.procUnitConfObjDict[procKey]
951 procUnitConfObj = self.procUnitConfObjDict[procKey]
952 idProcUnit = str(int(self.id) * 10 + n)
952 idProcUnit = str(int(self.id) * 10 + n)
953 procUnitConfObj.updateId(idProcUnit, parentId=self.id)
953 procUnitConfObj.updateId(idProcUnit, parentId=self.id)
954 newProcUnitConfObjDict[idProcUnit] = procUnitConfObj
954 newProcUnitConfObjDict[idProcUnit] = procUnitConfObj
955 n += 1
955 n += 1
956
956
957 self.procUnitConfObjDict = newProcUnitConfObjDict
957 self.procUnitConfObjDict = newProcUnitConfObjDict
958
958
959 def setup(self, id, name='', description='', email=None, alarm=[0]):
959 def setup(self, id, name='', description='', email=None, alarm=[0]):
960
960
961 print
961 print
962 print '*' * 60
962 print '*' * 60
963 print ' Starting SIGNAL CHAIN PROCESSING v%s ' % schainpy.__version__
963 print ' Starting SIGNAL CHAIN PROCESSING v%s ' % schainpy.__version__
964 print '*' * 60
964 print '*' * 60
965 print
965 print
966 self.id = str(id)
966 self.id = str(id)
967 self.description = description
967 self.description = description
968 self.email = email
968 self.email = email
969 self.alarm = alarm
969 self.alarm = alarm
970
970
971 def update(self, **kwargs):
971 def update(self, **kwargs):
972
972
973 for key, value in kwargs:
973 for key, value in kwargs:
974 setattr(self, key, value)
974 setattr(self, key, value)
975
975
976 def clone(self):
976 def clone(self):
977
977
978 p = Project()
978 p = Project()
979 p.procUnitConfObjDict = self.procUnitConfObjDict
979 p.procUnitConfObjDict = self.procUnitConfObjDict
980 return p
980 return p
981
981
982 def addReadUnit(self, id=None, datatype=None, name=None, **kwargs):
982 def addReadUnit(self, id=None, datatype=None, name=None, **kwargs):
983
983
984 if id is None:
984 if id is None:
985 idReadUnit = self.__getNewId()
985 idReadUnit = self.__getNewId()
986 else:
986 else:
987 idReadUnit = str(id)
987 idReadUnit = str(id)
988
988
989 readUnitConfObj = ReadUnitConf()
989 readUnitConfObj = ReadUnitConf()
990 readUnitConfObj.setup(idReadUnit, name, datatype,
990 readUnitConfObj.setup(idReadUnit, name, datatype,
991 parentId=self.id, **kwargs)
991 parentId=self.id, **kwargs)
992
992
993 self.procUnitConfObjDict[readUnitConfObj.getId()] = readUnitConfObj
993 self.procUnitConfObjDict[readUnitConfObj.getId()] = readUnitConfObj
994
994
995 return readUnitConfObj
995 return readUnitConfObj
996
996
997 def addProcUnit(self, inputId='0', datatype=None, name=None):
997 def addProcUnit(self, inputId='0', datatype=None, name=None):
998
998
999 idProcUnit = self.__getNewId()
999 idProcUnit = self.__getNewId()
1000
1000
1001 procUnitConfObj = ProcUnitConf()
1001 procUnitConfObj = ProcUnitConf()
1002 procUnitConfObj.setup(idProcUnit, name, datatype,
1002 procUnitConfObj.setup(idProcUnit, name, datatype,
1003 inputId, parentId=self.id)
1003 inputId, parentId=self.id)
1004
1004
1005 self.procUnitConfObjDict[procUnitConfObj.getId()] = procUnitConfObj
1005 self.procUnitConfObjDict[procUnitConfObj.getId()] = procUnitConfObj
1006
1006
1007 return procUnitConfObj
1007 return procUnitConfObj
1008
1008
1009 def removeProcUnit(self, id):
1009 def removeProcUnit(self, id):
1010
1010
1011 if id in self.procUnitConfObjDict.keys():
1011 if id in self.procUnitConfObjDict.keys():
1012 self.procUnitConfObjDict.pop(id)
1012 self.procUnitConfObjDict.pop(id)
1013
1013
1014 def getReadUnitId(self):
1014 def getReadUnitId(self):
1015
1015
1016 readUnitConfObj = self.getReadUnitObj()
1016 readUnitConfObj = self.getReadUnitObj()
1017
1017
1018 return readUnitConfObj.id
1018 return readUnitConfObj.id
1019
1019
1020 def getReadUnitObj(self):
1020 def getReadUnitObj(self):
1021
1021
1022 for obj in self.procUnitConfObjDict.values():
1022 for obj in self.procUnitConfObjDict.values():
1023 if obj.getElementName() == 'ReadUnit':
1023 if obj.getElementName() == 'ReadUnit':
1024 return obj
1024 return obj
1025
1025
1026 return None
1026 return None
1027
1027
1028 def getProcUnitObj(self, id=None, name=None):
1028 def getProcUnitObj(self, id=None, name=None):
1029
1029
1030 if id != None:
1030 if id != None:
1031 return self.procUnitConfObjDict[id]
1031 return self.procUnitConfObjDict[id]
1032
1032
1033 if name != None:
1033 if name != None:
1034 return self.getProcUnitObjByName(name)
1034 return self.getProcUnitObjByName(name)
1035
1035
1036 return None
1036 return None
1037
1037
1038 def getProcUnitObjByName(self, name):
1038 def getProcUnitObjByName(self, name):
1039
1039
1040 for obj in self.procUnitConfObjDict.values():
1040 for obj in self.procUnitConfObjDict.values():
1041 if obj.name == name:
1041 if obj.name == name:
1042 return obj
1042 return obj
1043
1043
1044 return None
1044 return None
1045
1045
1046 def procUnitItems(self):
1046 def procUnitItems(self):
1047
1047
1048 return self.procUnitConfObjDict.items()
1048 return self.procUnitConfObjDict.items()
1049
1049
1050 def makeXml(self):
1050 def makeXml(self):
1051
1051
1052 projectElement = Element('Project')
1052 projectElement = Element('Project')
1053 projectElement.set('id', str(self.id))
1053 projectElement.set('id', str(self.id))
1054 projectElement.set('name', self.name)
1054 projectElement.set('name', self.name)
1055 projectElement.set('description', self.description)
1055 projectElement.set('description', self.description)
1056
1056
1057 for procUnitConfObj in self.procUnitConfObjDict.values():
1057 for procUnitConfObj in self.procUnitConfObjDict.values():
1058 procUnitConfObj.makeXml(projectElement)
1058 procUnitConfObj.makeXml(projectElement)
1059
1059
1060 self.projectElement = projectElement
1060 self.projectElement = projectElement
1061
1061
1062 def writeXml(self, filename=None):
1062 def writeXml(self, filename=None):
1063
1063
1064 if filename == None:
1064 if filename == None:
1065 if self.filename:
1065 if self.filename:
1066 filename = self.filename
1066 filename = self.filename
1067 else:
1067 else:
1068 filename = 'schain.xml'
1068 filename = 'schain.xml'
1069
1069
1070 if not filename:
1070 if not filename:
1071 print 'filename has not been defined. Use setFilename(filename) for do it.'
1071 print 'filename has not been defined. Use setFilename(filename) for do it.'
1072 return 0
1072 return 0
1073
1073
1074 abs_file = os.path.abspath(filename)
1074 abs_file = os.path.abspath(filename)
1075
1075
1076 if not os.access(os.path.dirname(abs_file), os.W_OK):
1076 if not os.access(os.path.dirname(abs_file), os.W_OK):
1077 print 'No write permission on %s' % os.path.dirname(abs_file)
1077 print 'No write permission on %s' % os.path.dirname(abs_file)
1078 return 0
1078 return 0
1079
1079
1080 if os.path.isfile(abs_file) and not(os.access(abs_file, os.W_OK)):
1080 if os.path.isfile(abs_file) and not(os.access(abs_file, os.W_OK)):
1081 print 'File %s already exists and it could not be overwriten' % abs_file
1081 print 'File %s already exists and it could not be overwriten' % abs_file
1082 return 0
1082 return 0
1083
1083
1084 self.makeXml()
1084 self.makeXml()
1085
1085
1086 ElementTree(self.projectElement).write(abs_file, method='xml')
1086 ElementTree(self.projectElement).write(abs_file, method='xml')
1087
1087
1088 self.filename = abs_file
1088 self.filename = abs_file
1089
1089
1090 return 1
1090 return 1
1091
1091
1092 def readXml(self, filename=None):
1092 def readXml(self, filename=None):
1093
1093
1094 if not filename:
1094 if not filename:
1095 print 'filename is not defined'
1095 print 'filename is not defined'
1096 return 0
1096 return 0
1097
1097
1098 abs_file = os.path.abspath(filename)
1098 abs_file = os.path.abspath(filename)
1099
1099
1100 if not os.path.isfile(abs_file):
1100 if not os.path.isfile(abs_file):
1101 print '%s file does not exist' % abs_file
1101 print '%s file does not exist' % abs_file
1102 return 0
1102 return 0
1103
1103
1104 self.projectElement = None
1104 self.projectElement = None
1105 self.procUnitConfObjDict = {}
1105 self.procUnitConfObjDict = {}
1106
1106
1107 try:
1107 try:
1108 self.projectElement = ElementTree().parse(abs_file)
1108 self.projectElement = ElementTree().parse(abs_file)
1109 except:
1109 except:
1110 print 'Error reading %s, verify file format' % filename
1110 print 'Error reading %s, verify file format' % filename
1111 return 0
1111 return 0
1112
1112
1113 self.project = self.projectElement.tag
1113 self.project = self.projectElement.tag
1114
1114
1115 self.id = self.projectElement.get('id')
1115 self.id = self.projectElement.get('id')
1116 self.name = self.projectElement.get('name')
1116 self.name = self.projectElement.get('name')
1117 self.description = self.projectElement.get('description')
1117 self.description = self.projectElement.get('description')
1118
1118
1119 readUnitElementList = self.projectElement.iter(
1119 readUnitElementList = self.projectElement.iter(
1120 ReadUnitConf().getElementName())
1120 ReadUnitConf().getElementName())
1121
1121
1122 for readUnitElement in readUnitElementList:
1122 for readUnitElement in readUnitElementList:
1123 readUnitConfObj = ReadUnitConf()
1123 readUnitConfObj = ReadUnitConf()
1124 readUnitConfObj.readXml(readUnitElement)
1124 readUnitConfObj.readXml(readUnitElement)
1125
1125
1126 if readUnitConfObj.parentId == None:
1126 if readUnitConfObj.parentId == None:
1127 readUnitConfObj.parentId = self.id
1127 readUnitConfObj.parentId = self.id
1128
1128
1129 self.procUnitConfObjDict[readUnitConfObj.getId()] = readUnitConfObj
1129 self.procUnitConfObjDict[readUnitConfObj.getId()] = readUnitConfObj
1130
1130
1131 procUnitElementList = self.projectElement.iter(
1131 procUnitElementList = self.projectElement.iter(
1132 ProcUnitConf().getElementName())
1132 ProcUnitConf().getElementName())
1133
1133
1134 for procUnitElement in procUnitElementList:
1134 for procUnitElement in procUnitElementList:
1135 procUnitConfObj = ProcUnitConf()
1135 procUnitConfObj = ProcUnitConf()
1136 procUnitConfObj.readXml(procUnitElement)
1136 procUnitConfObj.readXml(procUnitElement)
1137
1137
1138 if procUnitConfObj.parentId == None:
1138 if procUnitConfObj.parentId == None:
1139 procUnitConfObj.parentId = self.id
1139 procUnitConfObj.parentId = self.id
1140
1140
1141 self.procUnitConfObjDict[procUnitConfObj.getId()] = procUnitConfObj
1141 self.procUnitConfObjDict[procUnitConfObj.getId()] = procUnitConfObj
1142
1142
1143 self.filename = abs_file
1143 self.filename = abs_file
1144
1144
1145 return 1
1145 return 1
1146
1146
1147 def printattr(self):
1147 def printattr(self):
1148
1148
1149 print 'Project[%s]: name = %s, description = %s' % (self.id,
1149 print 'Project[%s]: name = %s, description = %s' % (self.id,
1150 self.name,
1150 self.name,
1151 self.description)
1151 self.description)
1152
1152
1153 for procUnitConfObj in self.procUnitConfObjDict.values():
1153 for procUnitConfObj in self.procUnitConfObjDict.values():
1154 procUnitConfObj.printattr()
1154 procUnitConfObj.printattr()
1155
1155
1156 def createObjects(self):
1156 def createObjects(self):
1157
1157
1158 for procUnitConfObj in self.procUnitConfObjDict.values():
1158 for procUnitConfObj in self.procUnitConfObjDict.values():
1159 procUnitConfObj.createObjects(self.plotterQueue)
1159 procUnitConfObj.createObjects(self.plotterQueue)
1160
1160
1161 def __connect(self, objIN, thisObj):
1161 def __connect(self, objIN, thisObj):
1162
1162
1163 thisObj.setInput(objIN.getOutputObj())
1163 thisObj.setInput(objIN.getOutputObj())
1164
1164
1165 def connectObjects(self):
1165 def connectObjects(self):
1166
1166
1167 for thisPUConfObj in self.procUnitConfObjDict.values():
1167 for thisPUConfObj in self.procUnitConfObjDict.values():
1168
1168
1169 inputId = thisPUConfObj.getInputId()
1169 inputId = thisPUConfObj.getInputId()
1170
1170
1171 if int(inputId) == 0:
1171 if int(inputId) == 0:
1172 continue
1172 continue
1173
1173
1174 # Get input object
1174 # Get input object
1175 puConfINObj = self.procUnitConfObjDict[inputId]
1175 puConfINObj = self.procUnitConfObjDict[inputId]
1176 puObjIN = puConfINObj.getProcUnitObj()
1176 puObjIN = puConfINObj.getProcUnitObj()
1177
1177
1178 # Get current object
1178 # Get current object
1179 thisPUObj = thisPUConfObj.getProcUnitObj()
1179 thisPUObj = thisPUConfObj.getProcUnitObj()
1180
1180
1181 self.__connect(puObjIN, thisPUObj)
1181 self.__connect(puObjIN, thisPUObj)
1182
1182
1183 def __handleError(self, procUnitConfObj):
1183 def __handleError(self, procUnitConfObj, modes=None):
1184
1184
1185 import socket
1185 import socket
1186
1186
1187 if modes is None:
1188 modes = self.alarm
1189
1187 err = traceback.format_exception(sys.exc_info()[0],
1190 err = traceback.format_exception(sys.exc_info()[0],
1188 sys.exc_info()[1],
1191 sys.exc_info()[1],
1189 sys.exc_info()[2])
1192 sys.exc_info()[2])
1190
1193
1191 log.error('{}'.format(err[-1]), procUnitConfObj.name)
1194 log.error('{}'.format(err[-1]), procUnitConfObj.name)
1192
1195
1193 message = ''.join(err)
1196 message = ''.join(err)
1194
1197
1195 sys.stderr.write(message)
1198 sys.stderr.write(message)
1196
1199
1197 subject = 'SChain v%s: Error running %s\n' % (
1200 subject = 'SChain v%s: Error running %s\n' % (
1198 schainpy.__version__, procUnitConfObj.name)
1201 schainpy.__version__, procUnitConfObj.name)
1199
1202
1200 subtitle = '%s: %s\n' % (
1203 subtitle = '%s: %s\n' % (
1201 procUnitConfObj.getElementName(), procUnitConfObj.name)
1204 procUnitConfObj.getElementName(), procUnitConfObj.name)
1202 subtitle += 'Hostname: %s\n' % socket.gethostbyname(
1205 subtitle += 'Hostname: %s\n' % socket.gethostbyname(
1203 socket.gethostname())
1206 socket.gethostname())
1204 subtitle += 'Working directory: %s\n' % os.path.abspath('./')
1207 subtitle += 'Working directory: %s\n' % os.path.abspath('./')
1205 subtitle += 'Configuration file: %s\n' % self.filename
1208 subtitle += 'Configuration file: %s\n' % self.filename
1206 subtitle += 'Time: %s\n' % str(datetime.datetime.now())
1209 subtitle += 'Time: %s\n' % str(datetime.datetime.now())
1207
1210
1208 readUnitConfObj = self.getReadUnitObj()
1211 readUnitConfObj = self.getReadUnitObj()
1209 if readUnitConfObj:
1212 if readUnitConfObj:
1210 subtitle += '\nInput parameters:\n'
1213 subtitle += '\nInput parameters:\n'
1211 subtitle += '[Data path = %s]\n' % readUnitConfObj.path
1214 subtitle += '[Data path = %s]\n' % readUnitConfObj.path
1212 subtitle += '[Data type = %s]\n' % readUnitConfObj.datatype
1215 subtitle += '[Data type = %s]\n' % readUnitConfObj.datatype
1213 subtitle += '[Start date = %s]\n' % readUnitConfObj.startDate
1216 subtitle += '[Start date = %s]\n' % readUnitConfObj.startDate
1214 subtitle += '[End date = %s]\n' % readUnitConfObj.endDate
1217 subtitle += '[End date = %s]\n' % readUnitConfObj.endDate
1215 subtitle += '[Start time = %s]\n' % readUnitConfObj.startTime
1218 subtitle += '[Start time = %s]\n' % readUnitConfObj.startTime
1216 subtitle += '[End time = %s]\n' % readUnitConfObj.endTime
1219 subtitle += '[End time = %s]\n' % readUnitConfObj.endTime
1217
1220
1218 schainpy.admin.alarm(
1221 a = Alarm(
1219 modes=self.alarm,
1222 modes=modes,
1220 email=self.email,
1223 email=self.email,
1221 message=message,
1224 message=message,
1222 subject=subject,
1225 subject=subject,
1223 subtitle=subtitle,
1226 subtitle=subtitle,
1224 filename=self.filename
1227 filename=self.filename
1225 )
1228 )
1226
1229
1230 a.start()
1231
1227 def isPaused(self):
1232 def isPaused(self):
1228 return 0
1233 return 0
1229
1234
1230 def isStopped(self):
1235 def isStopped(self):
1231 return 0
1236 return 0
1232
1237
1233 def runController(self):
1238 def runController(self):
1234 '''
1239 '''
1235 returns 0 when this process has been stopped, 1 otherwise
1240 returns 0 when this process has been stopped, 1 otherwise
1236 '''
1241 '''
1237
1242
1238 if self.isPaused():
1243 if self.isPaused():
1239 print 'Process suspended'
1244 print 'Process suspended'
1240
1245
1241 while True:
1246 while True:
1242 time.sleep(0.1)
1247 time.sleep(0.1)
1243
1248
1244 if not self.isPaused():
1249 if not self.isPaused():
1245 break
1250 break
1246
1251
1247 if self.isStopped():
1252 if self.isStopped():
1248 break
1253 break
1249
1254
1250 print 'Process reinitialized'
1255 print 'Process reinitialized'
1251
1256
1252 if self.isStopped():
1257 if self.isStopped():
1253 print 'Process stopped'
1258 print 'Process stopped'
1254 return 0
1259 return 0
1255
1260
1256 return 1
1261 return 1
1257
1262
1258 def setFilename(self, filename):
1263 def setFilename(self, filename):
1259
1264
1260 self.filename = filename
1265 self.filename = filename
1261
1266
1262 def setPlotterQueue(self, plotter_queue):
1267 def setPlotterQueue(self, plotter_queue):
1263
1268
1264 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1269 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1265
1270
1266 def getPlotterQueue(self):
1271 def getPlotterQueue(self):
1267
1272
1268 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1273 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1269
1274
1270 def useExternalPlotter(self):
1275 def useExternalPlotter(self):
1271
1276
1272 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1277 raise NotImplementedError, 'Use schainpy.controller_api.ControllerThread instead Project class'
1273
1278
1274 def run(self):
1279 def run(self):
1275
1280
1276 log.success('Starting {}'.format(self.name))
1281 log.success('Starting {}'.format(self.name))
1277 self.start_time = time.time()
1282 self.start_time = time.time()
1278 self.createObjects()
1283 self.createObjects()
1279 self.connectObjects()
1284 self.connectObjects()
1280
1285
1281 keyList = self.procUnitConfObjDict.keys()
1286 keyList = self.procUnitConfObjDict.keys()
1282 keyList.sort()
1287 keyList.sort()
1283
1288
1284 while(True):
1289 while(True):
1285
1290
1286 is_ok = False
1291 is_ok = False
1287
1292
1288 for procKey in keyList:
1293 for procKey in keyList:
1289
1294
1290 procUnitConfObj = self.procUnitConfObjDict[procKey]
1295 procUnitConfObj = self.procUnitConfObjDict[procKey]
1291
1296
1292 try:
1297 try:
1293 sts = procUnitConfObj.run()
1298 sts = procUnitConfObj.run()
1294 is_ok = is_ok or sts
1299 is_ok = is_ok or sts
1295 j
1300 except SchainWarning:
1301 self.__handleError(procUnitConfObj, modes=[2, 3])
1296 except KeyboardInterrupt:
1302 except KeyboardInterrupt:
1297 is_ok = False
1303 is_ok = False
1298 break
1304 break
1299 except ValueError, e:
1305 except ValueError, e:
1300 time.sleep(0.5)
1306 time.sleep(0.5)
1301 self.__handleError(procUnitConfObj)
1307 self.__handleError(procUnitConfObj)
1302 is_ok = False
1308 is_ok = False
1303 break
1309 break
1304 except:
1310 except:
1305 time.sleep(0.5)
1311 time.sleep(0.5)
1306 self.__handleError(procUnitConfObj)
1312 self.__handleError(procUnitConfObj)
1307 is_ok = False
1313 is_ok = False
1308 break
1314 break
1309
1315
1310 # If every process unit finished so end process
1316 # If every process unit finished so end process
1311 if not(is_ok):
1317 if not(is_ok):
1312 break
1318 break
1313
1319
1314 if not self.runController():
1320 if not self.runController():
1315 break
1321 break
1316
1322
1317 # Closing every process
1323 # Closing every process
1318 for procKey in keyList:
1324 for procKey in keyList:
1319 procUnitConfObj = self.procUnitConfObjDict[procKey]
1325 procUnitConfObj = self.procUnitConfObjDict[procKey]
1320 procUnitConfObj.close()
1326 procUnitConfObj.close()
1321
1327
1322 log.success('{} finished (time: {}s)'.format(
1328 log.success('{} finished (time: {}s)'.format(
1323 self.name,
1329 self.name,
1324 time.time()-self.start_time))
1330 time.time()-self.start_time))
@@ -1,972 +1,971
1
1
2 import os
2 import os
3 import time
3 import time
4 import glob
4 import glob
5 import datetime
5 import datetime
6 from multiprocessing import Process
6 from multiprocessing import Process
7
7
8 import zmq
8 import zmq
9 import numpy
9 import numpy
10 import matplotlib
10 import matplotlib
11 import matplotlib.pyplot as plt
11 import matplotlib.pyplot as plt
12 from mpl_toolkits.axes_grid1 import make_axes_locatable
12 from mpl_toolkits.axes_grid1 import make_axes_locatable
13 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
13 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
14
14
15 from schainpy.model.proc.jroproc_base import Operation
15 from schainpy.model.proc.jroproc_base import Operation
16 from schainpy.utils import log
16 from schainpy.utils import log
17
17
18 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
18 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
19 blu_values = matplotlib.pyplot.get_cmap(
19 blu_values = matplotlib.pyplot.get_cmap(
20 'seismic_r', 20)(numpy.arange(20))[10:15]
20 'seismic_r', 20)(numpy.arange(20))[10:15]
21 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
21 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
22 'jro', numpy.vstack((blu_values, jet_values)))
22 'jro', numpy.vstack((blu_values, jet_values)))
23 matplotlib.pyplot.register_cmap(cmap=ncmap)
23 matplotlib.pyplot.register_cmap(cmap=ncmap)
24
24
25 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis', 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
25 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis', 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
26
26
27
27
28 def figpause(interval):
28 def figpause(interval):
29 backend = plt.rcParams['backend']
29 backend = plt.rcParams['backend']
30 if backend in matplotlib.rcsetup.interactive_bk:
30 if backend in matplotlib.rcsetup.interactive_bk:
31 figManager = matplotlib._pylab_helpers.Gcf.get_active()
31 figManager = matplotlib._pylab_helpers.Gcf.get_active()
32 if figManager is not None:
32 if figManager is not None:
33 canvas = figManager.canvas
33 canvas = figManager.canvas
34 if canvas.figure.stale:
34 if canvas.figure.stale:
35 canvas.draw()
35 canvas.draw()
36 canvas.start_event_loop(interval)
36 canvas.start_event_loop(interval)
37 return
37 return
38
38
39 def popup(message):
39 def popup(message):
40 fig = plt.figure(figsize=(12, 9), facecolor='r')
40 fig = plt.figure(figsize=(12, 8), facecolor='r')
41 fig.text(0.5, 0.5, message, ha='center', va='center', size='20', weight='heavy', color='w')
41 fig.text(0.5, 0.5, message, ha='center', va='center', size='20', weight='heavy', color='w')
42 fig.show()
42 fig.show()
43 figpause(1000)
43 figpause(1000)
44
44
45
45
46
47 class PlotData(Operation, Process):
46 class PlotData(Operation, Process):
48 '''
47 '''
49 Base class for Schain plotting operations
48 Base class for Schain plotting operations
50 '''
49 '''
51
50
52 CODE = 'Figure'
51 CODE = 'Figure'
53 colormap = 'jro'
52 colormap = 'jro'
54 bgcolor = 'white'
53 bgcolor = 'white'
55 CONFLATE = False
54 CONFLATE = False
56 __missing = 1E30
55 __missing = 1E30
57
56
58 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
57 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
59 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title',
58 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title',
60 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
59 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
61 'showprofile', 'decimation']
60 'showprofile', 'decimation']
62
61
63 def __init__(self, **kwargs):
62 def __init__(self, **kwargs):
64
63
65 Operation.__init__(self, plot=True, **kwargs)
64 Operation.__init__(self, plot=True, **kwargs)
66 Process.__init__(self)
65 Process.__init__(self)
67
66
68 self.kwargs['code'] = self.CODE
67 self.kwargs['code'] = self.CODE
69 self.mp = False
68 self.mp = False
70 self.data = None
69 self.data = None
71 self.isConfig = False
70 self.isConfig = False
72 self.figures = []
71 self.figures = []
73 self.axes = []
72 self.axes = []
74 self.cb_axes = []
73 self.cb_axes = []
75 self.localtime = kwargs.pop('localtime', True)
74 self.localtime = kwargs.pop('localtime', True)
76 self.show = kwargs.get('show', True)
75 self.show = kwargs.get('show', True)
77 self.save = kwargs.get('save', False)
76 self.save = kwargs.get('save', False)
78 self.colormap = kwargs.get('colormap', self.colormap)
77 self.colormap = kwargs.get('colormap', self.colormap)
79 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
78 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
80 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
79 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
81 self.colormaps = kwargs.get('colormaps', None)
80 self.colormaps = kwargs.get('colormaps', None)
82 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
81 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
83 self.showprofile = kwargs.get('showprofile', False)
82 self.showprofile = kwargs.get('showprofile', False)
84 self.title = kwargs.get('wintitle', self.CODE.upper())
83 self.title = kwargs.get('wintitle', self.CODE.upper())
85 self.cb_label = kwargs.get('cb_label', None)
84 self.cb_label = kwargs.get('cb_label', None)
86 self.cb_labels = kwargs.get('cb_labels', None)
85 self.cb_labels = kwargs.get('cb_labels', None)
87 self.xaxis = kwargs.get('xaxis', 'frequency')
86 self.xaxis = kwargs.get('xaxis', 'frequency')
88 self.zmin = kwargs.get('zmin', None)
87 self.zmin = kwargs.get('zmin', None)
89 self.zmax = kwargs.get('zmax', None)
88 self.zmax = kwargs.get('zmax', None)
90 self.zlimits = kwargs.get('zlimits', None)
89 self.zlimits = kwargs.get('zlimits', None)
91 self.xmin = kwargs.get('xmin', None)
90 self.xmin = kwargs.get('xmin', None)
92 self.xmax = kwargs.get('xmax', None)
91 self.xmax = kwargs.get('xmax', None)
93 self.xrange = kwargs.get('xrange', 24)
92 self.xrange = kwargs.get('xrange', 24)
94 self.ymin = kwargs.get('ymin', None)
93 self.ymin = kwargs.get('ymin', None)
95 self.ymax = kwargs.get('ymax', None)
94 self.ymax = kwargs.get('ymax', None)
96 self.xlabel = kwargs.get('xlabel', None)
95 self.xlabel = kwargs.get('xlabel', None)
97 self.decimation = kwargs.get('decimation', None)
96 self.decimation = kwargs.get('decimation', None)
98 self.showSNR = kwargs.get('showSNR', False)
97 self.showSNR = kwargs.get('showSNR', False)
99 self.oneFigure = kwargs.get('oneFigure', True)
98 self.oneFigure = kwargs.get('oneFigure', True)
100 self.width = kwargs.get('width', None)
99 self.width = kwargs.get('width', None)
101 self.height = kwargs.get('height', None)
100 self.height = kwargs.get('height', None)
102 self.colorbar = kwargs.get('colorbar', True)
101 self.colorbar = kwargs.get('colorbar', True)
103 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
102 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
104 self.titles = kwargs.get('titles', [])
103 self.titles = kwargs.get('titles', [])
105 self.polar = False
104 self.polar = False
106
105
107 def __fmtTime(self, x, pos):
106 def __fmtTime(self, x, pos):
108 '''
107 '''
109 '''
108 '''
110
109
111 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
110 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
112
111
113 def __setup(self):
112 def __setup(self):
114 '''
113 '''
115 Common setup for all figures, here figures and axes are created
114 Common setup for all figures, here figures and axes are created
116 '''
115 '''
117
116
118 if self.CODE not in self.data:
117 if self.CODE not in self.data:
119 raise ValueError(log.error('Missing data for {}'.format(self.CODE),
118 raise ValueError(log.error('Missing data for {}'.format(self.CODE),
120 self.name))
119 self.name))
121
120
122 self.setup()
121 self.setup()
123
122
124 self.time_label = 'LT' if self.localtime else 'UTC'
123 self.time_label = 'LT' if self.localtime else 'UTC'
125 if self.data.localtime:
124 if self.data.localtime:
126 self.getDateTime = datetime.datetime.fromtimestamp
125 self.getDateTime = datetime.datetime.fromtimestamp
127 else:
126 else:
128 self.getDateTime = datetime.datetime.utcfromtimestamp
127 self.getDateTime = datetime.datetime.utcfromtimestamp
129
128
130 if self.width is None:
129 if self.width is None:
131 self.width = 8
130 self.width = 8
132
131
133 self.figures = []
132 self.figures = []
134 self.axes = []
133 self.axes = []
135 self.cb_axes = []
134 self.cb_axes = []
136 self.pf_axes = []
135 self.pf_axes = []
137 self.cmaps = []
136 self.cmaps = []
138
137
139 size = '15%' if self.ncols == 1 else '30%'
138 size = '15%' if self.ncols == 1 else '30%'
140 pad = '4%' if self.ncols == 1 else '8%'
139 pad = '4%' if self.ncols == 1 else '8%'
141
140
142 if self.oneFigure:
141 if self.oneFigure:
143 if self.height is None:
142 if self.height is None:
144 self.height = 1.4 * self.nrows + 1
143 self.height = 1.4 * self.nrows + 1
145 fig = plt.figure(figsize=(self.width, self.height),
144 fig = plt.figure(figsize=(self.width, self.height),
146 edgecolor='k',
145 edgecolor='k',
147 facecolor='w')
146 facecolor='w')
148 self.figures.append(fig)
147 self.figures.append(fig)
149 for n in range(self.nplots):
148 for n in range(self.nplots):
150 ax = fig.add_subplot(self.nrows, self.ncols,
149 ax = fig.add_subplot(self.nrows, self.ncols,
151 n + 1, polar=self.polar)
150 n + 1, polar=self.polar)
152 ax.tick_params(labelsize=8)
151 ax.tick_params(labelsize=8)
153 ax.firsttime = True
152 ax.firsttime = True
154 ax.index = 0
153 ax.index = 0
155 ax.press = None
154 ax.press = None
156 self.axes.append(ax)
155 self.axes.append(ax)
157 if self.showprofile:
156 if self.showprofile:
158 cax = self.__add_axes(ax, size=size, pad=pad)
157 cax = self.__add_axes(ax, size=size, pad=pad)
159 cax.tick_params(labelsize=8)
158 cax.tick_params(labelsize=8)
160 self.pf_axes.append(cax)
159 self.pf_axes.append(cax)
161 else:
160 else:
162 if self.height is None:
161 if self.height is None:
163 self.height = 3
162 self.height = 3
164 for n in range(self.nplots):
163 for n in range(self.nplots):
165 fig = plt.figure(figsize=(self.width, self.height),
164 fig = plt.figure(figsize=(self.width, self.height),
166 edgecolor='k',
165 edgecolor='k',
167 facecolor='w')
166 facecolor='w')
168 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
167 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
169 ax.tick_params(labelsize=8)
168 ax.tick_params(labelsize=8)
170 ax.firsttime = True
169 ax.firsttime = True
171 ax.index = 0
170 ax.index = 0
172 ax.press = None
171 ax.press = None
173 self.figures.append(fig)
172 self.figures.append(fig)
174 self.axes.append(ax)
173 self.axes.append(ax)
175 if self.showprofile:
174 if self.showprofile:
176 cax = self.__add_axes(ax, size=size, pad=pad)
175 cax = self.__add_axes(ax, size=size, pad=pad)
177 cax.tick_params(labelsize=8)
176 cax.tick_params(labelsize=8)
178 self.pf_axes.append(cax)
177 self.pf_axes.append(cax)
179
178
180 for n in range(self.nrows):
179 for n in range(self.nrows):
181 if self.colormaps is not None:
180 if self.colormaps is not None:
182 cmap = plt.get_cmap(self.colormaps[n])
181 cmap = plt.get_cmap(self.colormaps[n])
183 else:
182 else:
184 cmap = plt.get_cmap(self.colormap)
183 cmap = plt.get_cmap(self.colormap)
185 cmap.set_bad(self.bgcolor, 1.)
184 cmap.set_bad(self.bgcolor, 1.)
186 self.cmaps.append(cmap)
185 self.cmaps.append(cmap)
187
186
188 for fig in self.figures:
187 for fig in self.figures:
189 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
188 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
190 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
189 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
191 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
190 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
192 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
191 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
193 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
192 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
194 if self.show:
193 if self.show:
195 fig.show()
194 fig.show()
196
195
197 def OnKeyPress(self, event):
196 def OnKeyPress(self, event):
198 '''
197 '''
199 Event for pressing keys (up, down) change colormap
198 Event for pressing keys (up, down) change colormap
200 '''
199 '''
201 ax = event.inaxes
200 ax = event.inaxes
202 if ax in self.axes:
201 if ax in self.axes:
203 if event.key == 'down':
202 if event.key == 'down':
204 ax.index += 1
203 ax.index += 1
205 elif event.key == 'up':
204 elif event.key == 'up':
206 ax.index -= 1
205 ax.index -= 1
207 if ax.index < 0:
206 if ax.index < 0:
208 ax.index = len(CMAPS) - 1
207 ax.index = len(CMAPS) - 1
209 elif ax.index == len(CMAPS):
208 elif ax.index == len(CMAPS):
210 ax.index = 0
209 ax.index = 0
211 cmap = CMAPS[ax.index]
210 cmap = CMAPS[ax.index]
212 ax.cbar.set_cmap(cmap)
211 ax.cbar.set_cmap(cmap)
213 ax.cbar.draw_all()
212 ax.cbar.draw_all()
214 ax.plt.set_cmap(cmap)
213 ax.plt.set_cmap(cmap)
215 ax.cbar.patch.figure.canvas.draw()
214 ax.cbar.patch.figure.canvas.draw()
216 self.colormap = cmap.name
215 self.colormap = cmap.name
217
216
218 def OnBtnScroll(self, event):
217 def OnBtnScroll(self, event):
219 '''
218 '''
220 Event for scrolling, scale figure
219 Event for scrolling, scale figure
221 '''
220 '''
222 cb_ax = event.inaxes
221 cb_ax = event.inaxes
223 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
222 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
224 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
223 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
225 pt = ax.cbar.ax.bbox.get_points()[:, 1]
224 pt = ax.cbar.ax.bbox.get_points()[:, 1]
226 nrm = ax.cbar.norm
225 nrm = ax.cbar.norm
227 vmin, vmax, p0, p1, pS = (
226 vmin, vmax, p0, p1, pS = (
228 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
227 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
229 scale = 2 if event.step == 1 else 0.5
228 scale = 2 if event.step == 1 else 0.5
230 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
229 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
231 ax.cbar.norm.vmin = point - scale * (point - vmin)
230 ax.cbar.norm.vmin = point - scale * (point - vmin)
232 ax.cbar.norm.vmax = point - scale * (point - vmax)
231 ax.cbar.norm.vmax = point - scale * (point - vmax)
233 ax.plt.set_norm(ax.cbar.norm)
232 ax.plt.set_norm(ax.cbar.norm)
234 ax.cbar.draw_all()
233 ax.cbar.draw_all()
235 ax.cbar.patch.figure.canvas.draw()
234 ax.cbar.patch.figure.canvas.draw()
236
235
237 def onBtnPress(self, event):
236 def onBtnPress(self, event):
238 '''
237 '''
239 Event for mouse button press
238 Event for mouse button press
240 '''
239 '''
241 cb_ax = event.inaxes
240 cb_ax = event.inaxes
242 if cb_ax is None:
241 if cb_ax is None:
243 return
242 return
244
243
245 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
244 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
246 cb_ax.press = event.x, event.y
245 cb_ax.press = event.x, event.y
247 else:
246 else:
248 cb_ax.press = None
247 cb_ax.press = None
249
248
250 def onMotion(self, event):
249 def onMotion(self, event):
251 '''
250 '''
252 Event for move inside colorbar
251 Event for move inside colorbar
253 '''
252 '''
254 cb_ax = event.inaxes
253 cb_ax = event.inaxes
255 if cb_ax is None:
254 if cb_ax is None:
256 return
255 return
257 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
256 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
258 return
257 return
259 if cb_ax.press is None:
258 if cb_ax.press is None:
260 return
259 return
261
260
262 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
261 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
263 xprev, yprev = cb_ax.press
262 xprev, yprev = cb_ax.press
264 dx = event.x - xprev
263 dx = event.x - xprev
265 dy = event.y - yprev
264 dy = event.y - yprev
266 cb_ax.press = event.x, event.y
265 cb_ax.press = event.x, event.y
267 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
266 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
268 perc = 0.03
267 perc = 0.03
269
268
270 if event.button == 1:
269 if event.button == 1:
271 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
270 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
272 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
271 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
273 elif event.button == 3:
272 elif event.button == 3:
274 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
273 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
275 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
274 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
276
275
277 ax.cbar.draw_all()
276 ax.cbar.draw_all()
278 ax.plt.set_norm(ax.cbar.norm)
277 ax.plt.set_norm(ax.cbar.norm)
279 ax.cbar.patch.figure.canvas.draw()
278 ax.cbar.patch.figure.canvas.draw()
280
279
281 def onBtnRelease(self, event):
280 def onBtnRelease(self, event):
282 '''
281 '''
283 Event for mouse button release
282 Event for mouse button release
284 '''
283 '''
285 cb_ax = event.inaxes
284 cb_ax = event.inaxes
286 if cb_ax is not None:
285 if cb_ax is not None:
287 cb_ax.press = None
286 cb_ax.press = None
288
287
289 def __add_axes(self, ax, size='30%', pad='8%'):
288 def __add_axes(self, ax, size='30%', pad='8%'):
290 '''
289 '''
291 Add new axes to the given figure
290 Add new axes to the given figure
292 '''
291 '''
293 divider = make_axes_locatable(ax)
292 divider = make_axes_locatable(ax)
294 nax = divider.new_horizontal(size=size, pad=pad)
293 nax = divider.new_horizontal(size=size, pad=pad)
295 ax.figure.add_axes(nax)
294 ax.figure.add_axes(nax)
296 return nax
295 return nax
297
296
298 self.setup()
297 self.setup()
299
298
300 def setup(self):
299 def setup(self):
301 '''
300 '''
302 This method should be implemented in the child class, the following
301 This method should be implemented in the child class, the following
303 attributes should be set:
302 attributes should be set:
304
303
305 self.nrows: number of rows
304 self.nrows: number of rows
306 self.ncols: number of cols
305 self.ncols: number of cols
307 self.nplots: number of plots (channels or pairs)
306 self.nplots: number of plots (channels or pairs)
308 self.ylabel: label for Y axes
307 self.ylabel: label for Y axes
309 self.titles: list of axes title
308 self.titles: list of axes title
310
309
311 '''
310 '''
312 raise(NotImplementedError, 'Implement this method in child class')
311 raise(NotImplementedError, 'Implement this method in child class')
313
312
314 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
313 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
315 '''
314 '''
316 Create a masked array for missing data
315 Create a masked array for missing data
317 '''
316 '''
318 if x_buffer.shape[0] < 2:
317 if x_buffer.shape[0] < 2:
319 return x_buffer, y_buffer, z_buffer
318 return x_buffer, y_buffer, z_buffer
320
319
321 deltas = x_buffer[1:] - x_buffer[0:-1]
320 deltas = x_buffer[1:] - x_buffer[0:-1]
322 x_median = numpy.median(deltas)
321 x_median = numpy.median(deltas)
323
322
324 index = numpy.where(deltas > 5 * x_median)
323 index = numpy.where(deltas > 5 * x_median)
325
324
326 if len(index[0]) != 0:
325 if len(index[0]) != 0:
327 z_buffer[::, index[0], ::] = self.__missing
326 z_buffer[::, index[0], ::] = self.__missing
328 z_buffer = numpy.ma.masked_inside(z_buffer,
327 z_buffer = numpy.ma.masked_inside(z_buffer,
329 0.99 * self.__missing,
328 0.99 * self.__missing,
330 1.01 * self.__missing)
329 1.01 * self.__missing)
331
330
332 return x_buffer, y_buffer, z_buffer
331 return x_buffer, y_buffer, z_buffer
333
332
334 def decimate(self):
333 def decimate(self):
335
334
336 # dx = int(len(self.x)/self.__MAXNUMX) + 1
335 # dx = int(len(self.x)/self.__MAXNUMX) + 1
337 dy = int(len(self.y) / self.decimation) + 1
336 dy = int(len(self.y) / self.decimation) + 1
338
337
339 # x = self.x[::dx]
338 # x = self.x[::dx]
340 x = self.x
339 x = self.x
341 y = self.y[::dy]
340 y = self.y[::dy]
342 z = self.z[::, ::, ::dy]
341 z = self.z[::, ::, ::dy]
343
342
344 return x, y, z
343 return x, y, z
345
344
346 def format(self):
345 def format(self):
347 '''
346 '''
348 Set min and max values, labels, ticks and titles
347 Set min and max values, labels, ticks and titles
349 '''
348 '''
350
349
351 if self.xmin is None:
350 if self.xmin is None:
352 xmin = self.min_time
351 xmin = self.min_time
353 else:
352 else:
354 if self.xaxis is 'time':
353 if self.xaxis is 'time':
355 dt = self.getDateTime(self.min_time)
354 dt = self.getDateTime(self.min_time)
356 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
355 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
357 datetime.datetime(1970, 1, 1)).total_seconds()
356 datetime.datetime(1970, 1, 1)).total_seconds()
358 if self.data.localtime:
357 if self.data.localtime:
359 xmin += time.timezone
358 xmin += time.timezone
360 else:
359 else:
361 xmin = self.xmin
360 xmin = self.xmin
362
361
363 if self.xmax is None:
362 if self.xmax is None:
364 xmax = xmin + self.xrange * 60 * 60
363 xmax = xmin + self.xrange * 60 * 60
365 else:
364 else:
366 if self.xaxis is 'time':
365 if self.xaxis is 'time':
367 dt = self.getDateTime(self.max_time)
366 dt = self.getDateTime(self.max_time)
368 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
367 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
369 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
368 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
370 if self.data.localtime:
369 if self.data.localtime:
371 xmax += time.timezone
370 xmax += time.timezone
372 else:
371 else:
373 xmax = self.xmax
372 xmax = self.xmax
374
373
375 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
374 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
376 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
375 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
377
376
378 Y = numpy.array([5, 10, 20, 50, 100, 200, 500, 1000, 2000])
377 Y = numpy.array([5, 10, 20, 50, 100, 200, 500, 1000, 2000])
379 i = 1 if numpy.where(ymax-ymin < Y)[0][0] < 0 else numpy.where(ymax-ymin < Y)[0][0]
378 i = 1 if numpy.where(ymax-ymin < Y)[0][0] < 0 else numpy.where(ymax-ymin < Y)[0][0]
380 ystep = Y[i] / 5
379 ystep = Y[i] / 5
381
380
382 for n, ax in enumerate(self.axes):
381 for n, ax in enumerate(self.axes):
383 if ax.firsttime:
382 if ax.firsttime:
384 ax.set_facecolor(self.bgcolor)
383 ax.set_facecolor(self.bgcolor)
385 ax.yaxis.set_major_locator(MultipleLocator(ystep))
384 ax.yaxis.set_major_locator(MultipleLocator(ystep))
386 if self.xaxis is 'time':
385 if self.xaxis is 'time':
387 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
386 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
388 ax.xaxis.set_major_locator(LinearLocator(9))
387 ax.xaxis.set_major_locator(LinearLocator(9))
389 if self.xlabel is not None:
388 if self.xlabel is not None:
390 ax.set_xlabel(self.xlabel)
389 ax.set_xlabel(self.xlabel)
391 ax.set_ylabel(self.ylabel)
390 ax.set_ylabel(self.ylabel)
392 ax.firsttime = False
391 ax.firsttime = False
393 if self.showprofile:
392 if self.showprofile:
394 self.pf_axes[n].set_ylim(ymin, ymax)
393 self.pf_axes[n].set_ylim(ymin, ymax)
395 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
394 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
396 self.pf_axes[n].set_xlabel('dB')
395 self.pf_axes[n].set_xlabel('dB')
397 self.pf_axes[n].grid(b=True, axis='x')
396 self.pf_axes[n].grid(b=True, axis='x')
398 [tick.set_visible(False)
397 [tick.set_visible(False)
399 for tick in self.pf_axes[n].get_yticklabels()]
398 for tick in self.pf_axes[n].get_yticklabels()]
400 if self.colorbar:
399 if self.colorbar:
401 ax.cbar = plt.colorbar(
400 ax.cbar = plt.colorbar(
402 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
401 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
403 ax.cbar.ax.tick_params(labelsize=8)
402 ax.cbar.ax.tick_params(labelsize=8)
404 ax.cbar.ax.press = None
403 ax.cbar.ax.press = None
405 if self.cb_label:
404 if self.cb_label:
406 ax.cbar.set_label(self.cb_label, size=8)
405 ax.cbar.set_label(self.cb_label, size=8)
407 elif self.cb_labels:
406 elif self.cb_labels:
408 ax.cbar.set_label(self.cb_labels[n], size=8)
407 ax.cbar.set_label(self.cb_labels[n], size=8)
409 else:
408 else:
410 ax.cbar = None
409 ax.cbar = None
411
410
412 if not self.polar:
411 if not self.polar:
413 ax.set_xlim(xmin, xmax)
412 ax.set_xlim(xmin, xmax)
414 ax.set_ylim(ymin, ymax)
413 ax.set_ylim(ymin, ymax)
415 ax.set_title('{} - {} {}'.format(
414 ax.set_title('{} - {} {}'.format(
416 self.titles[n],
415 self.titles[n],
417 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
416 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
418 self.time_label),
417 self.time_label),
419 size=8)
418 size=8)
420 else:
419 else:
421 ax.set_title('{}'.format(self.titles[n]), size=8)
420 ax.set_title('{}'.format(self.titles[n]), size=8)
422 ax.set_ylim(0, 90)
421 ax.set_ylim(0, 90)
423 ax.set_yticks(numpy.arange(0, 90, 20))
422 ax.set_yticks(numpy.arange(0, 90, 20))
424 ax.yaxis.labelpad = 40
423 ax.yaxis.labelpad = 40
425
424
426 def __plot(self):
425 def __plot(self):
427 '''
426 '''
428 '''
427 '''
429 log.success('Plotting', self.name)
428 log.success('Plotting', self.name)
430
429
431 try:
430 try:
432 self.plot()
431 self.plot()
433 self.format()
432 self.format()
434 except:
433 except:
435 log.warning('{} Plot could not be updated... check data'.format(self.CODE), self.name)
434 log.warning('{} Plot could not be updated... check data'.format(self.CODE), self.name)
436
435
437 for n, fig in enumerate(self.figures):
436 for n, fig in enumerate(self.figures):
438 if self.nrows == 0 or self.nplots == 0:
437 if self.nrows == 0 or self.nplots == 0:
439 log.warning('No data', self.name)
438 log.warning('No data', self.name)
440 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
439 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
441 fig.canvas.manager.set_window_title(self.CODE)
440 fig.canvas.manager.set_window_title(self.CODE)
442 continue
441 continue
443
442
444 fig.tight_layout()
443 fig.tight_layout()
445 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
444 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
446 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
445 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
447 fig.canvas.draw()
446 fig.canvas.draw()
448
447
449 if self.save and self.data.ended:
448 if self.save and self.data.ended:
450 channels = range(self.nrows)
449 channels = range(self.nrows)
451 if self.oneFigure:
450 if self.oneFigure:
452 label = ''
451 label = ''
453 else:
452 else:
454 label = '_{}'.format(channels[n])
453 label = '_{}'.format(channels[n])
455 figname = os.path.join(
454 figname = os.path.join(
456 self.save,
455 self.save,
457 '{}{}_{}.png'.format(
456 '{}{}_{}.png'.format(
458 self.CODE,
457 self.CODE,
459 label,
458 label,
460 self.getDateTime(self.saveTime).strftime(
459 self.getDateTime(self.saveTime).strftime(
461 '%Y%m%d_%H%M%S'),
460 '%Y%m%d_%H%M%S'),
462 )
461 )
463 )
462 )
464 log.log('Saving figure: {}'.format(figname), self.name)
463 log.log('Saving figure: {}'.format(figname), self.name)
465 fig.savefig(figname)
464 fig.savefig(figname)
466
465
467 def plot(self):
466 def plot(self):
468 '''
467 '''
469 '''
468 '''
470 raise(NotImplementedError, 'Implement this method in child class')
469 raise(NotImplementedError, 'Implement this method in child class')
471
470
472 def run(self):
471 def run(self):
473
472
474 log.success('Starting', self.name)
473 log.success('Starting', self.name)
475
474
476 context = zmq.Context()
475 context = zmq.Context()
477 receiver = context.socket(zmq.SUB)
476 receiver = context.socket(zmq.SUB)
478 receiver.setsockopt(zmq.SUBSCRIBE, '')
477 receiver.setsockopt(zmq.SUBSCRIBE, '')
479 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
478 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
480
479
481 if 'server' in self.kwargs['parent']:
480 if 'server' in self.kwargs['parent']:
482 receiver.connect(
481 receiver.connect(
483 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
482 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
484 else:
483 else:
485 receiver.connect("ipc:///tmp/zmq.plots")
484 receiver.connect("ipc:///tmp/zmq.plots")
486
485
487 while True:
486 while True:
488 try:
487 try:
489 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
488 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
490 if self.data.localtime and self.localtime:
489 if self.data.localtime and self.localtime:
491 self.times = self.data.times
490 self.times = self.data.times
492 elif self.data.localtime and not self.localtime:
491 elif self.data.localtime and not self.localtime:
493 self.times = self.data.times + time.timezone
492 self.times = self.data.times + time.timezone
494 elif not self.data.localtime and self.localtime:
493 elif not self.data.localtime and self.localtime:
495 self.times = self.data.times - time.timezone
494 self.times = self.data.times - time.timezone
496 else:
495 else:
497 self.times = self.data.times
496 self.times = self.data.times
498
497
499 self.min_time = self.times[0]
498 self.min_time = self.times[0]
500 self.max_time = self.times[-1]
499 self.max_time = self.times[-1]
501
500
502 if self.isConfig is False:
501 if self.isConfig is False:
503 self.__setup()
502 self.__setup()
504 self.isConfig = True
503 self.isConfig = True
505
504
506 self.__plot()
505 self.__plot()
507
506
508 except zmq.Again as e:
507 except zmq.Again as e:
509 log.log('Waiting for data...')
508 log.log('Waiting for data...')
510 if self.data:
509 if self.data:
511 figpause(self.data.throttle)
510 figpause(self.data.throttle)
512 else:
511 else:
513 time.sleep(2)
512 time.sleep(2)
514
513
515 def close(self):
514 def close(self):
516 if self.data:
515 if self.data:
517 self.__plot()
516 self.__plot()
518
517
519
518
520 class PlotSpectraData(PlotData):
519 class PlotSpectraData(PlotData):
521 '''
520 '''
522 Plot for Spectra data
521 Plot for Spectra data
523 '''
522 '''
524
523
525 CODE = 'spc'
524 CODE = 'spc'
526 colormap = 'jro'
525 colormap = 'jro'
527
526
528 def setup(self):
527 def setup(self):
529 self.nplots = len(self.data.channels)
528 self.nplots = len(self.data.channels)
530 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
529 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
531 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
530 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
532 self.width = 3.4 * self.ncols
531 self.width = 3.4 * self.ncols
533 self.height = 3 * self.nrows
532 self.height = 3 * self.nrows
534 self.cb_label = 'dB'
533 self.cb_label = 'dB'
535 if self.showprofile:
534 if self.showprofile:
536 self.width += 0.8 * self.ncols
535 self.width += 0.8 * self.ncols
537
536
538 self.ylabel = 'Range [km]'
537 self.ylabel = 'Range [km]'
539
538
540 def plot(self):
539 def plot(self):
541 if self.xaxis == "frequency":
540 if self.xaxis == "frequency":
542 x = self.data.xrange[0]
541 x = self.data.xrange[0]
543 self.xlabel = "Frequency (kHz)"
542 self.xlabel = "Frequency (kHz)"
544 elif self.xaxis == "time":
543 elif self.xaxis == "time":
545 x = self.data.xrange[1]
544 x = self.data.xrange[1]
546 self.xlabel = "Time (ms)"
545 self.xlabel = "Time (ms)"
547 else:
546 else:
548 x = self.data.xrange[2]
547 x = self.data.xrange[2]
549 self.xlabel = "Velocity (m/s)"
548 self.xlabel = "Velocity (m/s)"
550
549
551 if self.CODE == 'spc_mean':
550 if self.CODE == 'spc_mean':
552 x = self.data.xrange[2]
551 x = self.data.xrange[2]
553 self.xlabel = "Velocity (m/s)"
552 self.xlabel = "Velocity (m/s)"
554
553
555 self.titles = []
554 self.titles = []
556
555
557 y = self.data.heights
556 y = self.data.heights
558 self.y = y
557 self.y = y
559 z = self.data['spc']
558 z = self.data['spc']
560
559
561 for n, ax in enumerate(self.axes):
560 for n, ax in enumerate(self.axes):
562 noise = self.data['noise'][n][-1]
561 noise = self.data['noise'][n][-1]
563 if self.CODE == 'spc_mean':
562 if self.CODE == 'spc_mean':
564 mean = self.data['mean'][n][-1]
563 mean = self.data['mean'][n][-1]
565 if ax.firsttime:
564 if ax.firsttime:
566 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
565 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
567 self.xmin = self.xmin if self.xmin else -self.xmax
566 self.xmin = self.xmin if self.xmin else -self.xmax
568 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
567 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
569 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
568 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
570 ax.plt = ax.pcolormesh(x, y, z[n].T,
569 ax.plt = ax.pcolormesh(x, y, z[n].T,
571 vmin=self.zmin,
570 vmin=self.zmin,
572 vmax=self.zmax,
571 vmax=self.zmax,
573 cmap=plt.get_cmap(self.colormap)
572 cmap=plt.get_cmap(self.colormap)
574 )
573 )
575
574
576 if self.showprofile:
575 if self.showprofile:
577 ax.plt_profile = self.pf_axes[n].plot(
576 ax.plt_profile = self.pf_axes[n].plot(
578 self.data['rti'][n][-1], y)[0]
577 self.data['rti'][n][-1], y)[0]
579 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
578 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
580 color="k", linestyle="dashed", lw=1)[0]
579 color="k", linestyle="dashed", lw=1)[0]
581 if self.CODE == 'spc_mean':
580 if self.CODE == 'spc_mean':
582 ax.plt_mean = ax.plot(mean, y, color='k')[0]
581 ax.plt_mean = ax.plot(mean, y, color='k')[0]
583 else:
582 else:
584 ax.plt.set_array(z[n].T.ravel())
583 ax.plt.set_array(z[n].T.ravel())
585 if self.showprofile:
584 if self.showprofile:
586 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
585 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
587 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
586 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
588 if self.CODE == 'spc_mean':
587 if self.CODE == 'spc_mean':
589 ax.plt_mean.set_data(mean, y)
588 ax.plt_mean.set_data(mean, y)
590
589
591 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
590 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
592 self.saveTime = self.max_time
591 self.saveTime = self.max_time
593
592
594
593
595 class PlotCrossSpectraData(PlotData):
594 class PlotCrossSpectraData(PlotData):
596
595
597 CODE = 'cspc'
596 CODE = 'cspc'
598 zmin_coh = None
597 zmin_coh = None
599 zmax_coh = None
598 zmax_coh = None
600 zmin_phase = None
599 zmin_phase = None
601 zmax_phase = None
600 zmax_phase = None
602
601
603 def setup(self):
602 def setup(self):
604
603
605 self.ncols = 4
604 self.ncols = 4
606 self.nrows = len(self.data.pairs)
605 self.nrows = len(self.data.pairs)
607 self.nplots = self.nrows * 4
606 self.nplots = self.nrows * 4
608 self.width = 3.4 * self.ncols
607 self.width = 3.4 * self.ncols
609 self.height = 3 * self.nrows
608 self.height = 3 * self.nrows
610 self.ylabel = 'Range [km]'
609 self.ylabel = 'Range [km]'
611 self.showprofile = False
610 self.showprofile = False
612
611
613 def plot(self):
612 def plot(self):
614
613
615 if self.xaxis == "frequency":
614 if self.xaxis == "frequency":
616 x = self.data.xrange[0]
615 x = self.data.xrange[0]
617 self.xlabel = "Frequency (kHz)"
616 self.xlabel = "Frequency (kHz)"
618 elif self.xaxis == "time":
617 elif self.xaxis == "time":
619 x = self.data.xrange[1]
618 x = self.data.xrange[1]
620 self.xlabel = "Time (ms)"
619 self.xlabel = "Time (ms)"
621 else:
620 else:
622 x = self.data.xrange[2]
621 x = self.data.xrange[2]
623 self.xlabel = "Velocity (m/s)"
622 self.xlabel = "Velocity (m/s)"
624
623
625 self.titles = []
624 self.titles = []
626
625
627 y = self.data.heights
626 y = self.data.heights
628 self.y = y
627 self.y = y
629 spc = self.data['spc']
628 spc = self.data['spc']
630 cspc = self.data['cspc']
629 cspc = self.data['cspc']
631
630
632 for n in range(self.nrows):
631 for n in range(self.nrows):
633 noise = self.data['noise'][n][-1]
632 noise = self.data['noise'][n][-1]
634 pair = self.data.pairs[n]
633 pair = self.data.pairs[n]
635 ax = self.axes[4 * n]
634 ax = self.axes[4 * n]
636 ax3 = self.axes[4 * n + 3]
635 ax3 = self.axes[4 * n + 3]
637 if ax.firsttime:
636 if ax.firsttime:
638 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
637 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
639 self.xmin = self.xmin if self.xmin else -self.xmax
638 self.xmin = self.xmin if self.xmin else -self.xmax
640 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
639 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
641 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
640 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
642 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
641 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
643 vmin=self.zmin,
642 vmin=self.zmin,
644 vmax=self.zmax,
643 vmax=self.zmax,
645 cmap=plt.get_cmap(self.colormap)
644 cmap=plt.get_cmap(self.colormap)
646 )
645 )
647 else:
646 else:
648 ax.plt.set_array(spc[pair[0]].T.ravel())
647 ax.plt.set_array(spc[pair[0]].T.ravel())
649 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
648 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
650
649
651 ax = self.axes[4 * n + 1]
650 ax = self.axes[4 * n + 1]
652 if ax.firsttime:
651 if ax.firsttime:
653 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
652 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
654 vmin=self.zmin,
653 vmin=self.zmin,
655 vmax=self.zmax,
654 vmax=self.zmax,
656 cmap=plt.get_cmap(self.colormap)
655 cmap=plt.get_cmap(self.colormap)
657 )
656 )
658 else:
657 else:
659 ax.plt.set_array(spc[pair[1]].T.ravel())
658 ax.plt.set_array(spc[pair[1]].T.ravel())
660 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
659 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
661
660
662 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
661 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
663 coh = numpy.abs(out)
662 coh = numpy.abs(out)
664 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
663 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
665
664
666 ax = self.axes[4 * n + 2]
665 ax = self.axes[4 * n + 2]
667 if ax.firsttime:
666 if ax.firsttime:
668 ax.plt = ax.pcolormesh(x, y, coh.T,
667 ax.plt = ax.pcolormesh(x, y, coh.T,
669 vmin=0,
668 vmin=0,
670 vmax=1,
669 vmax=1,
671 cmap=plt.get_cmap(self.colormap_coh)
670 cmap=plt.get_cmap(self.colormap_coh)
672 )
671 )
673 else:
672 else:
674 ax.plt.set_array(coh.T.ravel())
673 ax.plt.set_array(coh.T.ravel())
675 self.titles.append(
674 self.titles.append(
676 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
675 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
677
676
678 ax = self.axes[4 * n + 3]
677 ax = self.axes[4 * n + 3]
679 if ax.firsttime:
678 if ax.firsttime:
680 ax.plt = ax.pcolormesh(x, y, phase.T,
679 ax.plt = ax.pcolormesh(x, y, phase.T,
681 vmin=-180,
680 vmin=-180,
682 vmax=180,
681 vmax=180,
683 cmap=plt.get_cmap(self.colormap_phase)
682 cmap=plt.get_cmap(self.colormap_phase)
684 )
683 )
685 else:
684 else:
686 ax.plt.set_array(phase.T.ravel())
685 ax.plt.set_array(phase.T.ravel())
687 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
686 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
688
687
689 self.saveTime = self.max_time
688 self.saveTime = self.max_time
690
689
691
690
692 class PlotSpectraMeanData(PlotSpectraData):
691 class PlotSpectraMeanData(PlotSpectraData):
693 '''
692 '''
694 Plot for Spectra and Mean
693 Plot for Spectra and Mean
695 '''
694 '''
696 CODE = 'spc_mean'
695 CODE = 'spc_mean'
697 colormap = 'jro'
696 colormap = 'jro'
698
697
699
698
700 class PlotRTIData(PlotData):
699 class PlotRTIData(PlotData):
701 '''
700 '''
702 Plot for RTI data
701 Plot for RTI data
703 '''
702 '''
704
703
705 CODE = 'rti'
704 CODE = 'rti'
706 colormap = 'jro'
705 colormap = 'jro'
707
706
708 def setup(self):
707 def setup(self):
709 self.xaxis = 'time'
708 self.xaxis = 'time'
710 self.ncols = 1
709 self.ncols = 1
711 self.nrows = len(self.data.channels)
710 self.nrows = len(self.data.channels)
712 self.nplots = len(self.data.channels)
711 self.nplots = len(self.data.channels)
713 self.ylabel = 'Range [km]'
712 self.ylabel = 'Range [km]'
714 self.cb_label = 'dB'
713 self.cb_label = 'dB'
715 self.titles = ['{} Channel {}'.format(
714 self.titles = ['{} Channel {}'.format(
716 self.CODE.upper(), x) for x in range(self.nrows)]
715 self.CODE.upper(), x) for x in range(self.nrows)]
717
716
718 def plot(self):
717 def plot(self):
719 self.x = self.times
718 self.x = self.times
720 self.y = self.data.heights
719 self.y = self.data.heights
721 self.z = self.data[self.CODE]
720 self.z = self.data[self.CODE]
722 self.z = numpy.ma.masked_invalid(self.z)
721 self.z = numpy.ma.masked_invalid(self.z)
723
722
724 if self.decimation is None:
723 if self.decimation is None:
725 x, y, z = self.fill_gaps(self.x, self.y, self.z)
724 x, y, z = self.fill_gaps(self.x, self.y, self.z)
726 else:
725 else:
727 x, y, z = self.fill_gaps(*self.decimate())
726 x, y, z = self.fill_gaps(*self.decimate())
728
727
729 for n, ax in enumerate(self.axes):
728 for n, ax in enumerate(self.axes):
730 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
729 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
731 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
730 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
732 if ax.firsttime:
731 if ax.firsttime:
733 ax.plt = ax.pcolormesh(x, y, z[n].T,
732 ax.plt = ax.pcolormesh(x, y, z[n].T,
734 vmin=self.zmin,
733 vmin=self.zmin,
735 vmax=self.zmax,
734 vmax=self.zmax,
736 cmap=plt.get_cmap(self.colormap)
735 cmap=plt.get_cmap(self.colormap)
737 )
736 )
738 if self.showprofile:
737 if self.showprofile:
739 ax.plot_profile = self.pf_axes[n].plot(
738 ax.plot_profile = self.pf_axes[n].plot(
740 self.data['rti'][n][-1], self.y)[0]
739 self.data['rti'][n][-1], self.y)[0]
741 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
740 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
742 color="k", linestyle="dashed", lw=1)[0]
741 color="k", linestyle="dashed", lw=1)[0]
743 else:
742 else:
744 ax.collections.remove(ax.collections[0])
743 ax.collections.remove(ax.collections[0])
745 ax.plt = ax.pcolormesh(x, y, z[n].T,
744 ax.plt = ax.pcolormesh(x, y, z[n].T,
746 vmin=self.zmin,
745 vmin=self.zmin,
747 vmax=self.zmax,
746 vmax=self.zmax,
748 cmap=plt.get_cmap(self.colormap)
747 cmap=plt.get_cmap(self.colormap)
749 )
748 )
750 if self.showprofile:
749 if self.showprofile:
751 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
750 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
752 ax.plot_noise.set_data(numpy.repeat(
751 ax.plot_noise.set_data(numpy.repeat(
753 self.data['noise'][n][-1], len(self.y)), self.y)
752 self.data['noise'][n][-1], len(self.y)), self.y)
754
753
755 self.saveTime = self.min_time
754 self.saveTime = self.min_time
756
755
757
756
758 class PlotCOHData(PlotRTIData):
757 class PlotCOHData(PlotRTIData):
759 '''
758 '''
760 Plot for Coherence data
759 Plot for Coherence data
761 '''
760 '''
762
761
763 CODE = 'coh'
762 CODE = 'coh'
764
763
765 def setup(self):
764 def setup(self):
766 self.xaxis = 'time'
765 self.xaxis = 'time'
767 self.ncols = 1
766 self.ncols = 1
768 self.nrows = len(self.data.pairs)
767 self.nrows = len(self.data.pairs)
769 self.nplots = len(self.data.pairs)
768 self.nplots = len(self.data.pairs)
770 self.ylabel = 'Range [km]'
769 self.ylabel = 'Range [km]'
771 if self.CODE == 'coh':
770 if self.CODE == 'coh':
772 self.cb_label = ''
771 self.cb_label = ''
773 self.titles = [
772 self.titles = [
774 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
773 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
775 else:
774 else:
776 self.cb_label = 'Degrees'
775 self.cb_label = 'Degrees'
777 self.titles = [
776 self.titles = [
778 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
777 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
779
778
780
779
781 class PlotPHASEData(PlotCOHData):
780 class PlotPHASEData(PlotCOHData):
782 '''
781 '''
783 Plot for Phase map data
782 Plot for Phase map data
784 '''
783 '''
785
784
786 CODE = 'phase'
785 CODE = 'phase'
787 colormap = 'seismic'
786 colormap = 'seismic'
788
787
789
788
790 class PlotNoiseData(PlotData):
789 class PlotNoiseData(PlotData):
791 '''
790 '''
792 Plot for noise
791 Plot for noise
793 '''
792 '''
794
793
795 CODE = 'noise'
794 CODE = 'noise'
796
795
797 def setup(self):
796 def setup(self):
798 self.xaxis = 'time'
797 self.xaxis = 'time'
799 self.ncols = 1
798 self.ncols = 1
800 self.nrows = 1
799 self.nrows = 1
801 self.nplots = 1
800 self.nplots = 1
802 self.ylabel = 'Intensity [dB]'
801 self.ylabel = 'Intensity [dB]'
803 self.titles = ['Noise']
802 self.titles = ['Noise']
804 self.colorbar = False
803 self.colorbar = False
805
804
806 def plot(self):
805 def plot(self):
807
806
808 x = self.times
807 x = self.times
809 xmin = self.min_time
808 xmin = self.min_time
810 xmax = xmin + self.xrange * 60 * 60
809 xmax = xmin + self.xrange * 60 * 60
811 Y = self.data[self.CODE]
810 Y = self.data[self.CODE]
812
811
813 if self.axes[0].firsttime:
812 if self.axes[0].firsttime:
814 for ch in self.data.channels:
813 for ch in self.data.channels:
815 y = Y[ch]
814 y = Y[ch]
816 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
815 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
817 plt.legend()
816 plt.legend()
818 else:
817 else:
819 for ch in self.data.channels:
818 for ch in self.data.channels:
820 y = Y[ch]
819 y = Y[ch]
821 self.axes[0].lines[ch].set_data(x, y)
820 self.axes[0].lines[ch].set_data(x, y)
822
821
823 self.ymin = numpy.nanmin(Y) - 5
822 self.ymin = numpy.nanmin(Y) - 5
824 self.ymax = numpy.nanmax(Y) + 5
823 self.ymax = numpy.nanmax(Y) + 5
825 self.saveTime = self.min_time
824 self.saveTime = self.min_time
826
825
827
826
828 class PlotSNRData(PlotRTIData):
827 class PlotSNRData(PlotRTIData):
829 '''
828 '''
830 Plot for SNR Data
829 Plot for SNR Data
831 '''
830 '''
832
831
833 CODE = 'snr'
832 CODE = 'snr'
834 colormap = 'jet'
833 colormap = 'jet'
835
834
836
835
837 class PlotDOPData(PlotRTIData):
836 class PlotDOPData(PlotRTIData):
838 '''
837 '''
839 Plot for DOPPLER Data
838 Plot for DOPPLER Data
840 '''
839 '''
841
840
842 CODE = 'dop'
841 CODE = 'dop'
843 colormap = 'jet'
842 colormap = 'jet'
844
843
845
844
846 class PlotSkyMapData(PlotData):
845 class PlotSkyMapData(PlotData):
847 '''
846 '''
848 Plot for meteors detection data
847 Plot for meteors detection data
849 '''
848 '''
850
849
851 CODE = 'param'
850 CODE = 'param'
852
851
853 def setup(self):
852 def setup(self):
854
853
855 self.ncols = 1
854 self.ncols = 1
856 self.nrows = 1
855 self.nrows = 1
857 self.width = 7.2
856 self.width = 7.2
858 self.height = 7.2
857 self.height = 7.2
859 self.nplots = 1
858 self.nplots = 1
860 self.xlabel = 'Zonal Zenith Angle (deg)'
859 self.xlabel = 'Zonal Zenith Angle (deg)'
861 self.ylabel = 'Meridional Zenith Angle (deg)'
860 self.ylabel = 'Meridional Zenith Angle (deg)'
862 self.polar = True
861 self.polar = True
863 self.ymin = -180
862 self.ymin = -180
864 self.ymax = 180
863 self.ymax = 180
865 self.colorbar = False
864 self.colorbar = False
866
865
867 def plot(self):
866 def plot(self):
868
867
869 arrayParameters = numpy.concatenate(self.data['param'])
868 arrayParameters = numpy.concatenate(self.data['param'])
870 error = arrayParameters[:, -1]
869 error = arrayParameters[:, -1]
871 indValid = numpy.where(error == 0)[0]
870 indValid = numpy.where(error == 0)[0]
872 finalMeteor = arrayParameters[indValid, :]
871 finalMeteor = arrayParameters[indValid, :]
873 finalAzimuth = finalMeteor[:, 3]
872 finalAzimuth = finalMeteor[:, 3]
874 finalZenith = finalMeteor[:, 4]
873 finalZenith = finalMeteor[:, 4]
875
874
876 x = finalAzimuth * numpy.pi / 180
875 x = finalAzimuth * numpy.pi / 180
877 y = finalZenith
876 y = finalZenith
878
877
879 ax = self.axes[0]
878 ax = self.axes[0]
880
879
881 if ax.firsttime:
880 if ax.firsttime:
882 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
881 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
883 else:
882 else:
884 ax.plot.set_data(x, y)
883 ax.plot.set_data(x, y)
885
884
886 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
885 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
887 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
886 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
888 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
887 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
889 dt2,
888 dt2,
890 len(x))
889 len(x))
891 self.titles[0] = title
890 self.titles[0] = title
892 self.saveTime = self.max_time
891 self.saveTime = self.max_time
893
892
894
893
895 class PlotParamData(PlotRTIData):
894 class PlotParamData(PlotRTIData):
896 '''
895 '''
897 Plot for data_param object
896 Plot for data_param object
898 '''
897 '''
899
898
900 CODE = 'param'
899 CODE = 'param'
901 colormap = 'seismic'
900 colormap = 'seismic'
902
901
903 def setup(self):
902 def setup(self):
904 self.xaxis = 'time'
903 self.xaxis = 'time'
905 self.ncols = 1
904 self.ncols = 1
906 self.nrows = self.data.shape(self.CODE)[0]
905 self.nrows = self.data.shape(self.CODE)[0]
907 self.nplots = self.nrows
906 self.nplots = self.nrows
908 if self.showSNR:
907 if self.showSNR:
909 self.nrows += 1
908 self.nrows += 1
910 self.nplots += 1
909 self.nplots += 1
911
910
912 self.ylabel = 'Height [km]'
911 self.ylabel = 'Height [km]'
913 if not self.titles:
912 if not self.titles:
914 self.titles = self.data.parameters \
913 self.titles = self.data.parameters \
915 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
914 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
916 if self.showSNR:
915 if self.showSNR:
917 self.titles.append('SNR')
916 self.titles.append('SNR')
918
917
919 def plot(self):
918 def plot(self):
920 self.data.normalize_heights()
919 self.data.normalize_heights()
921 self.x = self.times
920 self.x = self.times
922 self.y = self.data.heights
921 self.y = self.data.heights
923 if self.showSNR:
922 if self.showSNR:
924 self.z = numpy.concatenate(
923 self.z = numpy.concatenate(
925 (self.data[self.CODE], self.data['snr'])
924 (self.data[self.CODE], self.data['snr'])
926 )
925 )
927 else:
926 else:
928 self.z = self.data[self.CODE]
927 self.z = self.data[self.CODE]
929
928
930 self.z = numpy.ma.masked_invalid(self.z)
929 self.z = numpy.ma.masked_invalid(self.z)
931
930
932 if self.decimation is None:
931 if self.decimation is None:
933 x, y, z = self.fill_gaps(self.x, self.y, self.z)
932 x, y, z = self.fill_gaps(self.x, self.y, self.z)
934 else:
933 else:
935 x, y, z = self.fill_gaps(*self.decimate())
934 x, y, z = self.fill_gaps(*self.decimate())
936
935
937 for n, ax in enumerate(self.axes):
936 for n, ax in enumerate(self.axes):
938
937
939 self.zmax = self.zmax if self.zmax is not None else numpy.max(
938 self.zmax = self.zmax if self.zmax is not None else numpy.max(
940 self.z[n])
939 self.z[n])
941 self.zmin = self.zmin if self.zmin is not None else numpy.min(
940 self.zmin = self.zmin if self.zmin is not None else numpy.min(
942 self.z[n])
941 self.z[n])
943
942
944 if ax.firsttime:
943 if ax.firsttime:
945 if self.zlimits is not None:
944 if self.zlimits is not None:
946 self.zmin, self.zmax = self.zlimits[n]
945 self.zmin, self.zmax = self.zlimits[n]
947
946
948 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
947 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
949 vmin=self.zmin,
948 vmin=self.zmin,
950 vmax=self.zmax,
949 vmax=self.zmax,
951 cmap=self.cmaps[n]
950 cmap=self.cmaps[n]
952 )
951 )
953 else:
952 else:
954 if self.zlimits is not None:
953 if self.zlimits is not None:
955 self.zmin, self.zmax = self.zlimits[n]
954 self.zmin, self.zmax = self.zlimits[n]
956 ax.collections.remove(ax.collections[0])
955 ax.collections.remove(ax.collections[0])
957 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
956 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
958 vmin=self.zmin,
957 vmin=self.zmin,
959 vmax=self.zmax,
958 vmax=self.zmax,
960 cmap=self.cmaps[n]
959 cmap=self.cmaps[n]
961 )
960 )
962
961
963 self.saveTime = self.min_time
962 self.saveTime = self.min_time
964
963
965
964
966 class PlotOutputData(PlotParamData):
965 class PlotOutputData(PlotParamData):
967 '''
966 '''
968 Plot data_output object
967 Plot data_output object
969 '''
968 '''
970
969
971 CODE = 'output'
970 CODE = 'output'
972 colormap = 'seismic'
971 colormap = 'seismic'
General Comments 0
You need to be logged in to leave comments. Login now