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