##// END OF EJS Templates
Fix merge
jespinoza -
r1107:0e8d1b4cd150 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,952 +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', 'xaxis','cb_label', 'title',
53 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title',
54 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
54 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
55 'showprofile', 'decimation']
55 'showprofile', 'decimation']
56
56
57 def __init__(self, **kwargs):
57 def __init__(self, **kwargs):
58
58
59 Operation.__init__(self, plot=True, **kwargs)
59 Operation.__init__(self, plot=True, **kwargs)
60 Process.__init__(self)
60 Process.__init__(self)
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', 200)
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) + datetime.timedelta(seconds=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-ymin < Y)[0][0] < 0 else numpy.where(ymax-ymin < Y)[0][0]
373 i = 1 if numpy.where(ymax-ymin < Y)[0][0] < 0 else numpy.where(ymax-ymin < Y)[0][0]
373 ystep = Y[i] / 5
374 ystep = Y[i] / 5
374
375
375 for n, ax in enumerate(self.axes):
376 for n, ax in enumerate(self.axes):
376 if ax.firsttime:
377 if ax.firsttime:
377 ax.set_facecolor(self.bgcolor)
378 ax.set_facecolor(self.bgcolor)
378 ax.yaxis.set_major_locator(MultipleLocator(ystep))
379 ax.yaxis.set_major_locator(MultipleLocator(ystep))
379 if self.xaxis is 'time':
380 if self.xaxis is 'time':
380 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
381 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
381 ax.xaxis.set_major_locator(LinearLocator(9))
382 ax.xaxis.set_major_locator(LinearLocator(9))
382 if self.xlabel is not None:
383 if self.xlabel is not None:
383 ax.set_xlabel(self.xlabel)
384 ax.set_xlabel(self.xlabel)
384 ax.set_ylabel(self.ylabel)
385 ax.set_ylabel(self.ylabel)
385 ax.firsttime = False
386 ax.firsttime = False
386 if self.showprofile:
387 if self.showprofile:
387 self.pf_axes[n].set_ylim(ymin, ymax)
388 self.pf_axes[n].set_ylim(ymin, ymax)
388 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
389 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
389 self.pf_axes[n].set_xlabel('dB')
390 self.pf_axes[n].set_xlabel('dB')
390 self.pf_axes[n].grid(b=True, axis='x')
391 self.pf_axes[n].grid(b=True, axis='x')
391 [tick.set_visible(False)
392 [tick.set_visible(False)
392 for tick in self.pf_axes[n].get_yticklabels()]
393 for tick in self.pf_axes[n].get_yticklabels()]
393 if self.colorbar:
394 if self.colorbar:
394 ax.cbar = plt.colorbar(
395 ax.cbar = plt.colorbar(
395 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)
396 ax.cbar.ax.tick_params(labelsize=8)
397 ax.cbar.ax.tick_params(labelsize=8)
397 ax.cbar.ax.press = None
398 ax.cbar.ax.press = None
398 if self.cb_label:
399 if self.cb_label:
399 ax.cbar.set_label(self.cb_label, size=8)
400 ax.cbar.set_label(self.cb_label, size=8)
400 elif self.cb_labels:
401 elif self.cb_labels:
401 ax.cbar.set_label(self.cb_labels[n], size=8)
402 ax.cbar.set_label(self.cb_labels[n], size=8)
402 else:
403 else:
403 ax.cbar = None
404 ax.cbar = None
404
405
405 if not self.polar:
406 if not self.polar:
406 ax.set_xlim(xmin, xmax)
407 ax.set_xlim(xmin, xmax)
407 ax.set_ylim(ymin, ymax)
408 ax.set_ylim(ymin, ymax)
408 ax.set_title('{} - {} {}'.format(
409 ax.set_title('{} - {} {}'.format(
409 self.titles[n],
410 self.titles[n],
410 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
411 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
411 self.time_label),
412 self.time_label),
412 size=8)
413 size=8)
413 else:
414 else:
414 ax.set_title('{}'.format(self.titles[n]), size=8)
415 ax.set_title('{}'.format(self.titles[n]), size=8)
415 ax.set_ylim(0, 90)
416 ax.set_ylim(0, 90)
416 ax.set_yticks(numpy.arange(0, 90, 20))
417 ax.set_yticks(numpy.arange(0, 90, 20))
417 ax.yaxis.labelpad = 40
418 ax.yaxis.labelpad = 40
418
419
419 def __plot(self):
420 def __plot(self):
420 '''
421 '''
421 '''
422 '''
422 log.success('Plotting', self.name)
423 log.success('Plotting', self.name)
423
424
424 self.plot()
425 self.plot()
425 self.format()
426 self.format()
426
427
427 for n, fig in enumerate(self.figures):
428 for n, fig in enumerate(self.figures):
428 if self.nrows == 0 or self.nplots == 0:
429 if self.nrows == 0 or self.nplots == 0:
429 log.warning('No data', self.name)
430 log.warning('No data', self.name)
430 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')
431 fig.canvas.manager.set_window_title(self.CODE)
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 channels = range(self.nrows)
441 channels = range(self.nrows)
441 if self.oneFigure:
442 if self.oneFigure:
442 label = ''
443 label = ''
443 else:
444 else:
444 label = '_{}'.format(channels[n])
445 label = '_{}'.format(channels[n])
445 figname = os.path.join(
446 figname = os.path.join(
446 self.save,
447 self.save,
447 '{}{}_{}.png'.format(
448 '{}{}_{}.png'.format(
448 self.CODE,
449 self.CODE,
449 label,
450 label,
450 self.getDateTime(self.saveTime).strftime('%y%m%d_%H%M%S')
451 self.getDateTime(self.saveTime).strftime(
452 '%y%m%d_%H%M%S'),
451 )
453 )
452 )
454 )
453 log.log('Saving figure: {}'.format(figname), self.name)
455 log.log('Saving figure: {}'.format(figname), self.name)
454 fig.savefig(figname)
456 fig.savefig(figname)
455
457
456 def plot(self):
458 def plot(self):
457 '''
459 '''
458 '''
460 '''
459 raise(NotImplementedError, 'Implement this method in child class')
461 raise(NotImplementedError, 'Implement this method in child class')
460
462
461 def run(self):
463 def run(self):
462
464
463 log.success('Starting', self.name)
465 log.success('Starting', self.name)
464
466
465 context = zmq.Context()
467 context = zmq.Context()
466 receiver = context.socket(zmq.SUB)
468 receiver = context.socket(zmq.SUB)
467 receiver.setsockopt(zmq.SUBSCRIBE, '')
469 receiver.setsockopt(zmq.SUBSCRIBE, '')
468 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
470 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
469
471
470 if 'server' in self.kwargs['parent']:
472 if 'server' in self.kwargs['parent']:
471 receiver.connect(
473 receiver.connect(
472 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
474 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
473 else:
475 else:
474 receiver.connect("ipc:///tmp/zmq.plots")
476 receiver.connect("ipc:///tmp/zmq.plots")
475
477
476 while True:
478 while True:
477 try:
479 try:
478 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
480 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
479 if self.data.localtime and self.localtime:
481 if self.data.localtime and self.localtime:
480 self.times = self.data.times
482 self.times = self.data.times
481 elif self.data.localtime and not self.localtime:
483 elif self.data.localtime and not self.localtime:
482 self.times = self.data.times + time.timezone
484 self.times = self.data.times + time.timezone
483 elif not self.data.localtime and self.localtime:
485 elif not self.data.localtime and self.localtime:
484 self.times = self.data.times - time.timezone
486 self.times = self.data.times - time.timezone
485 else:
487 else:
486 self.times = self.data.times
488 self.times = self.data.times
487
489
488 self.min_time = self.times[0]
490 self.min_time = self.times[0]
489 self.max_time = self.times[-1]
491 self.max_time = self.times[-1]
490
492
491 if self.isConfig is False:
493 if self.isConfig is False:
492 self.__setup()
494 self.__setup()
493 self.isConfig = True
495 self.isConfig = True
494
496
495 self.__plot()
497 self.__plot()
496
498
497 except zmq.Again as e:
499 except zmq.Again as e:
498 log.log('Waiting for data...')
500 log.log('Waiting for data...')
499 if self.data:
501 if self.data:
500 figpause(self.data.throttle)
502 figpause(self.data.throttle)
501 else:
503 else:
502 time.sleep(2)
504 time.sleep(2)
503
505
504 def close(self):
506 def close(self):
505 if self.data:
507 if self.data:
506 self.__plot()
508 self.__plot()
507
509
508
510
509 class PlotSpectraData(PlotData):
511 class PlotSpectraData(PlotData):
510 '''
512 '''
511 Plot for Spectra data
513 Plot for Spectra data
512 '''
514 '''
513
515
514 CODE = 'spc'
516 CODE = 'spc'
515 colormap = 'jro'
517 colormap = 'jro'
516
518
517 def setup(self):
519 def setup(self):
518 self.nplots = len(self.data.channels)
520 self.nplots = len(self.data.channels)
519 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
521 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
520 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
522 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
521 self.width = 3.4 * self.ncols
523 self.width = 3.4 * self.ncols
522 self.height = 3 * self.nrows
524 self.height = 3 * self.nrows
523 self.cb_label = 'dB'
525 self.cb_label = 'dB'
524 if self.showprofile:
526 if self.showprofile:
525 self.width += 0.8 * self.ncols
527 self.width += 0.8 * self.ncols
526
528
527 self.ylabel = 'Range [Km]'
529 self.ylabel = 'Range [Km]'
528
530
529 def plot(self):
531 def plot(self):
530 if self.xaxis == "frequency":
532 if self.xaxis == "frequency":
531 x = self.data.xrange[0]
533 x = self.data.xrange[0]
532 self.xlabel = "Frequency (kHz)"
534 self.xlabel = "Frequency (kHz)"
533 elif self.xaxis == "time":
535 elif self.xaxis == "time":
534 x = self.data.xrange[1]
536 x = self.data.xrange[1]
535 self.xlabel = "Time (ms)"
537 self.xlabel = "Time (ms)"
536 else:
538 else:
537 x = self.data.xrange[2]
539 x = self.data.xrange[2]
538 self.xlabel = "Velocity (m/s)"
540 self.xlabel = "Velocity (m/s)"
539
541
540 if self.CODE == 'spc_mean':
542 if self.CODE == 'spc_mean':
541 x = self.data.xrange[2]
543 x = self.data.xrange[2]
542 self.xlabel = "Velocity (m/s)"
544 self.xlabel = "Velocity (m/s)"
543
545
544 self.titles = []
546 self.titles = []
545
547
546 y = self.data.heights
548 y = self.data.heights
547 self.y = y
549 self.y = y
548 z = self.data['spc']
550 z = self.data['spc']
549
551
550 for n, ax in enumerate(self.axes):
552 for n, ax in enumerate(self.axes):
551 noise = self.data['noise'][n][-1]
553 noise = self.data['noise'][n][-1]
552 if self.CODE == 'spc_mean':
554 if self.CODE == 'spc_mean':
553 mean = self.data['mean'][n][-1]
555 mean = self.data['mean'][n][-1]
554 if ax.firsttime:
556 if ax.firsttime:
555 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
557 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
556 self.xmin = self.xmin if self.xmin else -self.xmax
558 self.xmin = self.xmin if self.xmin else -self.xmax
557 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
559 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
558 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
560 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
559 ax.plt = ax.pcolormesh(x, y, z[n].T,
561 ax.plt = ax.pcolormesh(x, y, z[n].T,
560 vmin=self.zmin,
562 vmin=self.zmin,
561 vmax=self.zmax,
563 vmax=self.zmax,
562 cmap=plt.get_cmap(self.colormap)
564 cmap=plt.get_cmap(self.colormap)
563 )
565 )
564
566
565 if self.showprofile:
567 if self.showprofile:
566 ax.plt_profile = self.pf_axes[n].plot(
568 ax.plt_profile = self.pf_axes[n].plot(
567 self.data['rti'][n][-1], y)[0]
569 self.data['rti'][n][-1], y)[0]
568 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,
569 color="k", linestyle="dashed", lw=1)[0]
571 color="k", linestyle="dashed", lw=1)[0]
570 if self.CODE == 'spc_mean':
572 if self.CODE == 'spc_mean':
571 ax.plt_mean = ax.plot(mean, y, color='k')[0]
573 ax.plt_mean = ax.plot(mean, y, color='k')[0]
572 else:
574 else:
573 ax.plt.set_array(z[n].T.ravel())
575 ax.plt.set_array(z[n].T.ravel())
574 if self.showprofile:
576 if self.showprofile:
575 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
577 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
576 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
578 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
577 if self.CODE == 'spc_mean':
579 if self.CODE == 'spc_mean':
578 ax.plt_mean.set_data(mean, y)
580 ax.plt_mean.set_data(mean, y)
579
581
580 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
582 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
581 self.saveTime = self.max_time
583 self.saveTime = self.max_time
582
584
583
585
584 class PlotCrossSpectraData(PlotData):
586 class PlotCrossSpectraData(PlotData):
585
587
586 CODE = 'cspc'
588 CODE = 'cspc'
587 zmin_coh = None
589 zmin_coh = None
588 zmax_coh = None
590 zmax_coh = None
589 zmin_phase = None
591 zmin_phase = None
590 zmax_phase = None
592 zmax_phase = None
591
593
592 def setup(self):
594 def setup(self):
593
595
594 self.ncols = 4
596 self.ncols = 4
595 self.nrows = len(self.data.pairs)
597 self.nrows = len(self.data.pairs)
596 self.nplots = self.nrows * 4
598 self.nplots = self.nrows * 4
597 self.width = 3.4 * self.ncols
599 self.width = 3.4 * self.ncols
598 self.height = 3 * self.nrows
600 self.height = 3 * self.nrows
599 self.ylabel = 'Range [Km]'
601 self.ylabel = 'Range [Km]'
600 self.showprofile = False
602 self.showprofile = False
601
603
602 def plot(self):
604 def plot(self):
603
605
604 if self.xaxis == "frequency":
606 if self.xaxis == "frequency":
605 x = self.data.xrange[0]
607 x = self.data.xrange[0]
606 self.xlabel = "Frequency (kHz)"
608 self.xlabel = "Frequency (kHz)"
607 elif self.xaxis == "time":
609 elif self.xaxis == "time":
608 x = self.data.xrange[1]
610 x = self.data.xrange[1]
609 self.xlabel = "Time (ms)"
611 self.xlabel = "Time (ms)"
610 else:
612 else:
611 x = self.data.xrange[2]
613 x = self.data.xrange[2]
612 self.xlabel = "Velocity (m/s)"
614 self.xlabel = "Velocity (m/s)"
613
615
614 self.titles = []
616 self.titles = []
615
617
616 y = self.data.heights
618 y = self.data.heights
617 self.y = y
619 self.y = y
618 spc = self.data['spc']
620 spc = self.data['spc']
619 cspc = self.data['cspc']
621 cspc = self.data['cspc']
620
622
621 for n in range(self.nrows):
623 for n in range(self.nrows):
622 noise = self.data['noise'][n][-1]
624 noise = self.data['noise'][n][-1]
623 pair = self.data.pairs[n]
625 pair = self.data.pairs[n]
624 ax = self.axes[4 * n]
626 ax = self.axes[4 * n]
625 ax3 = self.axes[4 * n + 3]
627 ax3 = self.axes[4 * n + 3]
626 if ax.firsttime:
628 if ax.firsttime:
627 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
629 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
628 self.xmin = self.xmin if self.xmin else -self.xmax
630 self.xmin = self.xmin if self.xmin else -self.xmax
629 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
631 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
630 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
632 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
631 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
633 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
632 vmin=self.zmin,
634 vmin=self.zmin,
633 vmax=self.zmax,
635 vmax=self.zmax,
634 cmap=plt.get_cmap(self.colormap)
636 cmap=plt.get_cmap(self.colormap)
635 )
637 )
636 else:
638 else:
637 ax.plt.set_array(spc[pair[0]].T.ravel())
639 ax.plt.set_array(spc[pair[0]].T.ravel())
638 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
640 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
639
641
640 ax = self.axes[4 * n + 1]
642 ax = self.axes[4 * n + 1]
641 if ax.firsttime:
643 if ax.firsttime:
642 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
644 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
643 vmin=self.zmin,
645 vmin=self.zmin,
644 vmax=self.zmax,
646 vmax=self.zmax,
645 cmap=plt.get_cmap(self.colormap)
647 cmap=plt.get_cmap(self.colormap)
646 )
648 )
647 else:
649 else:
648 ax.plt.set_array(spc[pair[1]].T.ravel())
650 ax.plt.set_array(spc[pair[1]].T.ravel())
649 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
651 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
650
652
651 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
653 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
652 coh = numpy.abs(out)
654 coh = numpy.abs(out)
653 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
655 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
654
656
655 ax = self.axes[4 * n + 2]
657 ax = self.axes[4 * n + 2]
656 if ax.firsttime:
658 if ax.firsttime:
657 ax.plt = ax.pcolormesh(x, y, coh.T,
659 ax.plt = ax.pcolormesh(x, y, coh.T,
658 vmin=0,
660 vmin=0,
659 vmax=1,
661 vmax=1,
660 cmap=plt.get_cmap(self.colormap_coh)
662 cmap=plt.get_cmap(self.colormap_coh)
661 )
663 )
662 else:
664 else:
663 ax.plt.set_array(coh.T.ravel())
665 ax.plt.set_array(coh.T.ravel())
664 self.titles.append(
666 self.titles.append(
665 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
667 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
666
668
667 ax = self.axes[4 * n + 3]
669 ax = self.axes[4 * n + 3]
668 if ax.firsttime:
670 if ax.firsttime:
669 ax.plt = ax.pcolormesh(x, y, phase.T,
671 ax.plt = ax.pcolormesh(x, y, phase.T,
670 vmin=-180,
672 vmin=-180,
671 vmax=180,
673 vmax=180,
672 cmap=plt.get_cmap(self.colormap_phase)
674 cmap=plt.get_cmap(self.colormap_phase)
673 )
675 )
674 else:
676 else:
675 ax.plt.set_array(phase.T.ravel())
677 ax.plt.set_array(phase.T.ravel())
676 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
678 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
677
679
678 self.saveTime = self.max_time
680 self.saveTime = self.max_time
679
681
680
682
681 class PlotSpectraMeanData(PlotSpectraData):
683 class PlotSpectraMeanData(PlotSpectraData):
682 '''
684 '''
683 Plot for Spectra and Mean
685 Plot for Spectra and Mean
684 '''
686 '''
685 CODE = 'spc_mean'
687 CODE = 'spc_mean'
686 colormap = 'jro'
688 colormap = 'jro'
687
689
688
690
689 class PlotRTIData(PlotData):
691 class PlotRTIData(PlotData):
690 '''
692 '''
691 Plot for RTI data
693 Plot for RTI data
692 '''
694 '''
693
695
694 CODE = 'rti'
696 CODE = 'rti'
695 colormap = 'jro'
697 colormap = 'jro'
696
698
697 def setup(self):
699 def setup(self):
698 self.xaxis = 'time'
700 self.xaxis = 'time'
699 self.ncols = 1
701 self.ncols = 1
700 self.nrows = len(self.data.channels)
702 self.nrows = len(self.data.channels)
701 self.nplots = len(self.data.channels)
703 self.nplots = len(self.data.channels)
702 self.ylabel = 'Range [Km]'
704 self.ylabel = 'Range [Km]'
703 self.cb_label = 'dB'
705 self.cb_label = 'dB'
704 self.titles = ['{} Channel {}'.format(
706 self.titles = ['{} Channel {}'.format(
705 self.CODE.upper(), x) for x in range(self.nrows)]
707 self.CODE.upper(), x) for x in range(self.nrows)]
706
708
707 def plot(self):
709 def plot(self):
708 self.x = self.times
710 self.x = self.times
709 self.y = self.data.heights
711 self.y = self.data.heights
710 self.z = self.data[self.CODE]
712 self.z = self.data[self.CODE]
711 self.z = numpy.ma.masked_invalid(self.z)
713 self.z = numpy.ma.masked_invalid(self.z)
712
714
713 for n, ax in enumerate(self.axes):
715 for n, ax in enumerate(self.axes):
714 x, y, z = self.fill_gaps(*self.decimate())
716 x, y, z = self.fill_gaps(*self.decimate())
715 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)
716 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)
717 if ax.firsttime:
719 if ax.firsttime:
718 ax.plt = ax.pcolormesh(x, y, z[n].T,
720 ax.plt = ax.pcolormesh(x, y, z[n].T,
719 vmin=self.zmin,
721 vmin=self.zmin,
720 vmax=self.zmax,
722 vmax=self.zmax,
721 cmap=plt.get_cmap(self.colormap)
723 cmap=plt.get_cmap(self.colormap)
722 )
724 )
723 if self.showprofile:
725 if self.showprofile:
724 ax.plot_profile = self.pf_axes[n].plot(
726 ax.plot_profile = self.pf_axes[n].plot(
725 self.data['rti'][n][-1], self.y)[0]
727 self.data['rti'][n][-1], self.y)[0]
726 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,
727 color="k", linestyle="dashed", lw=1)[0]
729 color="k", linestyle="dashed", lw=1)[0]
728 else:
730 else:
729 ax.collections.remove(ax.collections[0])
731 ax.collections.remove(ax.collections[0])
730 ax.plt = ax.pcolormesh(x, y, z[n].T,
732 ax.plt = ax.pcolormesh(x, y, z[n].T,
731 vmin=self.zmin,
733 vmin=self.zmin,
732 vmax=self.zmax,
734 vmax=self.zmax,
733 cmap=plt.get_cmap(self.colormap)
735 cmap=plt.get_cmap(self.colormap)
734 )
736 )
735 if self.showprofile:
737 if self.showprofile:
736 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)
737 ax.plot_noise.set_data(numpy.repeat(
739 ax.plot_noise.set_data(numpy.repeat(
738 self.data['noise'][n][-1], len(self.y)), self.y)
740 self.data['noise'][n][-1], len(self.y)), self.y)
739
741
740 self.saveTime = self.min_time
742 self.saveTime = self.min_time
741
743
742
744
743 class PlotCOHData(PlotRTIData):
745 class PlotCOHData(PlotRTIData):
744 '''
746 '''
745 Plot for Coherence data
747 Plot for Coherence data
746 '''
748 '''
747
749
748 CODE = 'coh'
750 CODE = 'coh'
749
751
750 def setup(self):
752 def setup(self):
751 self.xaxis = 'time'
753 self.xaxis = 'time'
752 self.ncols = 1
754 self.ncols = 1
753 self.nrows = len(self.data.pairs)
755 self.nrows = len(self.data.pairs)
754 self.nplots = len(self.data.pairs)
756 self.nplots = len(self.data.pairs)
755 self.ylabel = 'Range [Km]'
757 self.ylabel = 'Range [Km]'
756 if self.CODE == 'coh':
758 if self.CODE == 'coh':
757 self.cb_label = ''
759 self.cb_label = ''
758 self.titles = [
760 self.titles = [
759 '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]
760 else:
762 else:
761 self.cb_label = 'Degrees'
763 self.cb_label = 'Degrees'
762 self.titles = [
764 self.titles = [
763 '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]
764
766
765
767
766 class PlotPHASEData(PlotCOHData):
768 class PlotPHASEData(PlotCOHData):
767 '''
769 '''
768 Plot for Phase map data
770 Plot for Phase map data
769 '''
771 '''
770
772
771 CODE = 'phase'
773 CODE = 'phase'
772 colormap = 'seismic'
774 colormap = 'seismic'
773
775
774
776
775 class PlotNoiseData(PlotData):
777 class PlotNoiseData(PlotData):
776 '''
778 '''
777 Plot for noise
779 Plot for noise
778 '''
780 '''
779
781
780 CODE = 'noise'
782 CODE = 'noise'
781
783
782 def setup(self):
784 def setup(self):
783 self.xaxis = 'time'
785 self.xaxis = 'time'
784 self.ncols = 1
786 self.ncols = 1
785 self.nrows = 1
787 self.nrows = 1
786 self.nplots = 1
788 self.nplots = 1
787 self.ylabel = 'Intensity [dB]'
789 self.ylabel = 'Intensity [dB]'
788 self.titles = ['Noise']
790 self.titles = ['Noise']
789 self.colorbar = False
791 self.colorbar = False
790
792
791 def plot(self):
793 def plot(self):
792
794
793 x = self.times
795 x = self.times
794 xmin = self.min_time
796 xmin = self.min_time
795 xmax = xmin + self.xrange * 60 * 60
797 xmax = xmin + self.xrange * 60 * 60
796 Y = self.data[self.CODE]
798 Y = self.data[self.CODE]
797
799
798 if self.axes[0].firsttime:
800 if self.axes[0].firsttime:
799 for ch in self.data.channels:
801 for ch in self.data.channels:
800 y = Y[ch]
802 y = Y[ch]
801 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))
802 plt.legend()
804 plt.legend()
803 else:
805 else:
804 for ch in self.data.channels:
806 for ch in self.data.channels:
805 y = Y[ch]
807 y = Y[ch]
806 self.axes[0].lines[ch].set_data(x, y)
808 self.axes[0].lines[ch].set_data(x, y)
807
809
808 self.ymin = numpy.nanmin(Y) - 5
810 self.ymin = numpy.nanmin(Y) - 5
809 self.ymax = numpy.nanmax(Y) + 5
811 self.ymax = numpy.nanmax(Y) + 5
810 self.saveTime = self.min_time
812 self.saveTime = self.min_time
811
813
812
814
813 class PlotSNRData(PlotRTIData):
815 class PlotSNRData(PlotRTIData):
814 '''
816 '''
815 Plot for SNR Data
817 Plot for SNR Data
816 '''
818 '''
817
819
818 CODE = 'snr'
820 CODE = 'snr'
819 colormap = 'jet'
821 colormap = 'jet'
820
822
821
823
822 class PlotDOPData(PlotRTIData):
824 class PlotDOPData(PlotRTIData):
823 '''
825 '''
824 Plot for DOPPLER Data
826 Plot for DOPPLER Data
825 '''
827 '''
826
828
827 CODE = 'dop'
829 CODE = 'dop'
828 colormap = 'jet'
830 colormap = 'jet'
829
831
830
832
831 class PlotSkyMapData(PlotData):
833 class PlotSkyMapData(PlotData):
832 '''
834 '''
833 Plot for meteors detection data
835 Plot for meteors detection data
834 '''
836 '''
835
837
836 CODE = 'param'
838 CODE = 'param'
837
839
838 def setup(self):
840 def setup(self):
839
841
840 self.ncols = 1
842 self.ncols = 1
841 self.nrows = 1
843 self.nrows = 1
842 self.width = 7.2
844 self.width = 7.2
843 self.height = 7.2
845 self.height = 7.2
844 self.nplots = 1
846 self.nplots = 1
845 self.xlabel = 'Zonal Zenith Angle (deg)'
847 self.xlabel = 'Zonal Zenith Angle (deg)'
846 self.ylabel = 'Meridional Zenith Angle (deg)'
848 self.ylabel = 'Meridional Zenith Angle (deg)'
847 self.polar = True
849 self.polar = True
848 self.ymin = -180
850 self.ymin = -180
849 self.ymax = 180
851 self.ymax = 180
850 self.colorbar = False
852 self.colorbar = False
851
853
852 def plot(self):
854 def plot(self):
853
855
854 arrayParameters = numpy.concatenate(self.data['param'])
856 arrayParameters = numpy.concatenate(self.data['param'])
855 error = arrayParameters[:, -1]
857 error = arrayParameters[:, -1]
856 indValid = numpy.where(error == 0)[0]
858 indValid = numpy.where(error == 0)[0]
857 finalMeteor = arrayParameters[indValid, :]
859 finalMeteor = arrayParameters[indValid, :]
858 finalAzimuth = finalMeteor[:, 3]
860 finalAzimuth = finalMeteor[:, 3]
859 finalZenith = finalMeteor[:, 4]
861 finalZenith = finalMeteor[:, 4]
860
862
861 x = finalAzimuth * numpy.pi / 180
863 x = finalAzimuth * numpy.pi / 180
862 y = finalZenith
864 y = finalZenith
863
865
864 ax = self.axes[0]
866 ax = self.axes[0]
865
867
866 if ax.firsttime:
868 if ax.firsttime:
867 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
869 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
868 else:
870 else:
869 ax.plot.set_data(x, y)
871 ax.plot.set_data(x, y)
870
872
871 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')
872 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')
873 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,
874 dt2,
876 dt2,
875 len(x))
877 len(x))
876 self.titles[0] = title
878 self.titles[0] = title
877 self.saveTime = self.max_time
879 self.saveTime = self.max_time
878
880
879
881
880 class PlotParamData(PlotRTIData):
882 class PlotParamData(PlotRTIData):
881 '''
883 '''
882 Plot for data_param object
884 Plot for data_param object
883 '''
885 '''
884
886
885 CODE = 'param'
887 CODE = 'param'
886 colormap = 'seismic'
888 colormap = 'seismic'
887
889
888 def setup(self):
890 def setup(self):
889 self.xaxis = 'time'
891 self.xaxis = 'time'
890 self.ncols = 1
892 self.ncols = 1
891 self.nrows = self.data.shape(self.CODE)[0]
893 self.nrows = self.data.shape(self.CODE)[0]
892 self.nplots = self.nrows
894 self.nplots = self.nrows
893 if self.showSNR:
895 if self.showSNR:
894 self.nrows += 1
896 self.nrows += 1
895 self.nplots += 1
897 self.nplots += 1
896
898
897 self.ylabel = 'Height [Km]'
899 self.ylabel = 'Height [Km]'
898 self.titles = self.data.parameters \
900 if not self.titles:
899 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
901 self.titles = self.data.parameters \
900 if self.showSNR:
902 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
901 self.titles.append('SNR')
903 if self.showSNR:
904 self.titles.append('SNR')
902
905
903 def plot(self):
906 def plot(self):
904 self.data.normalize_heights()
907 self.data.normalize_heights()
905 self.x = self.times
908 self.x = self.times
906 self.y = self.data.heights
909 self.y = self.data.heights
907 if self.showSNR:
910 if self.showSNR:
908 self.z = numpy.concatenate(
911 self.z = numpy.concatenate(
909 (self.data[self.CODE], self.data['snr'])
912 (self.data[self.CODE], self.data['snr'])
910 )
913 )
911 else:
914 else:
912 self.z = self.data[self.CODE]
915 self.z = self.data[self.CODE]
913
916
914 self.z = numpy.ma.masked_invalid(self.z)
917 self.z = numpy.ma.masked_invalid(self.z)
915
918
916 for n, ax in enumerate(self.axes):
919 for n, ax in enumerate(self.axes):
917
920
918 x, y, z = self.fill_gaps(*self.decimate())
921 x, y, z = self.fill_gaps(*self.decimate())
919 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(
920 self.z[n])
923 self.z[n])
921 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(
922 self.z[n])
925 self.z[n])
923
926
924 if ax.firsttime:
927 if ax.firsttime:
925 if self.zlimits is not None:
928 if self.zlimits is not None:
926 self.zmin, self.zmax = self.zlimits[n]
929 self.zmin, self.zmax = self.zlimits[n]
927
930
928 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],
929 vmin=self.zmin,
932 vmin=self.zmin,
930 vmax=self.zmax,
933 vmax=self.zmax,
931 cmap=self.cmaps[n]
934 cmap=self.cmaps[n]
932 )
935 )
933 else:
936 else:
934 if self.zlimits is not None:
937 if self.zlimits is not None:
935 self.zmin, self.zmax = self.zlimits[n]
938 self.zmin, self.zmax = self.zlimits[n]
936 ax.collections.remove(ax.collections[0])
939 ax.collections.remove(ax.collections[0])
937 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],
938 vmin=self.zmin,
941 vmin=self.zmin,
939 vmax=self.zmax,
942 vmax=self.zmax,
940 cmap=self.cmaps[n]
943 cmap=self.cmaps[n]
941 )
944 )
942
945
943 self.saveTime = self.min_time
946 self.saveTime = self.min_time
944
947
945
948
946 class PlotOutputData(PlotParamData):
949 class PlotOutputData(PlotParamData):
947 '''
950 '''
948 Plot data_output object
951 Plot data_output object
949 '''
952 '''
950
953
951 CODE = 'output'
954 CODE = 'output'
952 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