##// END OF EJS Templates
Merge branch 'v2.3' of http://jro-dev.igp.gob.pe/rhodecode/schain into v2.3
José Chávez -
r1109:354077bea65d merge
parent child
Show More
@@ -0,0 +1,343
1 '''
2 Created on Set 10, 2017
3
4 @author: Juan C. Espinoza
5 '''
6
7
8 import os
9 import sys
10 import time
11 import glob
12 import datetime
13
14 import numpy
15
16 from schainpy.model.proc.jroproc_base import ProcessingUnit
17 from schainpy.model.data.jrodata import Parameters
18 from schainpy.model.io.jroIO_base import JRODataReader, isNumber
19 from schainpy.utils import log
20
21 FILE_HEADER_STRUCTURE = numpy.dtype([
22 ('year', 'f'),
23 ('doy', 'f'),
24 ('nint', 'f'),
25 ('navg', 'f'),
26 ('fh', 'f'),
27 ('dh', 'f'),
28 ('nheights', 'f'),
29 ('ipp', 'f')
30 ])
31
32 REC_HEADER_STRUCTURE = numpy.dtype([
33 ('magic', 'f'),
34 ('hours', 'f'),
35 ('interval', 'f'),
36 ('h0', 'f'),
37 ('nheights', 'f'),
38 ('snr1', 'f'),
39 ('snr2', 'f'),
40 ('snr', 'f'),
41 ])
42
43 DATA_STRUCTURE = numpy.dtype([
44 ('range', '<u4'),
45 ('status', '<u4'),
46 ('zonal', '<f4'),
47 ('meridional', '<f4'),
48 ('vertical', '<f4'),
49 ('zonal_a', '<f4'),
50 ('meridional_a', '<f4'),
51 ('corrected_fading', '<f4'), # seconds
52 ('uncorrected_fading', '<f4'), # seconds
53 ('time_diff', '<f4'),
54 ('major_axis', '<f4'),
55 ('axial_ratio', '<f4'),
56 ('orientation', '<f4'),
57 ('sea_power', '<u4'),
58 ('sea_algorithm', '<u4')
59 ])
60
61
62 class JULIAParamReader(JRODataReader, ProcessingUnit):
63 '''
64 Julia data (eej, spf, 150km) *.dat files
65 '''
66
67 ext = '.dat'
68
69 def __init__(self, **kwargs):
70
71 ProcessingUnit.__init__(self, **kwargs)
72
73 self.dataOut = Parameters()
74 self.counter_records = 0
75 self.flagNoMoreFiles = 0
76 self.isConfig = False
77 self.filename = None
78 self.clockpulse = 0.15
79 self.kd = 213.6
80
81 def setup(self,
82 path=None,
83 startDate=None,
84 endDate=None,
85 ext=None,
86 startTime=datetime.time(0, 0, 0),
87 endTime=datetime.time(23, 59, 59),
88 timezone=0,
89 format=None,
90 **kwargs):
91
92 self.path = path
93 self.startDate = startDate
94 self.endDate = endDate
95 self.startTime = startTime
96 self.endTime = endTime
97 self.datatime = datetime.datetime(1900, 1, 1)
98 self.format = format
99
100 if self.path is None:
101 raise ValueError, "The path is not valid"
102
103 if ext is None:
104 ext = self.ext
105
106 self.search_files(self.path, startDate, endDate, ext)
107 self.timezone = timezone
108 self.fileIndex = 0
109
110 if not self.fileList:
111 log.warning('There is no files matching these date in the folder: {}'.format(
112 path), self.name)
113
114 self.setNextFile()
115
116 def search_files(self, path, startDate, endDate, ext):
117 '''
118 Searching for BLTR rawdata file in path
119 Creating a list of file to proces included in [startDate,endDate]
120
121 Input:
122 path - Path to find BLTR rawdata files
123 startDate - Select file from this date
124 enDate - Select file until this date
125 ext - Extension of the file to read
126 '''
127
128 log.success('Searching files in {} '.format(path), self.name)
129 fileList0 = glob.glob1(path, '{}*{}'.format(self.format.upper(), ext))
130 fileList0.sort()
131
132 self.fileList = []
133 self.dateFileList = []
134
135 for thisFile in fileList0:
136 year = thisFile[2:4]
137 if not isNumber(year):
138 continue
139
140 month = thisFile[4:6]
141 if not isNumber(month):
142 continue
143
144 day = thisFile[6:8]
145 if not isNumber(day):
146 continue
147
148 year, month, day = int(year), int(month), int(day)
149 dateFile = datetime.date(year+2000, month, day)
150
151 if (startDate > dateFile) or (endDate < dateFile):
152 continue
153
154 self.fileList.append(thisFile)
155 self.dateFileList.append(dateFile)
156
157 return
158
159 def setNextFile(self):
160
161 file_id = self.fileIndex
162
163 if file_id == len(self.fileList):
164 log.success('No more files in the folder', self.name)
165 self.flagNoMoreFiles = 1
166 return 0
167
168 log.success('Opening {}'.format(self.fileList[file_id]), self.name)
169 filename = os.path.join(self.path, self.fileList[file_id])
170
171 dirname, name = os.path.split(filename)
172 self.siteFile = name.split('.')[0]
173 if self.filename is not None:
174 self.fp.close()
175 self.filename = filename
176 self.fp = open(self.filename, 'rb')
177
178 self.header_file = numpy.fromfile(self.fp, FILE_HEADER_STRUCTURE, 1)
179 yy = self.header_file['year'] - 1900 * (self.header_file['year'] > 3000)
180 self.year = int(yy + 1900 * (yy < 1000))
181 self.doy = int(self.header_file['doy'])
182 self.dH = round(self.header_file['dh'], 2)
183 self.ipp = round(self.header_file['ipp'], 2)
184 self.sizeOfFile = os.path.getsize(self.filename)
185 self.counter_records = 0
186 self.flagIsNewFile = 0
187 self.fileIndex += 1
188
189 return 1
190
191 def readNextBlock(self):
192
193 while True:
194 if not self.readBlock():
195 self.flagIsNewFile = 1
196 if not self.setNextFile():
197 return 0
198
199 if (self.datatime < datetime.datetime.combine(self.startDate, self.startTime)) or \
200 (self.datatime > datetime.datetime.combine(self.endDate, self.endTime)):
201 log.warning(
202 'Reading Record No. {} -> {} [Skipping]'.format(
203 self.counter_records,
204 self.datatime.ctime()),
205 self.name)
206 continue
207 break
208
209 log.log('Reading Record No. {} -> {}'.format(
210 self.counter_records,
211 self.datatime.ctime()), self.name)
212
213 return 1
214
215 def readBlock(self):
216
217 pointer = self.fp.tell()
218 heights, dt = self.readHeader()
219 self.fp.seek(pointer)
220 buffer_h = []
221 buffer_d = []
222 while True:
223 pointer = self.fp.tell()
224 if pointer == self.sizeOfFile:
225 return 0
226 heights, datatime = self.readHeader()
227 if dt == datatime:
228 buffer_h.append(heights)
229 buffer_d.append(self.readData(len(heights)))
230 continue
231 self.fp.seek(pointer)
232 break
233
234 if dt.date() > self.datatime.date():
235 self.flagDiscontinuousBlock = 1
236 self.datatime = dt
237 self.time = (dt - datetime.datetime(1970, 1, 1)).total_seconds() + time.timezone
238 self.heights = numpy.concatenate(buffer_h)
239 self.buffer = numpy.zeros((5, len(self.heights))) + numpy.nan
240 self.buffer[0, :] = numpy.concatenate([buf[0] for buf in buffer_d])
241 self.buffer[1, :] = numpy.concatenate([buf[1] for buf in buffer_d])
242 self.buffer[2, :] = numpy.concatenate([buf[2] for buf in buffer_d])
243 self.buffer[3, :] = numpy.concatenate([buf[3] for buf in buffer_d])
244 self.buffer[4, :] = numpy.concatenate([buf[4] for buf in buffer_d])
245
246 self.counter_records += 1
247
248 return 1
249
250 def readHeader(self):
251 '''
252 Parse recordHeader
253 '''
254
255 self.header_rec = numpy.fromfile(self.fp, REC_HEADER_STRUCTURE, 1)
256 self.interval = self.header_rec['interval']
257 if self.header_rec['magic'] == 888.:
258 self.header_rec['h0'] = round(self.header_rec['h0'], 2)
259 nheights = int(self.header_rec['nheights'])
260 hours = float(self.header_rec['hours'][0])
261 heights = numpy.arange(nheights) * self.dH + self.header_rec['h0']
262 datatime = datetime.datetime(self.year, 1, 1) + datetime.timedelta(days=self.doy-1, hours=hours)
263 return heights, datatime
264 else:
265 return False
266
267 def readData(self, N):
268 '''
269 Parse data
270 '''
271
272 buffer = numpy.fromfile(self.fp, 'f', 8*N).reshape(N, 8)
273
274 pow0 = buffer[:, 0]
275 pow1 = buffer[:, 1]
276 acf0 = (buffer[:,2] + buffer[:,3]*1j) / pow0
277 acf1 = (buffer[:,4] + buffer[:,5]*1j) / pow1
278 dccf = (buffer[:,6] + buffer[:,7]*1j) / (pow0*pow1)
279
280 ### SNR
281 sno = (pow0 + pow1 - self.header_rec['snr']) / self.header_rec['snr']
282 sno10 = numpy.log10(sno)
283 # dsno = 1.0 / numpy.sqrt(self.header_file['nint'] * self.header_file['navg']) * (1 + (1 / sno))
284
285 ### Vertical Drift
286 sp = numpy.sqrt(numpy.abs(acf0)*numpy.abs(acf1))
287 sp[numpy.where(numpy.abs(sp) >= 1.0)] = numpy.sqrt(0.9999)
288
289 vzo = -numpy.arctan2(acf0.imag + acf1.imag,acf0.real + acf1.real)*1.5E5*1.5/(self.ipp*numpy.pi)
290 dvzo = numpy.sqrt(1.0 - sp*sp)*0.338*1.5E5/(numpy.sqrt(self.header_file['nint']*self.header_file['navg'])*sp*self.ipp)
291 err = numpy.where(dvzo <= 0.1)
292 dvzo[err] = 0.1
293
294 #Zonal Drifts
295 dt = self.header_file['nint']*self.ipp / 1.5E5
296 coh = numpy.sqrt(numpy.abs(dccf))
297 err = numpy.where(coh >= 1.0)
298 coh[err] = numpy.sqrt(0.99999)
299
300 err = numpy.where(coh <= 0.1)
301 coh[err] = numpy.sqrt(0.1)
302
303 vxo = numpy.arctan2(dccf.imag, dccf.real)*self.header_rec['h0']*1.0E3/(self.kd*dt)
304 dvxo = numpy.sqrt(1.0 - coh*coh)*self.header_rec['h0']*1.0E3/(numpy.sqrt(self.header_file['nint']*self.header_file['navg'])*coh*self.kd*dt)
305
306 err = numpy.where(dvxo <= 0.1)
307 dvxo[err] = 0.1
308
309 return vzo, dvzo, vxo, dvxo, sno10
310
311 def set_output(self):
312 '''
313 Storing data from databuffer to dataOut object
314 '''
315
316 self.dataOut.data_SNR = self.buffer[4].reshape(1, -1)
317 self.dataOut.heightList = self.heights
318 self.dataOut.data_param = self.buffer[0:4,]
319 self.dataOut.utctimeInit = self.time
320 self.dataOut.utctime = self.time
321 self.dataOut.useLocalTime = True
322 self.dataOut.paramInterval = self.interval
323 self.dataOut.timezone = self.timezone
324 self.dataOut.sizeOfFile = self.sizeOfFile
325 self.dataOut.flagNoData = False
326 self.dataOut.flagDiscontinuousBlock = self.flagDiscontinuousBlock
327
328 def getData(self):
329 '''
330 Storing data from databuffer to dataOut object
331 '''
332 if self.flagNoMoreFiles:
333 self.dataOut.flagNoData = True
334 log.success('No file left to process', self.name)
335 return 0
336
337 if not self.readNextBlock():
338 self.dataOut.flagNoData = True
339 return 0
340
341 self.set_output()
342
343 return 1
@@ -1,109 +1,112
1 ## CHANGELOG:
1 ## CHANGELOG:
2
2
3 ### 2.3
3 ### 2.3
4 * Added support for Madrigal formats (reading/writing).
5 * Added support for reading BLTR parameters (*.sswma).
6 * Added support for reading Julia format (*.dat).
4 * Added high order function `MPProject` for multiprocessing scripts.
7 * Added high order function `MPProject` for multiprocessing scripts.
5 * Added two new Processing Units `PublishData` and `ReceiverData` for receiving and sending dataOut through multiple ways (tcp, ipc, inproc).
8 * Added two new Processing Units `PublishData` and `ReceiverData` for receiving and sending dataOut through multiple ways (tcp, ipc, inproc).
6 * Added a new graphics Processing Unit `PlotterReceiver`. It is decoupled from normal processing sequence with support for data generated by multiprocessing scripts.
9 * Added a new graphics Processing Unit `PlotterReceiver`. It is decoupled from normal processing sequence with support for data generated by multiprocessing scripts.
7 * Added support for sending realtime graphic to web server.
10 * Added support for sending realtime graphic to web server.
8 * GUI command `schain` is now `schainGUI`.
11 * GUI command `schain` is now `schainGUI`.
9 * Added a CLI tool named `schain`.
12 * Added a CLI tool named `schain`.
10 * Scripts templates can be now generated with `schain generate`.
13 * Scripts templates can be now generated with `schain generate`.
11 * Now it is possible to search Processing Units and Operations with `schain search [module]` to get the right name and its allowed parameters.
14 * Now it is possible to search Processing Units and Operations with `schain search [module]` to get the right name and its allowed parameters.
12 * `schain xml` to run xml scripts.
15 * `schain xml` to run xml scripts.
13 * Added suggestions when parameters are poorly written.
16 * Added suggestions when parameters are poorly written.
14 * `Controller.start()` now runs in a different process than the process calling it.
17 * `Controller.start()` now runs in a different process than the process calling it.
15 * Added `schainpy.utils.log` for log standarization.
18 * Added `schainpy.utils.log` for log standarization.
16 * Running script on online mode no longer ignores date and hour. Issue #1109.
19 * Running script on online mode no longer ignores date and hour. Issue #1109.
17 * Added support for receving voltage data directly from JARS (tcp, ipc).
20 * Added support for receving voltage data directly from JARS (tcp, ipc).
18 * Updated README for MAC OS GUI installation.
21 * Updated README for MAC OS GUI installation.
19 * Setup now installs numpy.
22 * Setup now installs numpy.
20
23
21 ### 2.2.6
24 ### 2.2.6
22 * Graphics generated by the GUI are now the same as generated by scripts. Issue #1074.
25 * Graphics generated by the GUI are now the same as generated by scripts. Issue #1074.
23 * Added support for C extensions.
26 * Added support for C extensions.
24 * Function `hildebrand_sehkon` optimized with a C wrapper.
27 * Function `hildebrand_sehkon` optimized with a C wrapper.
25 * Numpy version updated.
28 * Numpy version updated.
26 * Migration to GIT.
29 * Migration to GIT.
27
30
28 ### 2.2.5:
31 ### 2.2.5:
29 * splitProfiles and combineProfiles modules were added to VoltageProc and Signal Chain GUI.
32 * splitProfiles and combineProfiles modules were added to VoltageProc and Signal Chain GUI.
30 * nProfiles of USRP data (hdf5) is the number of profiles thera are in one second.
33 * nProfiles of USRP data (hdf5) is the number of profiles thera are in one second.
31 * jroPlotter works directly with data objects instead of dictionaries
34 * jroPlotter works directly with data objects instead of dictionaries
32 * script "schain" was added to Signal Chain installer
35 * script "schain" was added to Signal Chain installer
33
36
34 ### 2.2.4.1:
37 ### 2.2.4.1:
35 * jroIO_usrp.py is update to read Sandra's data
38 * jroIO_usrp.py is update to read Sandra's data
36 * decimation in Spectra and RTI plots is always enabled.
39 * decimation in Spectra and RTI plots is always enabled.
37 * time* window option added to GUI
40 * time* window option added to GUI
38
41
39 ### 2.2.4:
42 ### 2.2.4:
40 * jroproc_spectra_lags.py added to schainpy
43 * jroproc_spectra_lags.py added to schainpy
41 * Bug fixed in schainGUI: ProcUnit was created with the same id in some cases.
44 * Bug fixed in schainGUI: ProcUnit was created with the same id in some cases.
42 * Bug fixed in jroHeaderIO: Header size validation.
45 * Bug fixed in jroHeaderIO: Header size validation.
43
46
44 ### 2.2.3.1:
47 ### 2.2.3.1:
45 * Filtering block by time has been added.
48 * Filtering block by time has been added.
46 * Bug fixed plotting RTI, CoherenceMap and others using xmin and xmax parameters. The first day worked
49 * Bug fixed plotting RTI, CoherenceMap and others using xmin and xmax parameters. The first day worked
47 properly but the next days did not.
50 properly but the next days did not.
48
51
49 ### 2.2.3:
52 ### 2.2.3:
50 * Bug fixed in GUI: Error getting(reading) Code value
53 * Bug fixed in GUI: Error getting(reading) Code value
51 * Bug fixed in GUI: Flip option always needs channelList field
54 * Bug fixed in GUI: Flip option always needs channelList field
52 * Bug fixed in jrodata: when one branch modified a value in "dataOut" (example: dataOut.code) this value
55 * Bug fixed in jrodata: when one branch modified a value in "dataOut" (example: dataOut.code) this value
53 was modified for every branch (because this was a reference). It was modified in data.copy()
56 was modified for every branch (because this was a reference). It was modified in data.copy()
54 * Bug fixed in jroproc_voltage.profileSelector(): rangeList replaces to profileRangeList.
57 * Bug fixed in jroproc_voltage.profileSelector(): rangeList replaces to profileRangeList.
55
58
56 ### 2.2.2:
59 ### 2.2.2:
57 * VoltageProc: ProfileSelector, Reshape, Decoder with nTxs!=1 and getblock=True was tested
60 * VoltageProc: ProfileSelector, Reshape, Decoder with nTxs!=1 and getblock=True was tested
58 * Rawdata and testRawdata.py added to Signal Chain project
61 * Rawdata and testRawdata.py added to Signal Chain project
59
62
60 ### 2.2.1:
63 ### 2.2.1:
61 * Bugs fixed in GUI
64 * Bugs fixed in GUI
62 * Views were improved in GUI
65 * Views were improved in GUI
63 * Support to MST* ISR experiments
66 * Support to MST* ISR experiments
64 * Bug fixed getting noise using hyldebrant. (minimum number of points > 20%)
67 * Bug fixed getting noise using hyldebrant. (minimum number of points > 20%)
65 * handleError added to jroplotter.py
68 * handleError added to jroplotter.py
66
69
67 ### 2.2.0:
70 ### 2.2.0:
68 * GUI: use of external plotter
71 * GUI: use of external plotter
69 * Compatible with matplotlib 1.5.0
72 * Compatible with matplotlib 1.5.0
70
73
71 ### 2.1.5:
74 ### 2.1.5:
72 * serializer module added to Signal Chain
75 * serializer module added to Signal Chain
73 * jroplotter.py added to Signal Chain
76 * jroplotter.py added to Signal Chain
74
77
75 ### 2.1.4.2:
78 ### 2.1.4.2:
76 * A new Plotter Class was added
79 * A new Plotter Class was added
77 * Project.start() does not accept filename as a parameter anymore
80 * Project.start() does not accept filename as a parameter anymore
78
81
79 ### 2.1.4.1:
82 ### 2.1.4.1:
80 * Send notifications when an error different to ValueError is detected
83 * Send notifications when an error different to ValueError is detected
81
84
82 ### 2.1.4:
85 ### 2.1.4:
83 * Sending error notifications to signal chain administrator
86 * Sending error notifications to signal chain administrator
84 * Login to email server added
87 * Login to email server added
85
88
86 ### 2.1.3.3:
89 ### 2.1.3.3:
87 * Colored Button Icons were added to GUI
90 * Colored Button Icons were added to GUI
88
91
89 ### 2.1.3.2:
92 ### 2.1.3.2:
90 * GUI: user interaction enhanced
93 * GUI: user interaction enhanced
91 * controller_api.py: Safe access to ControllerThead
94 * controller_api.py: Safe access to ControllerThead
92
95
93 ### 2.1.3.1:
96 ### 2.1.3.1:
94 * GUI: every icon were resized
97 * GUI: every icon were resized
95 * jroproc_voltage.py: Print a message when "Read from code" option is selected and the code is not defined inside data file
98 * jroproc_voltage.py: Print a message when "Read from code" option is selected and the code is not defined inside data file
96
99
97 ### 2.1.3:
100 ### 2.1.3:
98 * jroplot_heispectra.py: SpectraHeisScope was not showing the right channels
101 * jroplot_heispectra.py: SpectraHeisScope was not showing the right channels
99 * jroproc_voltage.py: Bug fixed selecting profiles (self.nProfiles took a wrong value),
102 * jroproc_voltage.py: Bug fixed selecting profiles (self.nProfiles took a wrong value),
100 Bug fixed selecting heights by block (selecting profiles instead heights)
103 Bug fixed selecting heights by block (selecting profiles instead heights)
101 * jroproc_voltage.py: New feature added: decoding data by block using FFT.
104 * jroproc_voltage.py: New feature added: decoding data by block using FFT.
102 * jroIO_heispectra.py: Bug fixed in FitsReader. Using local Fits instance instead schainpy.mode.data.jrodata.Fits.
105 * jroIO_heispectra.py: Bug fixed in FitsReader. Using local Fits instance instead schainpy.mode.data.jrodata.Fits.
103 * jroIO_heispectra.py: Channel index list does not exist.
106 * jroIO_heispectra.py: Channel index list does not exist.
104
107
105 ### 2.1.2:
108 ### 2.1.2:
106 * jroutils_ftp.py: Bug fixed, Any error sending file stopped the Server Thread
109 * jroutils_ftp.py: Bug fixed, Any error sending file stopped the Server Thread
107 Server thread opens and closes remote server each time file list is sent
110 Server thread opens and closes remote server each time file list is sent
108 * jroplot_spectra.py: Noise path was not being created when noise data is saved.
111 * jroplot_spectra.py: Noise path was not being created when noise data is saved.
109 * jroIO_base.py: startTime can be greater than endTime. Example: SpreadF [18:00 * 07:00] No newline at end of file
112 * jroIO_base.py: startTime can be greater than endTime. Example: SpreadF [18:00 * 07:00]
@@ -1,955 +1,955
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', 'RdBu_r', 'seismic')]
25 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'RdBu_r', 'seismic')]
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
39
40 class PlotData(Operation, Process):
40 class PlotData(Operation, Process):
41 '''
41 '''
42 Base class for Schain plotting operations
42 Base class for Schain plotting operations
43 '''
43 '''
44
44
45 CODE = 'Figure'
45 CODE = 'Figure'
46 colormap = 'jro'
46 colormap = 'jro'
47 bgcolor = 'white'
47 bgcolor = 'white'
48 CONFLATE = False
48 CONFLATE = False
49 __MAXNUMX = 80
49 __MAXNUMX = 80
50 __missing = 1E30
50 __missing = 1E30
51
51
52 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
52 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
53 'zlimits', 'xlabel', 'ylabel', 'cb_label', 'title', 'titles', 'colorbar',
53 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title',
54 'bgcolor', 'width', 'height', 'localtime', 'oneFigure', 'showprofile']
54 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
55 'showprofile', 'decimation']
55
56
56 def __init__(self, **kwargs):
57 def __init__(self, **kwargs):
57
58
58 Operation.__init__(self, plot=True, **kwargs)
59 Operation.__init__(self, plot=True, **kwargs)
59 Process.__init__(self)
60 Process.__init__(self)
60 self.contador = 0
61
61 self.kwargs['code'] = self.CODE
62 self.kwargs['code'] = self.CODE
62 self.mp = False
63 self.mp = False
63 self.data = None
64 self.data = None
64 self.isConfig = False
65 self.isConfig = False
65 self.figures = []
66 self.figures = []
66 self.axes = []
67 self.axes = []
67 self.cb_axes = []
68 self.cb_axes = []
68 self.localtime = kwargs.pop('localtime', True)
69 self.localtime = kwargs.pop('localtime', True)
69 self.show = kwargs.get('show', True)
70 self.show = kwargs.get('show', True)
70 self.save = kwargs.get('save', False)
71 self.save = kwargs.get('save', False)
71 self.colormap = kwargs.get('colormap', self.colormap)
72 self.colormap = kwargs.get('colormap', self.colormap)
72 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
73 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
73 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
74 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
74 self.colormaps = kwargs.get('colormaps', None)
75 self.colormaps = kwargs.get('colormaps', None)
75 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
76 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
76 self.showprofile = kwargs.get('showprofile', False)
77 self.showprofile = kwargs.get('showprofile', False)
77 self.title = kwargs.get('wintitle', self.CODE.upper())
78 self.title = kwargs.get('wintitle', self.CODE.upper())
78 self.cb_label = kwargs.get('cb_label', None)
79 self.cb_label = kwargs.get('cb_label', None)
79 self.cb_labels = kwargs.get('cb_labels', None)
80 self.cb_labels = kwargs.get('cb_labels', None)
80 self.xaxis = kwargs.get('xaxis', 'frequency')
81 self.xaxis = kwargs.get('xaxis', 'frequency')
81 self.zmin = kwargs.get('zmin', None)
82 self.zmin = kwargs.get('zmin', None)
82 self.zmax = kwargs.get('zmax', None)
83 self.zmax = kwargs.get('zmax', None)
83 self.zlimits = kwargs.get('zlimits', None)
84 self.zlimits = kwargs.get('zlimits', None)
84 self.xmin = kwargs.get('xmin', None)
85 self.xmin = kwargs.get('xmin', None)
85 self.xmax = kwargs.get('xmax', None)
86 self.xmax = kwargs.get('xmax', None)
86 self.xrange = kwargs.get('xrange', 24)
87 self.xrange = kwargs.get('xrange', 24)
87 self.ymin = kwargs.get('ymin', None)
88 self.ymin = kwargs.get('ymin', None)
88 self.ymax = kwargs.get('ymax', None)
89 self.ymax = kwargs.get('ymax', None)
89 self.xlabel = kwargs.get('xlabel', None)
90 self.xlabel = kwargs.get('xlabel', None)
90 self.__MAXNUMY = kwargs.get('decimation', 300)
91 self.__MAXNUMY = kwargs.get('decimation', 200)
91 self.showSNR = kwargs.get('showSNR', False)
92 self.showSNR = kwargs.get('showSNR', False)
92 self.oneFigure = kwargs.get('oneFigure', True)
93 self.oneFigure = kwargs.get('oneFigure', True)
93 self.width = kwargs.get('width', None)
94 self.width = kwargs.get('width', None)
94 self.height = kwargs.get('height', None)
95 self.height = kwargs.get('height', None)
95 self.colorbar = kwargs.get('colorbar', True)
96 self.colorbar = kwargs.get('colorbar', True)
96 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
97 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
97 self.titles = ['' for __ in range(16)]
98 self.titles = kwargs.get('titles', [])
98 self.polar = False
99 self.polar = False
99
100
100 def __fmtTime(self, x, pos):
101 def __fmtTime(self, x, pos):
101 '''
102 '''
102 '''
103 '''
103
104
104 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
105 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
105
106
106 def __setup(self):
107 def __setup(self):
107 '''
108 '''
108 Common setup for all figures, here figures and axes are created
109 Common setup for all figures, here figures and axes are created
109 '''
110 '''
110
111
111 if self.CODE not in self.data:
112 if self.CODE not in self.data:
112 raise ValueError(log.error('Missing data for {}'.format(self.CODE),
113 raise ValueError(log.error('Missing data for {}'.format(self.CODE),
113 self.name))
114 self.name))
114
115
115 self.setup()
116 self.setup()
116
117
117 self.time_label = 'LT' if self.localtime else 'UTC'
118 self.time_label = 'LT' if self.localtime else 'UTC'
118 if self.data.localtime:
119 if self.data.localtime:
119 self.getDateTime = datetime.datetime.fromtimestamp
120 self.getDateTime = datetime.datetime.fromtimestamp
120 else:
121 else:
121 self.getDateTime = datetime.datetime.utcfromtimestamp
122 self.getDateTime = datetime.datetime.utcfromtimestamp
122
123
123 if self.width is None:
124 if self.width is None:
124 self.width = 8
125 self.width = 8
125
126
126 self.figures = []
127 self.figures = []
127 self.axes = []
128 self.axes = []
128 self.cb_axes = []
129 self.cb_axes = []
129 self.pf_axes = []
130 self.pf_axes = []
130 self.cmaps = []
131 self.cmaps = []
131
132
132 size = '15%' if self.ncols == 1 else '30%'
133 size = '15%' if self.ncols == 1 else '30%'
133 pad = '4%' if self.ncols == 1 else '8%'
134 pad = '4%' if self.ncols == 1 else '8%'
134
135
135 if self.oneFigure:
136 if self.oneFigure:
136 if self.height is None:
137 if self.height is None:
137 self.height = 1.4 * self.nrows + 1
138 self.height = 1.4 * self.nrows + 1
138 fig = plt.figure(figsize=(self.width, self.height),
139 fig = plt.figure(figsize=(self.width, self.height),
139 edgecolor='k',
140 edgecolor='k',
140 facecolor='w')
141 facecolor='w')
141 self.figures.append(fig)
142 self.figures.append(fig)
142 for n in range(self.nplots):
143 for n in range(self.nplots):
143 ax = fig.add_subplot(self.nrows, self.ncols,
144 ax = fig.add_subplot(self.nrows, self.ncols,
144 n + 1, polar=self.polar)
145 n + 1, polar=self.polar)
145 ax.tick_params(labelsize=8)
146 ax.tick_params(labelsize=8)
146 ax.firsttime = True
147 ax.firsttime = True
147 ax.index = 0
148 ax.index = 0
148 ax.press = None
149 ax.press = None
149 self.axes.append(ax)
150 self.axes.append(ax)
150 if self.showprofile:
151 if self.showprofile:
151 cax = self.__add_axes(ax, size=size, pad=pad)
152 cax = self.__add_axes(ax, size=size, pad=pad)
152 cax.tick_params(labelsize=8)
153 cax.tick_params(labelsize=8)
153 self.pf_axes.append(cax)
154 self.pf_axes.append(cax)
154 else:
155 else:
155 if self.height is None:
156 if self.height is None:
156 self.height = 3
157 self.height = 3
157 for n in range(self.nplots):
158 for n in range(self.nplots):
158 fig = plt.figure(figsize=(self.width, self.height),
159 fig = plt.figure(figsize=(self.width, self.height),
159 edgecolor='k',
160 edgecolor='k',
160 facecolor='w')
161 facecolor='w')
161 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
162 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
162 ax.tick_params(labelsize=8)
163 ax.tick_params(labelsize=8)
163 ax.firsttime = True
164 ax.firsttime = True
164 ax.index = 0
165 ax.index = 0
165 ax.press = None
166 ax.press = None
166 self.figures.append(fig)
167 self.figures.append(fig)
167 self.axes.append(ax)
168 self.axes.append(ax)
168 if self.showprofile:
169 if self.showprofile:
169 cax = self.__add_axes(ax, size=size, pad=pad)
170 cax = self.__add_axes(ax, size=size, pad=pad)
170 cax.tick_params(labelsize=8)
171 cax.tick_params(labelsize=8)
171 self.pf_axes.append(cax)
172 self.pf_axes.append(cax)
172
173
173 for n in range(self.nrows):
174 for n in range(self.nrows):
174 if self.colormaps is not None:
175 if self.colormaps is not None:
175 cmap = plt.get_cmap(self.colormaps[n])
176 cmap = plt.get_cmap(self.colormaps[n])
176 else:
177 else:
177 cmap = plt.get_cmap(self.colormap)
178 cmap = plt.get_cmap(self.colormap)
178 cmap.set_bad(self.bgcolor, 1.)
179 cmap.set_bad(self.bgcolor, 1.)
179 self.cmaps.append(cmap)
180 self.cmaps.append(cmap)
180
181
181 for fig in self.figures:
182 for fig in self.figures:
182 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
183 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
183 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
184 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
184 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
185 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
185 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
186 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
186 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
187 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
187 if self.show:
188 if self.show:
188 fig.show()
189 fig.show()
189
190
190 def OnKeyPress(self, event):
191 def OnKeyPress(self, event):
191 '''
192 '''
192 Event for pressing keys (up, down) change colormap
193 Event for pressing keys (up, down) change colormap
193 '''
194 '''
194 ax = event.inaxes
195 ax = event.inaxes
195 if ax in self.axes:
196 if ax in self.axes:
196 if event.key == 'down':
197 if event.key == 'down':
197 ax.index += 1
198 ax.index += 1
198 elif event.key == 'up':
199 elif event.key == 'up':
199 ax.index -= 1
200 ax.index -= 1
200 if ax.index < 0:
201 if ax.index < 0:
201 ax.index = len(CMAPS) - 1
202 ax.index = len(CMAPS) - 1
202 elif ax.index == len(CMAPS):
203 elif ax.index == len(CMAPS):
203 ax.index = 0
204 ax.index = 0
204 cmap = CMAPS[ax.index]
205 cmap = CMAPS[ax.index]
205 ax.cbar.set_cmap(cmap)
206 ax.cbar.set_cmap(cmap)
206 ax.cbar.draw_all()
207 ax.cbar.draw_all()
207 ax.plt.set_cmap(cmap)
208 ax.plt.set_cmap(cmap)
208 ax.cbar.patch.figure.canvas.draw()
209 ax.cbar.patch.figure.canvas.draw()
209 self.colormap = cmap.name
210 self.colormap = cmap.name
210
211
211 def OnBtnScroll(self, event):
212 def OnBtnScroll(self, event):
212 '''
213 '''
213 Event for scrolling, scale figure
214 Event for scrolling, scale figure
214 '''
215 '''
215 cb_ax = event.inaxes
216 cb_ax = event.inaxes
216 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
217 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]
218 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
218 pt = ax.cbar.ax.bbox.get_points()[:, 1]
219 pt = ax.cbar.ax.bbox.get_points()[:, 1]
219 nrm = ax.cbar.norm
220 nrm = ax.cbar.norm
220 vmin, vmax, p0, p1, pS = (
221 vmin, vmax, p0, p1, pS = (
221 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
222 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
222 scale = 2 if event.step == 1 else 0.5
223 scale = 2 if event.step == 1 else 0.5
223 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
224 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
224 ax.cbar.norm.vmin = point - scale * (point - vmin)
225 ax.cbar.norm.vmin = point - scale * (point - vmin)
225 ax.cbar.norm.vmax = point - scale * (point - vmax)
226 ax.cbar.norm.vmax = point - scale * (point - vmax)
226 ax.plt.set_norm(ax.cbar.norm)
227 ax.plt.set_norm(ax.cbar.norm)
227 ax.cbar.draw_all()
228 ax.cbar.draw_all()
228 ax.cbar.patch.figure.canvas.draw()
229 ax.cbar.patch.figure.canvas.draw()
229
230
230 def onBtnPress(self, event):
231 def onBtnPress(self, event):
231 '''
232 '''
232 Event for mouse button press
233 Event for mouse button press
233 '''
234 '''
234 cb_ax = event.inaxes
235 cb_ax = event.inaxes
235 if cb_ax is None:
236 if cb_ax is None:
236 return
237 return
237
238
238 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
239 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
239 cb_ax.press = event.x, event.y
240 cb_ax.press = event.x, event.y
240 else:
241 else:
241 cb_ax.press = None
242 cb_ax.press = None
242
243
243 def onMotion(self, event):
244 def onMotion(self, event):
244 '''
245 '''
245 Event for move inside colorbar
246 Event for move inside colorbar
246 '''
247 '''
247 cb_ax = event.inaxes
248 cb_ax = event.inaxes
248 if cb_ax is None:
249 if cb_ax is None:
249 return
250 return
250 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
251 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
251 return
252 return
252 if cb_ax.press is None:
253 if cb_ax.press is None:
253 return
254 return
254
255
255 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
256 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
256 xprev, yprev = cb_ax.press
257 xprev, yprev = cb_ax.press
257 dx = event.x - xprev
258 dx = event.x - xprev
258 dy = event.y - yprev
259 dy = event.y - yprev
259 cb_ax.press = event.x, event.y
260 cb_ax.press = event.x, event.y
260 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
261 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
261 perc = 0.03
262 perc = 0.03
262
263
263 if event.button == 1:
264 if event.button == 1:
264 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
265 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
265 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
266 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
266 elif event.button == 3:
267 elif event.button == 3:
267 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
268 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
268 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
269 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
269
270
270 ax.cbar.draw_all()
271 ax.cbar.draw_all()
271 ax.plt.set_norm(ax.cbar.norm)
272 ax.plt.set_norm(ax.cbar.norm)
272 ax.cbar.patch.figure.canvas.draw()
273 ax.cbar.patch.figure.canvas.draw()
273
274
274 def onBtnRelease(self, event):
275 def onBtnRelease(self, event):
275 '''
276 '''
276 Event for mouse button release
277 Event for mouse button release
277 '''
278 '''
278 cb_ax = event.inaxes
279 cb_ax = event.inaxes
279 if cb_ax is not None:
280 if cb_ax is not None:
280 cb_ax.press = None
281 cb_ax.press = None
281
282
282 def __add_axes(self, ax, size='30%', pad='8%'):
283 def __add_axes(self, ax, size='30%', pad='8%'):
283 '''
284 '''
284 Add new axes to the given figure
285 Add new axes to the given figure
285 '''
286 '''
286 divider = make_axes_locatable(ax)
287 divider = make_axes_locatable(ax)
287 nax = divider.new_horizontal(size=size, pad=pad)
288 nax = divider.new_horizontal(size=size, pad=pad)
288 ax.figure.add_axes(nax)
289 ax.figure.add_axes(nax)
289 return nax
290 return nax
290
291
291 self.setup()
292 self.setup()
292
293
293 def setup(self):
294 def setup(self):
294 '''
295 '''
295 This method should be implemented in the child class, the following
296 This method should be implemented in the child class, the following
296 attributes should be set:
297 attributes should be set:
297
298
298 self.nrows: number of rows
299 self.nrows: number of rows
299 self.ncols: number of cols
300 self.ncols: number of cols
300 self.nplots: number of plots (channels or pairs)
301 self.nplots: number of plots (channels or pairs)
301 self.ylabel: label for Y axes
302 self.ylabel: label for Y axes
302 self.titles: list of axes title
303 self.titles: list of axes title
303
304
304 '''
305 '''
305 raise(NotImplementedError, 'Implement this method in child class')
306 raise(NotImplementedError, 'Implement this method in child class')
306
307
307 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
308 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
308 '''
309 '''
309 Create a masked array for missing data
310 Create a masked array for missing data
310 '''
311 '''
311 if x_buffer.shape[0] < 2:
312 if x_buffer.shape[0] < 2:
312 return x_buffer, y_buffer, z_buffer
313 return x_buffer, y_buffer, z_buffer
313
314
314 deltas = x_buffer[1:] - x_buffer[0:-1]
315 deltas = x_buffer[1:] - x_buffer[0:-1]
315 x_median = numpy.median(deltas)
316 x_median = numpy.median(deltas)
316
317
317 index = numpy.where(deltas > 5 * x_median)
318 index = numpy.where(deltas > 5 * x_median)
318
319
319 if len(index[0]) != 0:
320 if len(index[0]) != 0:
320 z_buffer[::, index[0], ::] = self.__missing
321 z_buffer[::, index[0], ::] = self.__missing
321 z_buffer = numpy.ma.masked_inside(z_buffer,
322 z_buffer = numpy.ma.masked_inside(z_buffer,
322 0.99 * self.__missing,
323 0.99 * self.__missing,
323 1.01 * self.__missing)
324 1.01 * self.__missing)
324
325
325 return x_buffer, y_buffer, z_buffer
326 return x_buffer, y_buffer, z_buffer
326
327
327 def decimate(self):
328 def decimate(self):
328
329
329 # dx = int(len(self.x)/self.__MAXNUMX) + 1
330 # dx = int(len(self.x)/self.__MAXNUMX) + 1
330 dy = int(len(self.y) / self.__MAXNUMY) + 1
331 dy = int(len(self.y) / self.__MAXNUMY) + 1
331
332
332 # x = self.x[::dx]
333 # x = self.x[::dx]
333 x = self.x
334 x = self.x
334 y = self.y[::dy]
335 y = self.y[::dy]
335 z = self.z[::, ::, ::dy]
336 z = self.z[::, ::, ::dy]
336
337
337 return x, y, z
338 return x, y, z
338
339
339 def format(self):
340 def format(self):
340 '''
341 '''
341 Set min and max values, labels, ticks and titles
342 Set min and max values, labels, ticks and titles
342 '''
343 '''
343
344
344 if self.xmin is None:
345 if self.xmin is None:
345 xmin = self.min_time
346 xmin = self.min_time
346 else:
347 else:
347 if self.xaxis is 'time':
348 if self.xaxis is 'time':
348 dt = self.getDateTime(self.min_time)
349 dt = self.getDateTime(self.min_time)
349 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
350 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
350 datetime.datetime(1970, 1, 1)).total_seconds()
351 datetime.datetime(1970, 1, 1)).total_seconds()
351 if self.data.localtime:
352 if self.data.localtime:
352 xmin += time.timezone
353 xmin += time.timezone
353 else:
354 else:
354 xmin = self.xmin
355 xmin = self.xmin
355
356
356 if self.xmax is None:
357 if self.xmax is None:
357 xmax = xmin + self.xrange * 60 * 60
358 xmax = xmin + self.xrange * 60 * 60
358 else:
359 else:
359 if self.xaxis is 'time':
360 if self.xaxis is 'time':
360 dt = self.getDateTime(self.max_time)
361 dt = self.getDateTime(self.max_time)
361 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
362 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
362 datetime.datetime(1970, 1, 1)).total_seconds()
363 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
363 if self.data.localtime:
364 if self.data.localtime:
364 xmax += time.timezone
365 xmax += time.timezone
365 else:
366 else:
366 xmax = self.xmax
367 xmax = self.xmax
367
368
368 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
369 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
369 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
370 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
370
371
371 Y = numpy.array([10, 20, 50, 100, 200, 500, 1000, 2000])
372 Y = numpy.array([10, 20, 50, 100, 200, 500, 1000, 2000])
372 i = 1 if numpy.where(ymax < Y)[
373 i = 1 if numpy.where(ymax-ymin < Y)[0][0] < 0 else numpy.where(ymax-ymin < Y)[0][0]
373 0][0] < 0 else numpy.where(ymax < Y)[0][0]
374 ystep = Y[i] / 5
374 ystep = Y[i - 1] / 5
375
375
376 for n, ax in enumerate(self.axes):
376 for n, ax in enumerate(self.axes):
377 if ax.firsttime:
377 if ax.firsttime:
378 ax.set_facecolor(self.bgcolor)
378 ax.set_facecolor(self.bgcolor)
379 ax.yaxis.set_major_locator(MultipleLocator(ystep))
379 ax.yaxis.set_major_locator(MultipleLocator(ystep))
380 if self.xaxis is 'time':
380 if self.xaxis is 'time':
381 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
381 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
382 ax.xaxis.set_major_locator(LinearLocator(9))
382 ax.xaxis.set_major_locator(LinearLocator(9))
383 if self.xlabel is not None:
383 if self.xlabel is not None:
384 ax.set_xlabel(self.xlabel)
384 ax.set_xlabel(self.xlabel)
385 ax.set_ylabel(self.ylabel)
385 ax.set_ylabel(self.ylabel)
386 ax.firsttime = False
386 ax.firsttime = False
387 if self.showprofile:
387 if self.showprofile:
388 self.pf_axes[n].set_ylim(ymin, ymax)
388 self.pf_axes[n].set_ylim(ymin, ymax)
389 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
389 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
390 self.pf_axes[n].set_xlabel('dB')
390 self.pf_axes[n].set_xlabel('dB')
391 self.pf_axes[n].grid(b=True, axis='x')
391 self.pf_axes[n].grid(b=True, axis='x')
392 [tick.set_visible(False)
392 [tick.set_visible(False)
393 for tick in self.pf_axes[n].get_yticklabels()]
393 for tick in self.pf_axes[n].get_yticklabels()]
394 if self.colorbar:
394 if self.colorbar:
395 ax.cbar = plt.colorbar(
395 ax.cbar = plt.colorbar(
396 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
396 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
397 ax.cbar.ax.tick_params(labelsize=8)
397 ax.cbar.ax.tick_params(labelsize=8)
398 ax.cbar.ax.press = None
398 ax.cbar.ax.press = None
399 if self.cb_label:
399 if self.cb_label:
400 ax.cbar.set_label(self.cb_label, size=8)
400 ax.cbar.set_label(self.cb_label, size=8)
401 elif self.cb_labels:
401 elif self.cb_labels:
402 ax.cbar.set_label(self.cb_labels[n], size=8)
402 ax.cbar.set_label(self.cb_labels[n], size=8)
403 else:
403 else:
404 ax.cbar = None
404 ax.cbar = None
405
405
406 if not self.polar:
406 if not self.polar:
407 ax.set_xlim(xmin, xmax)
407 ax.set_xlim(xmin, xmax)
408 ax.set_ylim(ymin, ymax)
408 ax.set_ylim(ymin, ymax)
409 ax.set_title('{} - {} {}'.format(
409 ax.set_title('{} - {} {}'.format(
410 self.titles[n],
410 self.titles[n],
411 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
411 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
412 self.time_label),
412 self.time_label),
413 size=8)
413 size=8)
414 else:
414 else:
415 ax.set_title('{}'.format(self.titles[n]), size=8)
415 ax.set_title('{}'.format(self.titles[n]), size=8)
416 ax.set_ylim(0, 90)
416 ax.set_ylim(0, 90)
417 ax.set_yticks(numpy.arange(0, 90, 20))
417 ax.set_yticks(numpy.arange(0, 90, 20))
418 ax.yaxis.labelpad = 40
418 ax.yaxis.labelpad = 40
419
419
420 def __plot(self):
420 def __plot(self):
421 '''
421 '''
422 '''
422 '''
423 log.success('Plotting', self.name)
423 log.success('Plotting', self.name)
424
424
425 self.plot()
425 self.plot()
426 self.format()
426 self.format()
427
427
428 for n, fig in enumerate(self.figures):
428 for n, fig in enumerate(self.figures):
429 if self.nrows == 0 or self.nplots == 0:
429 if self.nrows == 0 or self.nplots == 0:
430 log.warning('No data', self.name)
430 log.warning('No data', self.name)
431 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
431 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
432 fig.canvas.manager.set_window_title(self.CODE)
432 continue
433 continue
433
434
434 fig.tight_layout()
435 fig.tight_layout()
435 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
436 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
436 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
437 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
437 # fig.canvas.draw()
438 fig.canvas.draw()
438
439
439 if self.save: # and self.data.ended:
440 if self.save and self.data.ended:
440 self.contador += 1
441 channels = range(self.nrows)
441 channels = range(self.nrows)
442 if self.oneFigure:
442 if self.oneFigure:
443 label = ''
443 label = ''
444 else:
444 else:
445 label = '_{}'.format(channels[n])
445 label = '_{}'.format(channels[n])
446 figname = os.path.join(
446 figname = os.path.join(
447 self.save,
447 self.save,
448 '{}{}_{}{}.png'.format(
448 '{}{}_{}.png'.format(
449 self.CODE,
449 self.CODE,
450 label,
450 label,
451 self.getDateTime(self.saveTime).strftime(
451 self.getDateTime(self.saveTime).strftime(
452 '%y%m%d_%H%M%S'),
452 '%y%m%d_%H%M%S'),
453 str(self.contador),
454 )
453 )
455 )
454 )
456 log.log('Saving figure: {}'.format(figname), self.name)
455 log.log('Saving figure: {}'.format(figname), self.name)
457 fig.savefig(figname)
456 fig.savefig(figname)
458
457
459 def plot(self):
458 def plot(self):
460 '''
459 '''
461 '''
460 '''
462 raise(NotImplementedError, 'Implement this method in child class')
461 raise(NotImplementedError, 'Implement this method in child class')
463
462
464 def run(self):
463 def run(self):
465
464
466 log.success('Starting', self.name)
465 log.success('Starting', self.name)
467
466
468 context = zmq.Context()
467 context = zmq.Context()
469 receiver = context.socket(zmq.SUB)
468 receiver = context.socket(zmq.SUB)
470 receiver.setsockopt(zmq.SUBSCRIBE, '')
469 receiver.setsockopt(zmq.SUBSCRIBE, '')
471 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
470 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
472
471
473 if 'server' in self.kwargs['parent']:
472 if 'server' in self.kwargs['parent']:
474 receiver.connect(
473 receiver.connect(
475 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
474 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
476 else:
475 else:
477 receiver.connect("ipc:///tmp/zmq.plots")
476 receiver.connect("ipc:///tmp/zmq.plots")
478
477
479 while True:
478 while True:
480 try:
479 try:
481 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
480 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
482 if self.data.localtime and self.localtime:
481 if self.data.localtime and self.localtime:
483 self.times = self.data.times
482 self.times = self.data.times
484 elif self.data.localtime and not self.localtime:
483 elif self.data.localtime and not self.localtime:
485 self.times = self.data.times + time.timezone
484 self.times = self.data.times + time.timezone
486 elif not self.data.localtime and self.localtime:
485 elif not self.data.localtime and self.localtime:
487 self.times = self.data.times - time.timezone
486 self.times = self.data.times - time.timezone
488 else:
487 else:
489 self.times = self.data.times
488 self.times = self.data.times
490
489
491 self.min_time = self.times[0]
490 self.min_time = self.times[0]
492 self.max_time = self.times[-1]
491 self.max_time = self.times[-1]
493
492
494 if self.isConfig is False:
493 if self.isConfig is False:
495 self.__setup()
494 self.__setup()
496 self.isConfig = True
495 self.isConfig = True
497
496
498 self.__plot()
497 self.__plot()
499
498
500 except zmq.Again as e:
499 except zmq.Again as e:
501 log.log('Waiting for data...')
500 log.log('Waiting for data...')
502 if self.data:
501 if self.data:
503 figpause(self.data.throttle)
502 figpause(self.data.throttle)
504 else:
503 else:
505 time.sleep(2)
504 time.sleep(2)
506
505
507 def close(self):
506 def close(self):
508 if self.data:
507 if self.data:
509 self.__plot()
508 self.__plot()
510
509
511
510
512 class PlotSpectraData(PlotData):
511 class PlotSpectraData(PlotData):
513 '''
512 '''
514 Plot for Spectra data
513 Plot for Spectra data
515 '''
514 '''
516
515
517 CODE = 'spc'
516 CODE = 'spc'
518 colormap = 'jro'
517 colormap = 'jro'
519
518
520 def setup(self):
519 def setup(self):
521 self.nplots = len(self.data.channels)
520 self.nplots = len(self.data.channels)
522 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
521 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
523 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
522 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
524 self.width = 3.4 * self.ncols
523 self.width = 3.4 * self.ncols
525 self.height = 3 * self.nrows
524 self.height = 3 * self.nrows
526 self.cb_label = 'dB'
525 self.cb_label = 'dB'
527 if self.showprofile:
526 if self.showprofile:
528 self.width += 0.8 * self.ncols
527 self.width += 0.8 * self.ncols
529
528
530 self.ylabel = 'Range [Km]'
529 self.ylabel = 'Range [Km]'
531
530
532 def plot(self):
531 def plot(self):
533 if self.xaxis == "frequency":
532 if self.xaxis == "frequency":
534 x = self.data.xrange[0]
533 x = self.data.xrange[0]
535 self.xlabel = "Frequency (kHz)"
534 self.xlabel = "Frequency (kHz)"
536 elif self.xaxis == "time":
535 elif self.xaxis == "time":
537 x = self.data.xrange[1]
536 x = self.data.xrange[1]
538 self.xlabel = "Time (ms)"
537 self.xlabel = "Time (ms)"
539 else:
538 else:
540 x = self.data.xrange[2]
539 x = self.data.xrange[2]
541 self.xlabel = "Velocity (m/s)"
540 self.xlabel = "Velocity (m/s)"
542
541
543 if self.CODE == 'spc_mean':
542 if self.CODE == 'spc_mean':
544 x = self.data.xrange[2]
543 x = self.data.xrange[2]
545 self.xlabel = "Velocity (m/s)"
544 self.xlabel = "Velocity (m/s)"
546
545
547 self.titles = []
546 self.titles = []
548
547
549 y = self.data.heights
548 y = self.data.heights
550 self.y = y
549 self.y = y
551 z = self.data['spc']
550 z = self.data['spc']
552
551
553 for n, ax in enumerate(self.axes):
552 for n, ax in enumerate(self.axes):
554 noise = self.data['noise'][n][-1]
553 noise = self.data['noise'][n][-1]
555 if self.CODE == 'spc_mean':
554 if self.CODE == 'spc_mean':
556 mean = self.data['mean'][n][-1]
555 mean = self.data['mean'][n][-1]
557 if ax.firsttime:
556 if ax.firsttime:
558 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
557 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
559 self.xmin = self.xmin if self.xmin else -self.xmax
558 self.xmin = self.xmin if self.xmin else -self.xmax
560 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
559 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
561 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
560 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
562 ax.plt = ax.pcolormesh(x, y, z[n].T,
561 ax.plt = ax.pcolormesh(x, y, z[n].T,
563 vmin=self.zmin,
562 vmin=self.zmin,
564 vmax=self.zmax,
563 vmax=self.zmax,
565 cmap=plt.get_cmap(self.colormap)
564 cmap=plt.get_cmap(self.colormap)
566 )
565 )
567
566
568 if self.showprofile:
567 if self.showprofile:
569 ax.plt_profile = self.pf_axes[n].plot(
568 ax.plt_profile = self.pf_axes[n].plot(
570 self.data['rti'][n][-1], y)[0]
569 self.data['rti'][n][-1], y)[0]
571 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
570 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
572 color="k", linestyle="dashed", lw=1)[0]
571 color="k", linestyle="dashed", lw=1)[0]
573 if self.CODE == 'spc_mean':
572 if self.CODE == 'spc_mean':
574 ax.plt_mean = ax.plot(mean, y, color='k')[0]
573 ax.plt_mean = ax.plot(mean, y, color='k')[0]
575 else:
574 else:
576 ax.plt.set_array(z[n].T.ravel())
575 ax.plt.set_array(z[n].T.ravel())
577 if self.showprofile:
576 if self.showprofile:
578 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
577 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
579 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
578 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
580 if self.CODE == 'spc_mean':
579 if self.CODE == 'spc_mean':
581 ax.plt_mean.set_data(mean, y)
580 ax.plt_mean.set_data(mean, y)
582
581
583 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
582 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
584 self.saveTime = self.max_time
583 self.saveTime = self.max_time
585
584
586
585
587 class PlotCrossSpectraData(PlotData):
586 class PlotCrossSpectraData(PlotData):
588
587
589 CODE = 'cspc'
588 CODE = 'cspc'
590 zmin_coh = None
589 zmin_coh = None
591 zmax_coh = None
590 zmax_coh = None
592 zmin_phase = None
591 zmin_phase = None
593 zmax_phase = None
592 zmax_phase = None
594
593
595 def setup(self):
594 def setup(self):
596
595
597 self.ncols = 4
596 self.ncols = 4
598 self.nrows = len(self.data.pairs)
597 self.nrows = len(self.data.pairs)
599 self.nplots = self.nrows * 4
598 self.nplots = self.nrows * 4
600 self.width = 3.4 * self.ncols
599 self.width = 3.4 * self.ncols
601 self.height = 3 * self.nrows
600 self.height = 3 * self.nrows
602 self.ylabel = 'Range [Km]'
601 self.ylabel = 'Range [Km]'
603 self.showprofile = False
602 self.showprofile = False
604
603
605 def plot(self):
604 def plot(self):
606
605
607 if self.xaxis == "frequency":
606 if self.xaxis == "frequency":
608 x = self.data.xrange[0]
607 x = self.data.xrange[0]
609 self.xlabel = "Frequency (kHz)"
608 self.xlabel = "Frequency (kHz)"
610 elif self.xaxis == "time":
609 elif self.xaxis == "time":
611 x = self.data.xrange[1]
610 x = self.data.xrange[1]
612 self.xlabel = "Time (ms)"
611 self.xlabel = "Time (ms)"
613 else:
612 else:
614 x = self.data.xrange[2]
613 x = self.data.xrange[2]
615 self.xlabel = "Velocity (m/s)"
614 self.xlabel = "Velocity (m/s)"
616
615
617 self.titles = []
616 self.titles = []
618
617
619 y = self.data.heights
618 y = self.data.heights
620 self.y = y
619 self.y = y
621 spc = self.data['spc']
620 spc = self.data['spc']
622 cspc = self.data['cspc']
621 cspc = self.data['cspc']
623
622
624 for n in range(self.nrows):
623 for n in range(self.nrows):
625 noise = self.data['noise'][n][-1]
624 noise = self.data['noise'][n][-1]
626 pair = self.data.pairs[n]
625 pair = self.data.pairs[n]
627 ax = self.axes[4 * n]
626 ax = self.axes[4 * n]
628 ax3 = self.axes[4 * n + 3]
627 ax3 = self.axes[4 * n + 3]
629 if ax.firsttime:
628 if ax.firsttime:
630 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
629 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
631 self.xmin = self.xmin if self.xmin else -self.xmax
630 self.xmin = self.xmin if self.xmin else -self.xmax
632 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
631 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
633 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
632 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
634 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
633 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
635 vmin=self.zmin,
634 vmin=self.zmin,
636 vmax=self.zmax,
635 vmax=self.zmax,
637 cmap=plt.get_cmap(self.colormap)
636 cmap=plt.get_cmap(self.colormap)
638 )
637 )
639 else:
638 else:
640 ax.plt.set_array(spc[pair[0]].T.ravel())
639 ax.plt.set_array(spc[pair[0]].T.ravel())
641 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
640 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
642
641
643 ax = self.axes[4 * n + 1]
642 ax = self.axes[4 * n + 1]
644 if ax.firsttime:
643 if ax.firsttime:
645 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
644 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
646 vmin=self.zmin,
645 vmin=self.zmin,
647 vmax=self.zmax,
646 vmax=self.zmax,
648 cmap=plt.get_cmap(self.colormap)
647 cmap=plt.get_cmap(self.colormap)
649 )
648 )
650 else:
649 else:
651 ax.plt.set_array(spc[pair[1]].T.ravel())
650 ax.plt.set_array(spc[pair[1]].T.ravel())
652 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
651 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
653
652
654 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
653 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
655 coh = numpy.abs(out)
654 coh = numpy.abs(out)
656 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
655 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
657
656
658 ax = self.axes[4 * n + 2]
657 ax = self.axes[4 * n + 2]
659 if ax.firsttime:
658 if ax.firsttime:
660 ax.plt = ax.pcolormesh(x, y, coh.T,
659 ax.plt = ax.pcolormesh(x, y, coh.T,
661 vmin=0,
660 vmin=0,
662 vmax=1,
661 vmax=1,
663 cmap=plt.get_cmap(self.colormap_coh)
662 cmap=plt.get_cmap(self.colormap_coh)
664 )
663 )
665 else:
664 else:
666 ax.plt.set_array(coh.T.ravel())
665 ax.plt.set_array(coh.T.ravel())
667 self.titles.append(
666 self.titles.append(
668 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
667 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
669
668
670 ax = self.axes[4 * n + 3]
669 ax = self.axes[4 * n + 3]
671 if ax.firsttime:
670 if ax.firsttime:
672 ax.plt = ax.pcolormesh(x, y, phase.T,
671 ax.plt = ax.pcolormesh(x, y, phase.T,
673 vmin=-180,
672 vmin=-180,
674 vmax=180,
673 vmax=180,
675 cmap=plt.get_cmap(self.colormap_phase)
674 cmap=plt.get_cmap(self.colormap_phase)
676 )
675 )
677 else:
676 else:
678 ax.plt.set_array(phase.T.ravel())
677 ax.plt.set_array(phase.T.ravel())
679 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
678 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
680
679
681 self.saveTime = self.max_time
680 self.saveTime = self.max_time
682
681
683
682
684 class PlotSpectraMeanData(PlotSpectraData):
683 class PlotSpectraMeanData(PlotSpectraData):
685 '''
684 '''
686 Plot for Spectra and Mean
685 Plot for Spectra and Mean
687 '''
686 '''
688 CODE = 'spc_mean'
687 CODE = 'spc_mean'
689 colormap = 'jro'
688 colormap = 'jro'
690
689
691
690
692 class PlotRTIData(PlotData):
691 class PlotRTIData(PlotData):
693 '''
692 '''
694 Plot for RTI data
693 Plot for RTI data
695 '''
694 '''
696
695
697 CODE = 'rti'
696 CODE = 'rti'
698 colormap = 'jro'
697 colormap = 'jro'
699
698
700 def setup(self):
699 def setup(self):
701 self.xaxis = 'time'
700 self.xaxis = 'time'
702 self.ncols = 1
701 self.ncols = 1
703 self.nrows = len(self.data.channels)
702 self.nrows = len(self.data.channels)
704 self.nplots = len(self.data.channels)
703 self.nplots = len(self.data.channels)
705 self.ylabel = 'Range [Km]'
704 self.ylabel = 'Range [Km]'
706 self.cb_label = 'dB'
705 self.cb_label = 'dB'
707 self.titles = ['{} Channel {}'.format(
706 self.titles = ['{} Channel {}'.format(
708 self.CODE.upper(), x) for x in range(self.nrows)]
707 self.CODE.upper(), x) for x in range(self.nrows)]
709
708
710 def plot(self):
709 def plot(self):
711 self.x = self.times
710 self.x = self.times
712 self.y = self.data.heights
711 self.y = self.data.heights
713 self.z = self.data[self.CODE]
712 self.z = self.data[self.CODE]
714 self.z = numpy.ma.masked_invalid(self.z)
713 self.z = numpy.ma.masked_invalid(self.z)
715
714
716 for n, ax in enumerate(self.axes):
715 for n, ax in enumerate(self.axes):
717 x, y, z = self.fill_gaps(*self.decimate())
716 x, y, z = self.fill_gaps(*self.decimate())
718 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
717 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
719 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
718 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
720 if ax.firsttime:
719 if ax.firsttime:
721 ax.plt = ax.pcolormesh(x, y, z[n].T,
720 ax.plt = ax.pcolormesh(x, y, z[n].T,
722 vmin=self.zmin,
721 vmin=self.zmin,
723 vmax=self.zmax,
722 vmax=self.zmax,
724 cmap=plt.get_cmap(self.colormap)
723 cmap=plt.get_cmap(self.colormap)
725 )
724 )
726 if self.showprofile:
725 if self.showprofile:
727 ax.plot_profile = self.pf_axes[n].plot(
726 ax.plot_profile = self.pf_axes[n].plot(
728 self.data['rti'][n][-1], self.y)[0]
727 self.data['rti'][n][-1], self.y)[0]
729 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
728 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
730 color="k", linestyle="dashed", lw=1)[0]
729 color="k", linestyle="dashed", lw=1)[0]
731 else:
730 else:
732 ax.collections.remove(ax.collections[0])
731 ax.collections.remove(ax.collections[0])
733 ax.plt = ax.pcolormesh(x, y, z[n].T,
732 ax.plt = ax.pcolormesh(x, y, z[n].T,
734 vmin=self.zmin,
733 vmin=self.zmin,
735 vmax=self.zmax,
734 vmax=self.zmax,
736 cmap=plt.get_cmap(self.colormap)
735 cmap=plt.get_cmap(self.colormap)
737 )
736 )
738 if self.showprofile:
737 if self.showprofile:
739 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
738 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
740 ax.plot_noise.set_data(numpy.repeat(
739 ax.plot_noise.set_data(numpy.repeat(
741 self.data['noise'][n][-1], len(self.y)), self.y)
740 self.data['noise'][n][-1], len(self.y)), self.y)
742
741
743 self.saveTime = self.min_time
742 self.saveTime = self.min_time
744
743
745
744
746 class PlotCOHData(PlotRTIData):
745 class PlotCOHData(PlotRTIData):
747 '''
746 '''
748 Plot for Coherence data
747 Plot for Coherence data
749 '''
748 '''
750
749
751 CODE = 'coh'
750 CODE = 'coh'
752
751
753 def setup(self):
752 def setup(self):
754 self.xaxis = 'time'
753 self.xaxis = 'time'
755 self.ncols = 1
754 self.ncols = 1
756 self.nrows = len(self.data.pairs)
755 self.nrows = len(self.data.pairs)
757 self.nplots = len(self.data.pairs)
756 self.nplots = len(self.data.pairs)
758 self.ylabel = 'Range [Km]'
757 self.ylabel = 'Range [Km]'
759 if self.CODE == 'coh':
758 if self.CODE == 'coh':
760 self.cb_label = ''
759 self.cb_label = ''
761 self.titles = [
760 self.titles = [
762 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
761 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
763 else:
762 else:
764 self.cb_label = 'Degrees'
763 self.cb_label = 'Degrees'
765 self.titles = [
764 self.titles = [
766 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
765 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
767
766
768
767
769 class PlotPHASEData(PlotCOHData):
768 class PlotPHASEData(PlotCOHData):
770 '''
769 '''
771 Plot for Phase map data
770 Plot for Phase map data
772 '''
771 '''
773
772
774 CODE = 'phase'
773 CODE = 'phase'
775 colormap = 'seismic'
774 colormap = 'seismic'
776
775
777
776
778 class PlotNoiseData(PlotData):
777 class PlotNoiseData(PlotData):
779 '''
778 '''
780 Plot for noise
779 Plot for noise
781 '''
780 '''
782
781
783 CODE = 'noise'
782 CODE = 'noise'
784
783
785 def setup(self):
784 def setup(self):
786 self.xaxis = 'time'
785 self.xaxis = 'time'
787 self.ncols = 1
786 self.ncols = 1
788 self.nrows = 1
787 self.nrows = 1
789 self.nplots = 1
788 self.nplots = 1
790 self.ylabel = 'Intensity [dB]'
789 self.ylabel = 'Intensity [dB]'
791 self.titles = ['Noise']
790 self.titles = ['Noise']
792 self.colorbar = False
791 self.colorbar = False
793
792
794 def plot(self):
793 def plot(self):
795
794
796 x = self.times
795 x = self.times
797 xmin = self.min_time
796 xmin = self.min_time
798 xmax = xmin + self.xrange * 60 * 60
797 xmax = xmin + self.xrange * 60 * 60
799 Y = self.data[self.CODE]
798 Y = self.data[self.CODE]
800
799
801 if self.axes[0].firsttime:
800 if self.axes[0].firsttime:
802 for ch in self.data.channels:
801 for ch in self.data.channels:
803 y = Y[ch]
802 y = Y[ch]
804 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
803 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
805 plt.legend()
804 plt.legend()
806 else:
805 else:
807 for ch in self.data.channels:
806 for ch in self.data.channels:
808 y = Y[ch]
807 y = Y[ch]
809 self.axes[0].lines[ch].set_data(x, y)
808 self.axes[0].lines[ch].set_data(x, y)
810
809
811 self.ymin = numpy.nanmin(Y) - 5
810 self.ymin = numpy.nanmin(Y) - 5
812 self.ymax = numpy.nanmax(Y) + 5
811 self.ymax = numpy.nanmax(Y) + 5
813 self.saveTime = self.min_time
812 self.saveTime = self.min_time
814
813
815
814
816 class PlotSNRData(PlotRTIData):
815 class PlotSNRData(PlotRTIData):
817 '''
816 '''
818 Plot for SNR Data
817 Plot for SNR Data
819 '''
818 '''
820
819
821 CODE = 'snr'
820 CODE = 'snr'
822 colormap = 'jet'
821 colormap = 'jet'
823
822
824
823
825 class PlotDOPData(PlotRTIData):
824 class PlotDOPData(PlotRTIData):
826 '''
825 '''
827 Plot for DOPPLER Data
826 Plot for DOPPLER Data
828 '''
827 '''
829
828
830 CODE = 'dop'
829 CODE = 'dop'
831 colormap = 'jet'
830 colormap = 'jet'
832
831
833
832
834 class PlotSkyMapData(PlotData):
833 class PlotSkyMapData(PlotData):
835 '''
834 '''
836 Plot for meteors detection data
835 Plot for meteors detection data
837 '''
836 '''
838
837
839 CODE = 'param'
838 CODE = 'param'
840
839
841 def setup(self):
840 def setup(self):
842
841
843 self.ncols = 1
842 self.ncols = 1
844 self.nrows = 1
843 self.nrows = 1
845 self.width = 7.2
844 self.width = 7.2
846 self.height = 7.2
845 self.height = 7.2
847 self.nplots = 1
846 self.nplots = 1
848 self.xlabel = 'Zonal Zenith Angle (deg)'
847 self.xlabel = 'Zonal Zenith Angle (deg)'
849 self.ylabel = 'Meridional Zenith Angle (deg)'
848 self.ylabel = 'Meridional Zenith Angle (deg)'
850 self.polar = True
849 self.polar = True
851 self.ymin = -180
850 self.ymin = -180
852 self.ymax = 180
851 self.ymax = 180
853 self.colorbar = False
852 self.colorbar = False
854
853
855 def plot(self):
854 def plot(self):
856
855
857 arrayParameters = numpy.concatenate(self.data['param'])
856 arrayParameters = numpy.concatenate(self.data['param'])
858 error = arrayParameters[:, -1]
857 error = arrayParameters[:, -1]
859 indValid = numpy.where(error == 0)[0]
858 indValid = numpy.where(error == 0)[0]
860 finalMeteor = arrayParameters[indValid, :]
859 finalMeteor = arrayParameters[indValid, :]
861 finalAzimuth = finalMeteor[:, 3]
860 finalAzimuth = finalMeteor[:, 3]
862 finalZenith = finalMeteor[:, 4]
861 finalZenith = finalMeteor[:, 4]
863
862
864 x = finalAzimuth * numpy.pi / 180
863 x = finalAzimuth * numpy.pi / 180
865 y = finalZenith
864 y = finalZenith
866
865
867 ax = self.axes[0]
866 ax = self.axes[0]
868
867
869 if ax.firsttime:
868 if ax.firsttime:
870 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
869 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
871 else:
870 else:
872 ax.plot.set_data(x, y)
871 ax.plot.set_data(x, y)
873
872
874 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
873 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
875 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
874 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
876 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
875 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
877 dt2,
876 dt2,
878 len(x))
877 len(x))
879 self.titles[0] = title
878 self.titles[0] = title
880 self.saveTime = self.max_time
879 self.saveTime = self.max_time
881
880
882
881
883 class PlotParamData(PlotRTIData):
882 class PlotParamData(PlotRTIData):
884 '''
883 '''
885 Plot for data_param object
884 Plot for data_param object
886 '''
885 '''
887
886
888 CODE = 'param'
887 CODE = 'param'
889 colormap = 'seismic'
888 colormap = 'seismic'
890
889
891 def setup(self):
890 def setup(self):
892 self.xaxis = 'time'
891 self.xaxis = 'time'
893 self.ncols = 1
892 self.ncols = 1
894 self.nrows = self.data.shape(self.CODE)[0]
893 self.nrows = self.data.shape(self.CODE)[0]
895 self.nplots = self.nrows
894 self.nplots = self.nrows
896 if self.showSNR:
895 if self.showSNR:
897 self.nrows += 1
896 self.nrows += 1
898 self.nplots += 1
897 self.nplots += 1
899
898
900 self.ylabel = 'Height [Km]'
899 self.ylabel = 'Height [Km]'
901 self.titles = self.data.parameters \
900 if not self.titles:
902 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
901 self.titles = self.data.parameters \
903 if self.showSNR:
902 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
904 self.titles.append('SNR')
903 if self.showSNR:
904 self.titles.append('SNR')
905
905
906 def plot(self):
906 def plot(self):
907 self.data.normalize_heights()
907 self.data.normalize_heights()
908 self.x = self.times
908 self.x = self.times
909 self.y = self.data.heights
909 self.y = self.data.heights
910 if self.showSNR:
910 if self.showSNR:
911 self.z = numpy.concatenate(
911 self.z = numpy.concatenate(
912 (self.data[self.CODE], self.data['snr'])
912 (self.data[self.CODE], self.data['snr'])
913 )
913 )
914 else:
914 else:
915 self.z = self.data[self.CODE]
915 self.z = self.data[self.CODE]
916
916
917 self.z = numpy.ma.masked_invalid(self.z)
917 self.z = numpy.ma.masked_invalid(self.z)
918
918
919 for n, ax in enumerate(self.axes):
919 for n, ax in enumerate(self.axes):
920
920
921 x, y, z = self.fill_gaps(*self.decimate())
921 x, y, z = self.fill_gaps(*self.decimate())
922 self.zmax = self.zmax if self.zmax is not None else numpy.max(
922 self.zmax = self.zmax if self.zmax is not None else numpy.max(
923 self.z[n])
923 self.z[n])
924 self.zmin = self.zmin if self.zmin is not None else numpy.min(
924 self.zmin = self.zmin if self.zmin is not None else numpy.min(
925 self.z[n])
925 self.z[n])
926
926
927 if ax.firsttime:
927 if ax.firsttime:
928 if self.zlimits is not None:
928 if self.zlimits is not None:
929 self.zmin, self.zmax = self.zlimits[n]
929 self.zmin, self.zmax = self.zlimits[n]
930
930
931 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
931 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
932 vmin=self.zmin,
932 vmin=self.zmin,
933 vmax=self.zmax,
933 vmax=self.zmax,
934 cmap=self.cmaps[n]
934 cmap=self.cmaps[n]
935 )
935 )
936 else:
936 else:
937 if self.zlimits is not None:
937 if self.zlimits is not None:
938 self.zmin, self.zmax = self.zlimits[n]
938 self.zmin, self.zmax = self.zlimits[n]
939 ax.collections.remove(ax.collections[0])
939 ax.collections.remove(ax.collections[0])
940 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
940 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
941 vmin=self.zmin,
941 vmin=self.zmin,
942 vmax=self.zmax,
942 vmax=self.zmax,
943 cmap=self.cmaps[n]
943 cmap=self.cmaps[n]
944 )
944 )
945
945
946 self.saveTime = self.min_time
946 self.saveTime = self.min_time
947
947
948
948
949 class PlotOutputData(PlotParamData):
949 class PlotOutputData(PlotParamData):
950 '''
950 '''
951 Plot data_output object
951 Plot data_output object
952 '''
952 '''
953
953
954 CODE = 'output'
954 CODE = 'output'
955 colormap = 'seismic'
955 colormap = 'seismic'
@@ -1,20 +1,21
1 '''
1 '''
2
2
3 $Author: murco $
3 $Author: murco $
4 $Id: JRODataIO.py 169 2012-11-19 21:57:03Z murco $
4 $Id: JRODataIO.py 169 2012-11-19 21:57:03Z murco $
5 '''
5 '''
6
6
7 from jroIO_voltage import *
7 from jroIO_voltage import *
8 from jroIO_spectra import *
8 from jroIO_spectra import *
9 from jroIO_heispectra import *
9 from jroIO_heispectra import *
10 from jroIO_usrp import *
10 from jroIO_usrp import *
11 from jroIO_digitalRF import *
11 from jroIO_digitalRF import *
12 from jroIO_kamisr import *
12 from jroIO_kamisr import *
13 from jroIO_param import *
13 from jroIO_param import *
14 from jroIO_hf import *
14 from jroIO_hf import *
15
15
16 from jroIO_madrigal import *
16 from jroIO_madrigal import *
17
17
18 from bltrIO_param import *
18 from bltrIO_param import *
19 from jroIO_bltr import *
19 from jroIO_bltr import *
20 from jroIO_mira35c import *
20 from jroIO_mira35c import *
21 from julIO_param import * No newline at end of file
@@ -1,636 +1,635
1 '''
1 '''
2 @author: Juan C. Espinoza
2 @author: Juan C. Espinoza
3 '''
3 '''
4
4
5 import time
5 import time
6 import json
6 import json
7 import numpy
7 import numpy
8 import paho.mqtt.client as mqtt
8 import paho.mqtt.client as mqtt
9 import zmq
9 import zmq
10 import datetime
10 import datetime
11 from zmq.utils.monitor import recv_monitor_message
11 from zmq.utils.monitor import recv_monitor_message
12 from functools import wraps
12 from functools import wraps
13 from threading import Thread
13 from threading import Thread
14 from multiprocessing import Process
14 from multiprocessing import Process
15
15
16 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit
16 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit
17 from schainpy.model.data.jrodata import JROData
17 from schainpy.model.data.jrodata import JROData
18 from schainpy.utils import log
18 from schainpy.utils import log
19
19
20 MAXNUMX = 100
20 MAXNUMX = 100
21 MAXNUMY = 100
21 MAXNUMY = 100
22
22
23 class PrettyFloat(float):
23 class PrettyFloat(float):
24 def __repr__(self):
24 def __repr__(self):
25 return '%.2f' % self
25 return '%.2f' % self
26
26
27 def roundFloats(obj):
27 def roundFloats(obj):
28 if isinstance(obj, list):
28 if isinstance(obj, list):
29 return map(roundFloats, obj)
29 return map(roundFloats, obj)
30 elif isinstance(obj, float):
30 elif isinstance(obj, float):
31 return round(obj, 2)
31 return round(obj, 2)
32
32
33 def decimate(z, MAXNUMY):
33 def decimate(z, MAXNUMY):
34 dy = int(len(z[0])/MAXNUMY) + 1
34 dy = int(len(z[0])/MAXNUMY) + 1
35
35
36 return z[::, ::dy]
36 return z[::, ::dy]
37
37
38 class throttle(object):
38 class throttle(object):
39 '''
39 '''
40 Decorator that prevents a function from being called more than once every
40 Decorator that prevents a function from being called more than once every
41 time period.
41 time period.
42 To create a function that cannot be called more than once a minute, but
42 To create a function that cannot be called more than once a minute, but
43 will sleep until it can be called:
43 will sleep until it can be called:
44 @throttle(minutes=1)
44 @throttle(minutes=1)
45 def foo():
45 def foo():
46 pass
46 pass
47
47
48 for i in range(10):
48 for i in range(10):
49 foo()
49 foo()
50 print "This function has run %s times." % i
50 print "This function has run %s times." % i
51 '''
51 '''
52
52
53 def __init__(self, seconds=0, minutes=0, hours=0):
53 def __init__(self, seconds=0, minutes=0, hours=0):
54 self.throttle_period = datetime.timedelta(
54 self.throttle_period = datetime.timedelta(
55 seconds=seconds, minutes=minutes, hours=hours
55 seconds=seconds, minutes=minutes, hours=hours
56 )
56 )
57
57
58 self.time_of_last_call = datetime.datetime.min
58 self.time_of_last_call = datetime.datetime.min
59
59
60 def __call__(self, fn):
60 def __call__(self, fn):
61 @wraps(fn)
61 @wraps(fn)
62 def wrapper(*args, **kwargs):
62 def wrapper(*args, **kwargs):
63 coerce = kwargs.pop('coerce', None)
63 coerce = kwargs.pop('coerce', None)
64 if coerce:
64 if coerce:
65 self.time_of_last_call = datetime.datetime.now()
65 self.time_of_last_call = datetime.datetime.now()
66 return fn(*args, **kwargs)
66 return fn(*args, **kwargs)
67 else:
67 else:
68 now = datetime.datetime.now()
68 now = datetime.datetime.now()
69 time_since_last_call = now - self.time_of_last_call
69 time_since_last_call = now - self.time_of_last_call
70 time_left = self.throttle_period - time_since_last_call
70 time_left = self.throttle_period - time_since_last_call
71
71
72 if time_left > datetime.timedelta(seconds=0):
72 if time_left > datetime.timedelta(seconds=0):
73 return
73 return
74
74
75 self.time_of_last_call = datetime.datetime.now()
75 self.time_of_last_call = datetime.datetime.now()
76 return fn(*args, **kwargs)
76 return fn(*args, **kwargs)
77
77
78 return wrapper
78 return wrapper
79
79
80 class Data(object):
80 class Data(object):
81 '''
81 '''
82 Object to hold data to be plotted
82 Object to hold data to be plotted
83 '''
83 '''
84
84
85 def __init__(self, plottypes, throttle_value):
85 def __init__(self, plottypes, throttle_value):
86 self.plottypes = plottypes
86 self.plottypes = plottypes
87 self.throttle = throttle_value
87 self.throttle = throttle_value
88 self.ended = False
88 self.ended = False
89 self.localtime = False
89 self.localtime = False
90 self.__times = []
90 self.__times = []
91 self.__heights = []
91 self.__heights = []
92
92
93 def __str__(self):
93 def __str__(self):
94 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
94 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
95 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
95 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
96
96
97 def __len__(self):
97 def __len__(self):
98 return len(self.__times)
98 return len(self.__times)
99
99
100 def __getitem__(self, key):
100 def __getitem__(self, key):
101 if key not in self.data:
101 if key not in self.data:
102 raise KeyError(log.error('Missing key: {}'.format(key)))
102 raise KeyError(log.error('Missing key: {}'.format(key)))
103
103
104 if 'spc' in key:
104 if 'spc' in key:
105 ret = self.data[key]
105 ret = self.data[key]
106 else:
106 else:
107 ret = numpy.array([self.data[key][x] for x in self.times])
107 ret = numpy.array([self.data[key][x] for x in self.times])
108 if ret.ndim > 1:
108 if ret.ndim > 1:
109 ret = numpy.swapaxes(ret, 0, 1)
109 ret = numpy.swapaxes(ret, 0, 1)
110 return ret
110 return ret
111
111
112 def __contains__(self, key):
112 def __contains__(self, key):
113 return key in self.data
113 return key in self.data
114
114
115 def setup(self):
115 def setup(self):
116 '''
116 '''
117 Configure object
117 Configure object
118 '''
118 '''
119
119
120 self.ended = False
120 self.ended = False
121 self.data = {}
121 self.data = {}
122 self.__times = []
122 self.__times = []
123 self.__heights = []
123 self.__heights = []
124 self.__all_heights = set()
124 self.__all_heights = set()
125 for plot in self.plottypes:
125 for plot in self.plottypes:
126 if 'snr' in plot:
126 if 'snr' in plot:
127 plot = 'snr'
127 plot = 'snr'
128 self.data[plot] = {}
128 self.data[plot] = {}
129
129
130 def shape(self, key):
130 def shape(self, key):
131 '''
131 '''
132 Get the shape of the one-element data for the given key
132 Get the shape of the one-element data for the given key
133 '''
133 '''
134
134
135 if len(self.data[key]):
135 if len(self.data[key]):
136 if 'spc' in key:
136 if 'spc' in key:
137 return self.data[key].shape
137 return self.data[key].shape
138 return self.data[key][self.__times[0]].shape
138 return self.data[key][self.__times[0]].shape
139 return (0,)
139 return (0,)
140
140
141 def update(self, dataOut):
141 def update(self, dataOut, tm):
142 '''
142 '''
143 Update data object with new dataOut
143 Update data object with new dataOut
144 '''
144 '''
145
145
146 tm = dataOut.utctime
147 if tm in self.__times:
146 if tm in self.__times:
148 return
147 return
149
148
150 self.parameters = getattr(dataOut, 'parameters', [])
149 self.parameters = getattr(dataOut, 'parameters', [])
151 self.pairs = dataOut.pairsList
150 self.pairs = dataOut.pairsList
152 self.channels = dataOut.channelList
151 self.channels = dataOut.channelList
153 self.interval = dataOut.getTimeInterval()
152 self.interval = dataOut.getTimeInterval()
154 self.localtime = dataOut.useLocalTime
153 self.localtime = dataOut.useLocalTime
155 if 'spc' in self.plottypes or 'cspc' in self.plottypes:
154 if 'spc' in self.plottypes or 'cspc' in self.plottypes:
156 self.xrange = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
155 self.xrange = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
157 self.__heights.append(dataOut.heightList)
156 self.__heights.append(dataOut.heightList)
158 self.__all_heights.update(dataOut.heightList)
157 self.__all_heights.update(dataOut.heightList)
159 self.__times.append(tm)
158 self.__times.append(tm)
160
159
161 for plot in self.plottypes:
160 for plot in self.plottypes:
162 if plot == 'spc':
161 if plot == 'spc':
163 z = dataOut.data_spc/dataOut.normFactor
162 z = dataOut.data_spc/dataOut.normFactor
164 self.data[plot] = 10*numpy.log10(z)
163 self.data[plot] = 10*numpy.log10(z)
165 if plot == 'cspc':
164 if plot == 'cspc':
166 self.data[plot] = dataOut.data_cspc
165 self.data[plot] = dataOut.data_cspc
167 if plot == 'noise':
166 if plot == 'noise':
168 self.data[plot][tm] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
167 self.data[plot][tm] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
169 if plot == 'rti':
168 if plot == 'rti':
170 self.data[plot][tm] = dataOut.getPower()
169 self.data[plot][tm] = dataOut.getPower()
171 if plot == 'snr_db':
170 if plot == 'snr_db':
172 self.data['snr'][tm] = dataOut.data_SNR
171 self.data['snr'][tm] = dataOut.data_SNR
173 if plot == 'snr':
172 if plot == 'snr':
174 self.data[plot][tm] = 10*numpy.log10(dataOut.data_SNR)
173 self.data[plot][tm] = 10*numpy.log10(dataOut.data_SNR)
175 if plot == 'dop':
174 if plot == 'dop':
176 self.data[plot][tm] = 10*numpy.log10(dataOut.data_DOP)
175 self.data[plot][tm] = 10*numpy.log10(dataOut.data_DOP)
177 if plot == 'mean':
176 if plot == 'mean':
178 self.data[plot][tm] = dataOut.data_MEAN
177 self.data[plot][tm] = dataOut.data_MEAN
179 if plot == 'std':
178 if plot == 'std':
180 self.data[plot][tm] = dataOut.data_STD
179 self.data[plot][tm] = dataOut.data_STD
181 if plot == 'coh':
180 if plot == 'coh':
182 self.data[plot][tm] = dataOut.getCoherence()
181 self.data[plot][tm] = dataOut.getCoherence()
183 if plot == 'phase':
182 if plot == 'phase':
184 self.data[plot][tm] = dataOut.getCoherence(phase=True)
183 self.data[plot][tm] = dataOut.getCoherence(phase=True)
185 if plot == 'output':
184 if plot == 'output':
186 self.data[plot][tm] = dataOut.data_output
185 self.data[plot][tm] = dataOut.data_output
187 if plot == 'param':
186 if plot == 'param':
188 self.data[plot][tm] = dataOut.data_param
187 self.data[plot][tm] = dataOut.data_param
189
188
190 def normalize_heights(self):
189 def normalize_heights(self):
191 '''
190 '''
192 Ensure same-dimension of the data for different heighList
191 Ensure same-dimension of the data for different heighList
193 '''
192 '''
194
193
195 H = numpy.array(list(self.__all_heights))
194 H = numpy.array(list(self.__all_heights))
196 H.sort()
195 H.sort()
197 for key in self.data:
196 for key in self.data:
198 shape = self.shape(key)[:-1] + H.shape
197 shape = self.shape(key)[:-1] + H.shape
199 for tm, obj in self.data[key].items():
198 for tm, obj in self.data[key].items():
200 h = self.__heights[self.__times.index(tm)]
199 h = self.__heights[self.__times.index(tm)]
201 if H.size == h.size:
200 if H.size == h.size:
202 continue
201 continue
203 index = numpy.where(numpy.in1d(H, h))[0]
202 index = numpy.where(numpy.in1d(H, h))[0]
204 dummy = numpy.zeros(shape) + numpy.nan
203 dummy = numpy.zeros(shape) + numpy.nan
205 if len(shape) == 2:
204 if len(shape) == 2:
206 dummy[:, index] = obj
205 dummy[:, index] = obj
207 else:
206 else:
208 dummy[index] = obj
207 dummy[index] = obj
209 self.data[key][tm] = dummy
208 self.data[key][tm] = dummy
210
209
211 self.__heights = [H for tm in self.__times]
210 self.__heights = [H for tm in self.__times]
212
211
213 def jsonify(self, decimate=False):
212 def jsonify(self, decimate=False):
214 '''
213 '''
215 Convert data to json
214 Convert data to json
216 '''
215 '''
217
216
218 ret = {}
217 ret = {}
219 tm = self.times[-1]
218 tm = self.times[-1]
220
219
221 for key, value in self.data:
220 for key, value in self.data:
222 if key in ('spc', 'cspc'):
221 if key in ('spc', 'cspc'):
223 ret[key] = roundFloats(self.data[key].to_list())
222 ret[key] = roundFloats(self.data[key].to_list())
224 else:
223 else:
225 ret[key] = roundFloats(self.data[key][tm].to_list())
224 ret[key] = roundFloats(self.data[key][tm].to_list())
226
225
227 ret['timestamp'] = tm
226 ret['timestamp'] = tm
228 ret['interval'] = self.interval
227 ret['interval'] = self.interval
229
228
230 @property
229 @property
231 def times(self):
230 def times(self):
232 '''
231 '''
233 Return the list of times of the current data
232 Return the list of times of the current data
234 '''
233 '''
235
234
236 ret = numpy.array(self.__times)
235 ret = numpy.array(self.__times)
237 ret.sort()
236 ret.sort()
238 return ret
237 return ret
239
238
240 @property
239 @property
241 def heights(self):
240 def heights(self):
242 '''
241 '''
243 Return the list of heights of the current data
242 Return the list of heights of the current data
244 '''
243 '''
245
244
246 return numpy.array(self.__heights[-1])
245 return numpy.array(self.__heights[-1])
247
246
248 class PublishData(Operation):
247 class PublishData(Operation):
249 '''
248 '''
250 Operation to send data over zmq.
249 Operation to send data over zmq.
251 '''
250 '''
252
251
253 __attrs__ = ['host', 'port', 'delay', 'zeromq', 'mqtt', 'verbose']
252 __attrs__ = ['host', 'port', 'delay', 'zeromq', 'mqtt', 'verbose']
254
253
255 def __init__(self, **kwargs):
254 def __init__(self, **kwargs):
256 """Inicio."""
255 """Inicio."""
257 Operation.__init__(self, **kwargs)
256 Operation.__init__(self, **kwargs)
258 self.isConfig = False
257 self.isConfig = False
259 self.client = None
258 self.client = None
260 self.zeromq = None
259 self.zeromq = None
261 self.mqtt = None
260 self.mqtt = None
262
261
263 def on_disconnect(self, client, userdata, rc):
262 def on_disconnect(self, client, userdata, rc):
264 if rc != 0:
263 if rc != 0:
265 log.warning('Unexpected disconnection.')
264 log.warning('Unexpected disconnection.')
266 self.connect()
265 self.connect()
267
266
268 def connect(self):
267 def connect(self):
269 log.warning('trying to connect')
268 log.warning('trying to connect')
270 try:
269 try:
271 self.client.connect(
270 self.client.connect(
272 host=self.host,
271 host=self.host,
273 port=self.port,
272 port=self.port,
274 keepalive=60*10,
273 keepalive=60*10,
275 bind_address='')
274 bind_address='')
276 self.client.loop_start()
275 self.client.loop_start()
277 # self.client.publish(
276 # self.client.publish(
278 # self.topic + 'SETUP',
277 # self.topic + 'SETUP',
279 # json.dumps(setup),
278 # json.dumps(setup),
280 # retain=True
279 # retain=True
281 # )
280 # )
282 except:
281 except:
283 log.error('MQTT Conection error.')
282 log.error('MQTT Conection error.')
284 self.client = False
283 self.client = False
285
284
286 def setup(self, port=1883, username=None, password=None, clientId="user", zeromq=1, verbose=True, **kwargs):
285 def setup(self, port=1883, username=None, password=None, clientId="user", zeromq=1, verbose=True, **kwargs):
287 self.counter = 0
286 self.counter = 0
288 self.topic = kwargs.get('topic', 'schain')
287 self.topic = kwargs.get('topic', 'schain')
289 self.delay = kwargs.get('delay', 0)
288 self.delay = kwargs.get('delay', 0)
290 self.plottype = kwargs.get('plottype', 'spectra')
289 self.plottype = kwargs.get('plottype', 'spectra')
291 self.host = kwargs.get('host', "10.10.10.82")
290 self.host = kwargs.get('host', "10.10.10.82")
292 self.port = kwargs.get('port', 3000)
291 self.port = kwargs.get('port', 3000)
293 self.clientId = clientId
292 self.clientId = clientId
294 self.cnt = 0
293 self.cnt = 0
295 self.zeromq = zeromq
294 self.zeromq = zeromq
296 self.mqtt = kwargs.get('plottype', 0)
295 self.mqtt = kwargs.get('plottype', 0)
297 self.client = None
296 self.client = None
298 self.verbose = verbose
297 self.verbose = verbose
299 setup = []
298 setup = []
300 if mqtt is 1:
299 if mqtt is 1:
301 self.client = mqtt.Client(
300 self.client = mqtt.Client(
302 client_id=self.clientId + self.topic + 'SCHAIN',
301 client_id=self.clientId + self.topic + 'SCHAIN',
303 clean_session=True)
302 clean_session=True)
304 self.client.on_disconnect = self.on_disconnect
303 self.client.on_disconnect = self.on_disconnect
305 self.connect()
304 self.connect()
306 for plot in self.plottype:
305 for plot in self.plottype:
307 setup.append({
306 setup.append({
308 'plot': plot,
307 'plot': plot,
309 'topic': self.topic + plot,
308 'topic': self.topic + plot,
310 'title': getattr(self, plot + '_' + 'title', False),
309 'title': getattr(self, plot + '_' + 'title', False),
311 'xlabel': getattr(self, plot + '_' + 'xlabel', False),
310 'xlabel': getattr(self, plot + '_' + 'xlabel', False),
312 'ylabel': getattr(self, plot + '_' + 'ylabel', False),
311 'ylabel': getattr(self, plot + '_' + 'ylabel', False),
313 'xrange': getattr(self, plot + '_' + 'xrange', False),
312 'xrange': getattr(self, plot + '_' + 'xrange', False),
314 'yrange': getattr(self, plot + '_' + 'yrange', False),
313 'yrange': getattr(self, plot + '_' + 'yrange', False),
315 'zrange': getattr(self, plot + '_' + 'zrange', False),
314 'zrange': getattr(self, plot + '_' + 'zrange', False),
316 })
315 })
317 if zeromq is 1:
316 if zeromq is 1:
318 context = zmq.Context()
317 context = zmq.Context()
319 self.zmq_socket = context.socket(zmq.PUSH)
318 self.zmq_socket = context.socket(zmq.PUSH)
320 server = kwargs.get('server', 'zmq.pipe')
319 server = kwargs.get('server', 'zmq.pipe')
321
320
322 if 'tcp://' in server:
321 if 'tcp://' in server:
323 address = server
322 address = server
324 else:
323 else:
325 address = 'ipc:///tmp/%s' % server
324 address = 'ipc:///tmp/%s' % server
326
325
327 self.zmq_socket.connect(address)
326 self.zmq_socket.connect(address)
328 time.sleep(1)
327 time.sleep(1)
329
328
330
329
331 def publish_data(self):
330 def publish_data(self):
332 self.dataOut.finished = False
331 self.dataOut.finished = False
333 if self.mqtt is 1:
332 if self.mqtt is 1:
334 yData = self.dataOut.heightList[:2].tolist()
333 yData = self.dataOut.heightList[:2].tolist()
335 if self.plottype == 'spectra':
334 if self.plottype == 'spectra':
336 data = getattr(self.dataOut, 'data_spc')
335 data = getattr(self.dataOut, 'data_spc')
337 z = data/self.dataOut.normFactor
336 z = data/self.dataOut.normFactor
338 zdB = 10*numpy.log10(z)
337 zdB = 10*numpy.log10(z)
339 xlen, ylen = zdB[0].shape
338 xlen, ylen = zdB[0].shape
340 dx = int(xlen/MAXNUMX) + 1
339 dx = int(xlen/MAXNUMX) + 1
341 dy = int(ylen/MAXNUMY) + 1
340 dy = int(ylen/MAXNUMY) + 1
342 Z = [0 for i in self.dataOut.channelList]
341 Z = [0 for i in self.dataOut.channelList]
343 for i in self.dataOut.channelList:
342 for i in self.dataOut.channelList:
344 Z[i] = zdB[i][::dx, ::dy].tolist()
343 Z[i] = zdB[i][::dx, ::dy].tolist()
345 payload = {
344 payload = {
346 'timestamp': self.dataOut.utctime,
345 'timestamp': self.dataOut.utctime,
347 'data': roundFloats(Z),
346 'data': roundFloats(Z),
348 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
347 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
349 'interval': self.dataOut.getTimeInterval(),
348 'interval': self.dataOut.getTimeInterval(),
350 'type': self.plottype,
349 'type': self.plottype,
351 'yData': yData
350 'yData': yData
352 }
351 }
353
352
354 elif self.plottype in ('rti', 'power'):
353 elif self.plottype in ('rti', 'power'):
355 data = getattr(self.dataOut, 'data_spc')
354 data = getattr(self.dataOut, 'data_spc')
356 z = data/self.dataOut.normFactor
355 z = data/self.dataOut.normFactor
357 avg = numpy.average(z, axis=1)
356 avg = numpy.average(z, axis=1)
358 avgdB = 10*numpy.log10(avg)
357 avgdB = 10*numpy.log10(avg)
359 xlen, ylen = z[0].shape
358 xlen, ylen = z[0].shape
360 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
359 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
361 AVG = [0 for i in self.dataOut.channelList]
360 AVG = [0 for i in self.dataOut.channelList]
362 for i in self.dataOut.channelList:
361 for i in self.dataOut.channelList:
363 AVG[i] = avgdB[i][::dy].tolist()
362 AVG[i] = avgdB[i][::dy].tolist()
364 payload = {
363 payload = {
365 'timestamp': self.dataOut.utctime,
364 'timestamp': self.dataOut.utctime,
366 'data': roundFloats(AVG),
365 'data': roundFloats(AVG),
367 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
366 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
368 'interval': self.dataOut.getTimeInterval(),
367 'interval': self.dataOut.getTimeInterval(),
369 'type': self.plottype,
368 'type': self.plottype,
370 'yData': yData
369 'yData': yData
371 }
370 }
372 elif self.plottype == 'noise':
371 elif self.plottype == 'noise':
373 noise = self.dataOut.getNoise()/self.dataOut.normFactor
372 noise = self.dataOut.getNoise()/self.dataOut.normFactor
374 noisedB = 10*numpy.log10(noise)
373 noisedB = 10*numpy.log10(noise)
375 payload = {
374 payload = {
376 'timestamp': self.dataOut.utctime,
375 'timestamp': self.dataOut.utctime,
377 'data': roundFloats(noisedB.reshape(-1, 1).tolist()),
376 'data': roundFloats(noisedB.reshape(-1, 1).tolist()),
378 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
377 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
379 'interval': self.dataOut.getTimeInterval(),
378 'interval': self.dataOut.getTimeInterval(),
380 'type': self.plottype,
379 'type': self.plottype,
381 'yData': yData
380 'yData': yData
382 }
381 }
383 elif self.plottype == 'snr':
382 elif self.plottype == 'snr':
384 data = getattr(self.dataOut, 'data_SNR')
383 data = getattr(self.dataOut, 'data_SNR')
385 avgdB = 10*numpy.log10(data)
384 avgdB = 10*numpy.log10(data)
386
385
387 ylen = data[0].size
386 ylen = data[0].size
388 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
387 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
389 AVG = [0 for i in self.dataOut.channelList]
388 AVG = [0 for i in self.dataOut.channelList]
390 for i in self.dataOut.channelList:
389 for i in self.dataOut.channelList:
391 AVG[i] = avgdB[i][::dy].tolist()
390 AVG[i] = avgdB[i][::dy].tolist()
392 payload = {
391 payload = {
393 'timestamp': self.dataOut.utctime,
392 'timestamp': self.dataOut.utctime,
394 'data': roundFloats(AVG),
393 'data': roundFloats(AVG),
395 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
394 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
396 'type': self.plottype,
395 'type': self.plottype,
397 'yData': yData
396 'yData': yData
398 }
397 }
399 else:
398 else:
400 print "Tipo de grafico invalido"
399 print "Tipo de grafico invalido"
401 payload = {
400 payload = {
402 'data': 'None',
401 'data': 'None',
403 'timestamp': 'None',
402 'timestamp': 'None',
404 'type': None
403 'type': None
405 }
404 }
406
405
407 self.client.publish(self.topic + self.plottype, json.dumps(payload), qos=0)
406 self.client.publish(self.topic + self.plottype, json.dumps(payload), qos=0)
408
407
409 if self.zeromq is 1:
408 if self.zeromq is 1:
410 if self.verbose:
409 if self.verbose:
411 log.log(
410 log.log(
412 'Sending {} - {}'.format(self.dataOut.type, self.dataOut.datatime),
411 'Sending {} - {}'.format(self.dataOut.type, self.dataOut.datatime),
413 self.name
412 self.name
414 )
413 )
415 self.zmq_socket.send_pyobj(self.dataOut)
414 self.zmq_socket.send_pyobj(self.dataOut)
416
415
417 def run(self, dataOut, **kwargs):
416 def run(self, dataOut, **kwargs):
418 self.dataOut = dataOut
417 self.dataOut = dataOut
419 if not self.isConfig:
418 if not self.isConfig:
420 self.setup(**kwargs)
419 self.setup(**kwargs)
421 self.isConfig = True
420 self.isConfig = True
422
421
423 self.publish_data()
422 self.publish_data()
424 time.sleep(self.delay)
423 time.sleep(self.delay)
425
424
426 def close(self):
425 def close(self):
427 if self.zeromq is 1:
426 if self.zeromq is 1:
428 self.dataOut.finished = True
427 self.dataOut.finished = True
429 self.zmq_socket.send_pyobj(self.dataOut)
428 self.zmq_socket.send_pyobj(self.dataOut)
430 time.sleep(0.1)
429 time.sleep(0.1)
431 self.zmq_socket.close()
430 self.zmq_socket.close()
432 if self.client:
431 if self.client:
433 self.client.loop_stop()
432 self.client.loop_stop()
434 self.client.disconnect()
433 self.client.disconnect()
435
434
436
435
437 class ReceiverData(ProcessingUnit):
436 class ReceiverData(ProcessingUnit):
438
437
439 __attrs__ = ['server']
438 __attrs__ = ['server']
440
439
441 def __init__(self, **kwargs):
440 def __init__(self, **kwargs):
442
441
443 ProcessingUnit.__init__(self, **kwargs)
442 ProcessingUnit.__init__(self, **kwargs)
444
443
445 self.isConfig = False
444 self.isConfig = False
446 server = kwargs.get('server', 'zmq.pipe')
445 server = kwargs.get('server', 'zmq.pipe')
447 if 'tcp://' in server:
446 if 'tcp://' in server:
448 address = server
447 address = server
449 else:
448 else:
450 address = 'ipc:///tmp/%s' % server
449 address = 'ipc:///tmp/%s' % server
451
450
452 self.address = address
451 self.address = address
453 self.dataOut = JROData()
452 self.dataOut = JROData()
454
453
455 def setup(self):
454 def setup(self):
456
455
457 self.context = zmq.Context()
456 self.context = zmq.Context()
458 self.receiver = self.context.socket(zmq.PULL)
457 self.receiver = self.context.socket(zmq.PULL)
459 self.receiver.bind(self.address)
458 self.receiver.bind(self.address)
460 time.sleep(0.5)
459 time.sleep(0.5)
461 log.success('ReceiverData from {}'.format(self.address))
460 log.success('ReceiverData from {}'.format(self.address))
462
461
463
462
464 def run(self):
463 def run(self):
465
464
466 if not self.isConfig:
465 if not self.isConfig:
467 self.setup()
466 self.setup()
468 self.isConfig = True
467 self.isConfig = True
469
468
470 self.dataOut = self.receiver.recv_pyobj()
469 self.dataOut = self.receiver.recv_pyobj()
471 log.log('{} - {}'.format(self.dataOut.type,
470 log.log('{} - {}'.format(self.dataOut.type,
472 self.dataOut.datatime.ctime(),),
471 self.dataOut.datatime.ctime(),),
473 'Receiving')
472 'Receiving')
474
473
475
474
476 class PlotterReceiver(ProcessingUnit, Process):
475 class PlotterReceiver(ProcessingUnit, Process):
477
476
478 throttle_value = 5
477 throttle_value = 5
479 __attrs__ = ['server', 'plottypes', 'realtime', 'localtime', 'throttle']
478 __attrs__ = ['server', 'plottypes', 'realtime', 'localtime', 'throttle']
480
479
481 def __init__(self, **kwargs):
480 def __init__(self, **kwargs):
482
481
483 ProcessingUnit.__init__(self, **kwargs)
482 ProcessingUnit.__init__(self, **kwargs)
484 Process.__init__(self)
483 Process.__init__(self)
485 self.mp = False
484 self.mp = False
486 self.isConfig = False
485 self.isConfig = False
487 self.isWebConfig = False
486 self.isWebConfig = False
488 self.connections = 0
487 self.connections = 0
489 server = kwargs.get('server', 'zmq.pipe')
488 server = kwargs.get('server', 'zmq.pipe')
490 plot_server = kwargs.get('plot_server', 'zmq.web')
489 plot_server = kwargs.get('plot_server', 'zmq.web')
491 if 'tcp://' in server:
490 if 'tcp://' in server:
492 address = server
491 address = server
493 else:
492 else:
494 address = 'ipc:///tmp/%s' % server
493 address = 'ipc:///tmp/%s' % server
495
494
496 if 'tcp://' in plot_server:
495 if 'tcp://' in plot_server:
497 plot_address = plot_server
496 plot_address = plot_server
498 else:
497 else:
499 plot_address = 'ipc:///tmp/%s' % plot_server
498 plot_address = 'ipc:///tmp/%s' % plot_server
500
499
501 self.address = address
500 self.address = address
502 self.plot_address = plot_address
501 self.plot_address = plot_address
503 self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')]
502 self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')]
504 self.realtime = kwargs.get('realtime', False)
503 self.realtime = kwargs.get('realtime', False)
505 self.localtime = kwargs.get('localtime', True)
504 self.localtime = kwargs.get('localtime', True)
506 self.throttle_value = kwargs.get('throttle', 5)
505 self.throttle_value = kwargs.get('throttle', 5)
507 self.sendData = self.initThrottle(self.throttle_value)
506 self.sendData = self.initThrottle(self.throttle_value)
508 self.dates = []
507 self.dates = []
509 self.setup()
508 self.setup()
510
509
511 def setup(self):
510 def setup(self):
512
511
513 self.data = Data(self.plottypes, self.throttle_value)
512 self.data = Data(self.plottypes, self.throttle_value)
514 self.isConfig = True
513 self.isConfig = True
515
514
516 def event_monitor(self, monitor):
515 def event_monitor(self, monitor):
517
516
518 events = {}
517 events = {}
519
518
520 for name in dir(zmq):
519 for name in dir(zmq):
521 if name.startswith('EVENT_'):
520 if name.startswith('EVENT_'):
522 value = getattr(zmq, name)
521 value = getattr(zmq, name)
523 events[value] = name
522 events[value] = name
524
523
525 while monitor.poll():
524 while monitor.poll():
526 evt = recv_monitor_message(monitor)
525 evt = recv_monitor_message(monitor)
527 if evt['event'] == 32:
526 if evt['event'] == 32:
528 self.connections += 1
527 self.connections += 1
529 if evt['event'] == 512:
528 if evt['event'] == 512:
530 pass
529 pass
531
530
532 evt.update({'description': events[evt['event']]})
531 evt.update({'description': events[evt['event']]})
533
532
534 if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
533 if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
535 break
534 break
536 monitor.close()
535 monitor.close()
537 print('event monitor thread done!')
536 print('event monitor thread done!')
538
537
539 def initThrottle(self, throttle_value):
538 def initThrottle(self, throttle_value):
540
539
541 @throttle(seconds=throttle_value)
540 @throttle(seconds=throttle_value)
542 def sendDataThrottled(fn_sender, data):
541 def sendDataThrottled(fn_sender, data):
543 fn_sender(data)
542 fn_sender(data)
544
543
545 return sendDataThrottled
544 return sendDataThrottled
546
545
547 def send(self, data):
546 def send(self, data):
548 log.success('Sending {}'.format(data), self.name)
547 log.success('Sending {}'.format(data), self.name)
549 self.sender.send_pyobj(data)
548 self.sender.send_pyobj(data)
550
549
551 def run(self):
550 def run(self):
552
551
553 log.success(
552 log.success(
554 'Starting from {}'.format(self.address),
553 'Starting from {}'.format(self.address),
555 self.name
554 self.name
556 )
555 )
557
556
558 self.context = zmq.Context()
557 self.context = zmq.Context()
559 self.receiver = self.context.socket(zmq.PULL)
558 self.receiver = self.context.socket(zmq.PULL)
560 self.receiver.bind(self.address)
559 self.receiver.bind(self.address)
561 monitor = self.receiver.get_monitor_socket()
560 monitor = self.receiver.get_monitor_socket()
562 self.sender = self.context.socket(zmq.PUB)
561 self.sender = self.context.socket(zmq.PUB)
563 if self.realtime:
562 if self.realtime:
564 self.sender_web = self.context.socket(zmq.PUB)
563 self.sender_web = self.context.socket(zmq.PUB)
565 self.sender_web.connect(self.plot_address)
564 self.sender_web.connect(self.plot_address)
566 time.sleep(1)
565 time.sleep(1)
567
566
568 if 'server' in self.kwargs:
567 if 'server' in self.kwargs:
569 self.sender.bind("ipc:///tmp/{}.plots".format(self.kwargs['server']))
568 self.sender.bind("ipc:///tmp/{}.plots".format(self.kwargs['server']))
570 else:
569 else:
571 self.sender.bind("ipc:///tmp/zmq.plots")
570 self.sender.bind("ipc:///tmp/zmq.plots")
572
571
573 time.sleep(2)
572 time.sleep(2)
574
573
575 t = Thread(target=self.event_monitor, args=(monitor,))
574 t = Thread(target=self.event_monitor, args=(monitor,))
576 t.start()
575 t.start()
577
576
578 while True:
577 while True:
579 dataOut = self.receiver.recv_pyobj()
578 dataOut = self.receiver.recv_pyobj()
580 if not dataOut.flagNoData:
579 if not dataOut.flagNoData:
581 if dataOut.type == 'Parameters':
580 if dataOut.type == 'Parameters':
582 tm = dataOut.utctimeInit
581 tm = dataOut.utctimeInit
583 else:
582 else:
584 tm = dataOut.utctime
583 tm = dataOut.utctime
585 if dataOut.useLocalTime:
584 if dataOut.useLocalTime:
586 if not self.localtime:
585 if not self.localtime:
587 tm += time.timezone
586 tm += time.timezone
588 dt = datetime.datetime.fromtimestamp(tm).date()
587 dt = datetime.datetime.fromtimestamp(tm).date()
589 else:
588 else:
590 if self.localtime:
589 if self.localtime:
591 tm -= time.timezone
590 tm -= time.timezone
592 dt = datetime.datetime.utcfromtimestamp(tm).date()
591 dt = datetime.datetime.utcfromtimestamp(tm).date()
593 coerce = False
592 coerce = False
594 if dt not in self.dates:
593 if dt not in self.dates:
595 if self.data:
594 if self.data:
596 self.data.ended = True
595 self.data.ended = True
597 self.send(self.data)
596 self.send(self.data)
598 coerce = True
597 coerce = True
599 self.data.setup()
598 self.data.setup()
600 self.dates.append(dt)
599 self.dates.append(dt)
601
600
602 self.data.update(dataOut)
601 self.data.update(dataOut, tm)
603
602
604 if dataOut.finished is True:
603 if dataOut.finished is True:
605 self.connections -= 1
604 self.connections -= 1
606 if self.connections == 0 and dt in self.dates:
605 if self.connections == 0 and dt in self.dates:
607 self.data.ended = True
606 self.data.ended = True
608 self.send(self.data)
607 self.send(self.data)
609 self.data.setup()
608 self.data.setup()
610 else:
609 else:
611 if self.realtime:
610 if self.realtime:
612 self.send(self.data)
611 self.send(self.data)
613 # self.sender_web.send_string(self.data.jsonify())
612 # self.sender_web.send_string(self.data.jsonify())
614 else:
613 else:
615 self.sendData(self.send, self.data, coerce=coerce)
614 self.sendData(self.send, self.data, coerce=coerce)
616 coerce = False
615 coerce = False
617
616
618 return
617 return
619
618
620 def sendToWeb(self):
619 def sendToWeb(self):
621
620
622 if not self.isWebConfig:
621 if not self.isWebConfig:
623 context = zmq.Context()
622 context = zmq.Context()
624 sender_web_config = context.socket(zmq.PUB)
623 sender_web_config = context.socket(zmq.PUB)
625 if 'tcp://' in self.plot_address:
624 if 'tcp://' in self.plot_address:
626 dum, address, port = self.plot_address.split(':')
625 dum, address, port = self.plot_address.split(':')
627 conf_address = '{}:{}:{}'.format(dum, address, int(port)+1)
626 conf_address = '{}:{}:{}'.format(dum, address, int(port)+1)
628 else:
627 else:
629 conf_address = self.plot_address + '.config'
628 conf_address = self.plot_address + '.config'
630 sender_web_config.bind(conf_address)
629 sender_web_config.bind(conf_address)
631 time.sleep(1)
630 time.sleep(1)
632 for kwargs in self.operationKwargs.values():
631 for kwargs in self.operationKwargs.values():
633 if 'plot' in kwargs:
632 if 'plot' in kwargs:
634 log.success('[Sending] Config data to web for {}'.format(kwargs['code'].upper()))
633 log.success('[Sending] Config data to web for {}'.format(kwargs['code'].upper()))
635 sender_web_config.send_string(json.dumps(kwargs))
634 sender_web_config.send_string(json.dumps(kwargs))
636 self.isWebConfig = True
635 self.isWebConfig = True
General Comments 0
You need to be logged in to leave comments. Login now