##// END OF EJS Templates
Add localtime anf fix pause figs
Juan C. Espinoza -
r1089:d97088881fbc
parent child
Show More
@@ -1,895 +1,922
1 1
2 2 import os
3 3 import time
4 4 import glob
5 5 import datetime
6 6 from multiprocessing import Process
7 7
8 8 import zmq
9 9 import numpy
10 10 import matplotlib
11 11 import matplotlib.pyplot as plt
12 12 from mpl_toolkits.axes_grid1 import make_axes_locatable
13 13 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
14 14
15 15 from schainpy.model.proc.jroproc_base import Operation
16 16 from schainpy.utils import log
17 17
18 18 jet_values = matplotlib.pyplot.get_cmap("jet", 100)(numpy.arange(100))[10:90]
19 19 blu_values = matplotlib.pyplot.get_cmap("seismic_r", 20)(numpy.arange(20))[10:15]
20 20 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list("jro", numpy.vstack((blu_values, jet_values)))
21 21 matplotlib.pyplot.register_cmap(cmap=ncmap)
22 22
23 func = lambda x, pos: '{}'.format(datetime.datetime.utcfromtimestamp(x).strftime('%H:%M'))
24
25 23 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'RdBu_r', 'seismic')]
26 24
25 def figpause(interval):
26 backend = plt.rcParams['backend']
27 if backend in matplotlib.rcsetup.interactive_bk:
28 figManager = matplotlib._pylab_helpers.Gcf.get_active()
29 if figManager is not None:
30 canvas = figManager.canvas
31 if canvas.figure.stale:
32 canvas.draw()
33 canvas.start_event_loop(interval)
34 return
35
27 36 class PlotData(Operation, Process):
28 37 '''
29 38 Base class for Schain plotting operations
30 39 '''
31 40
32 41 CODE = 'Figure'
33 42 colormap = 'jro'
34 43 bgcolor = 'white'
35 44 CONFLATE = False
36 45 __MAXNUMX = 80
37 46 __missing = 1E30
38 47
39 48 def __init__(self, **kwargs):
40 49
41 50 Operation.__init__(self, plot=True, **kwargs)
42 51 Process.__init__(self)
43 52 self.kwargs['code'] = self.CODE
44 53 self.mp = False
45 54 self.data = None
46 55 self.isConfig = False
47 56 self.figures = []
48 57 self.axes = []
49 58 self.cb_axes = []
50 59 self.localtime = kwargs.pop('localtime', True)
51 60 self.show = kwargs.get('show', True)
52 61 self.save = kwargs.get('save', False)
53 62 self.colormap = kwargs.get('colormap', self.colormap)
54 63 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
55 64 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
56 65 self.colormaps = kwargs.get('colormaps', None)
57 66 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
58 67 self.showprofile = kwargs.get('showprofile', False)
59 68 self.title = kwargs.get('wintitle', self.CODE.upper())
60 69 self.cb_label = kwargs.get('cb_label', None)
61 70 self.cb_labels = kwargs.get('cb_labels', None)
62 71 self.xaxis = kwargs.get('xaxis', 'frequency')
63 72 self.zmin = kwargs.get('zmin', None)
64 73 self.zmax = kwargs.get('zmax', None)
65 74 self.zlimits = kwargs.get('zlimits', None)
66 75 self.xmin = kwargs.get('xmin', None)
67 76 self.xmax = kwargs.get('xmax', None)
68 77 self.xrange = kwargs.get('xrange', 24)
69 78 self.ymin = kwargs.get('ymin', None)
70 79 self.ymax = kwargs.get('ymax', None)
71 80 self.xlabel = kwargs.get('xlabel', None)
72 81 self.__MAXNUMY = kwargs.get('decimation', 100)
73 82 self.showSNR = kwargs.get('showSNR', False)
74 83 self.oneFigure = kwargs.get('oneFigure', True)
75 84 self.width = kwargs.get('width', None)
76 85 self.height = kwargs.get('height', None)
77 86 self.colorbar = kwargs.get('colorbar', True)
78 87 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
79 88 self.titles = ['' for __ in range(16)]
89
90 def __fmtTime(self, x, pos):
91 '''
92 '''
93
94 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
80 95
81 96 def __setup(self):
82 97 '''
83 98 Common setup for all figures, here figures and axes are created
84 99 '''
85 100
86 101 self.setup()
87 102
88 103 self.time_label = 'LT' if self.localtime else 'UTC'
104 if self.data.localtime:
105 self.getDateTime = datetime.datetime.fromtimestamp
106 else:
107 self.getDateTime = datetime.datetime.utcfromtimestamp
89 108
90 109 if self.width is None:
91 110 self.width = 8
92 111
93 112 self.figures = []
94 113 self.axes = []
95 114 self.cb_axes = []
96 115 self.pf_axes = []
97 116 self.cmaps = []
98 117
99 118 size = '15%' if self.ncols==1 else '30%'
100 119 pad = '4%' if self.ncols==1 else '8%'
101 120
102 121 if self.oneFigure:
103 122 if self.height is None:
104 123 self.height = 1.4*self.nrows + 1
105 124 fig = plt.figure(figsize=(self.width, self.height),
106 125 edgecolor='k',
107 126 facecolor='w')
108 127 self.figures.append(fig)
109 128 for n in range(self.nplots):
110 129 ax = fig.add_subplot(self.nrows, self.ncols, n+1)
111 130 ax.tick_params(labelsize=8)
112 131 ax.firsttime = True
113 132 ax.index = 0
114 133 ax.press = None
115 134 self.axes.append(ax)
116 135 if self.showprofile:
117 136 cax = self.__add_axes(ax, size=size, pad=pad)
118 137 cax.tick_params(labelsize=8)
119 138 self.pf_axes.append(cax)
120 139 else:
121 140 if self.height is None:
122 141 self.height = 3
123 142 for n in range(self.nplots):
124 143 fig = plt.figure(figsize=(self.width, self.height),
125 144 edgecolor='k',
126 145 facecolor='w')
127 146 ax = fig.add_subplot(1, 1, 1)
128 147 ax.tick_params(labelsize=8)
129 148 ax.firsttime = True
130 149 ax.index = 0
131 150 ax.press = None
132 151 self.figures.append(fig)
133 152 self.axes.append(ax)
134 153 if self.showprofile:
135 154 cax = self.__add_axes(ax, size=size, pad=pad)
136 155 cax.tick_params(labelsize=8)
137 156 self.pf_axes.append(cax)
138 157
139 158 for n in range(self.nrows):
140 159 if self.colormaps is not None:
141 160 cmap = plt.get_cmap(self.colormaps[n])
142 161 else:
143 162 cmap = plt.get_cmap(self.colormap)
144 163 cmap.set_bad(self.bgcolor, 1.)
145 164 self.cmaps.append(cmap)
146 165
147 166 for fig in self.figures:
148 167 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
149 168 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
150 169 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
151 170 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
152 171 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
172 if self.show:
173 fig.show()
153 174
154 175 def OnKeyPress(self, event):
155 176 '''
156 177 Event for pressing keys (up, down) change colormap
157 178 '''
158 179 ax = event.inaxes
159 180 if ax in self.axes:
160 181 if event.key == 'down':
161 182 ax.index += 1
162 183 elif event.key == 'up':
163 184 ax.index -= 1
164 185 if ax.index < 0:
165 186 ax.index = len(CMAPS) - 1
166 187 elif ax.index == len(CMAPS):
167 188 ax.index = 0
168 cmap = CMAPS[ax.index]
189 cmap = CMAPS[ax.index]
169 190 ax.cbar.set_cmap(cmap)
170 191 ax.cbar.draw_all()
171 192 ax.plt.set_cmap(cmap)
172 193 ax.cbar.patch.figure.canvas.draw()
194 self.colormap = cmap.name
173 195
174 196 def OnBtnScroll(self, event):
175 197 '''
176 198 Event for scrolling, scale figure
177 199 '''
178 200 cb_ax = event.inaxes
179 201 if cb_ax in [ax.cbar.ax for ax in self.axes]:
180 202 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
181 203 pt = ax.cbar.ax.bbox.get_points()[:,1]
182 204 nrm = ax.cbar.norm
183 205 vmin, vmax, p0, p1, pS = (nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
184 206 scale = 2 if event.step == 1 else 0.5
185 207 point = vmin + (vmax - vmin) / (p1 - p0)*(pS - p0)
186 208 ax.cbar.norm.vmin = point - scale*(point - vmin)
187 209 ax.cbar.norm.vmax = point - scale*(point - vmax)
188 210 ax.plt.set_norm(ax.cbar.norm)
189 211 ax.cbar.draw_all()
190 212 ax.cbar.patch.figure.canvas.draw()
191 213
192 214 def onBtnPress(self, event):
193 215 '''
194 216 Event for mouse button press
195 217 '''
196 218 cb_ax = event.inaxes
197 219 if cb_ax is None:
198 220 return
199 221
200 222 if cb_ax in [ax.cbar.ax for ax in self.axes]:
201 223 cb_ax.press = event.x, event.y
202 224 else:
203 225 cb_ax.press = None
204 226
205 227 def onMotion(self, event):
206 228 '''
207 229 Event for move inside colorbar
208 230 '''
209 231 cb_ax = event.inaxes
210 232 if cb_ax is None:
211 233 return
212 234 if cb_ax not in [ax.cbar.ax for ax in self.axes]:
213 235 return
214 236 if cb_ax.press is None:
215 237 return
216 238
217 239 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
218 240 xprev, yprev = cb_ax.press
219 241 dx = event.x - xprev
220 242 dy = event.y - yprev
221 243 cb_ax.press = event.x, event.y
222 244 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
223 245 perc = 0.03
224 246
225 247 if event.button == 1:
226 248 ax.cbar.norm.vmin -= (perc*scale)*numpy.sign(dy)
227 249 ax.cbar.norm.vmax -= (perc*scale)*numpy.sign(dy)
228 250 elif event.button == 3:
229 251 ax.cbar.norm.vmin -= (perc*scale)*numpy.sign(dy)
230 252 ax.cbar.norm.vmax += (perc*scale)*numpy.sign(dy)
231 253
232 254 ax.cbar.draw_all()
233 255 ax.plt.set_norm(ax.cbar.norm)
234 256 ax.cbar.patch.figure.canvas.draw()
235 257
236 258 def onBtnRelease(self, event):
237 259 '''
238 260 Event for mouse button release
239 261 '''
240 262 cb_ax = event.inaxes
241 263 if cb_ax is not None:
242 264 cb_ax.press = None
243 265
244 266 def __add_axes(self, ax, size='30%', pad='8%'):
245 267 '''
246 268 Add new axes to the given figure
247 269 '''
248 270 divider = make_axes_locatable(ax)
249 271 nax = divider.new_horizontal(size=size, pad=pad)
250 272 ax.figure.add_axes(nax)
251 273 return nax
252 274
253 275 self.setup()
254 276
255 277 def setup(self):
256 278 '''
257 279 This method should be implemented in the child class, the following
258 280 attributes should be set:
259 281
260 282 self.nrows: number of rows
261 283 self.ncols: number of cols
262 284 self.nplots: number of plots (channels or pairs)
263 285 self.ylabel: label for Y axes
264 286 self.titles: list of axes title
265 287
266 288 '''
267 289 raise(NotImplementedError, 'Implement this method in child class')
268 290
269 291 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
270 292 '''
271 293 Create a masked array for missing data
272 294 '''
273 295 if x_buffer.shape[0] < 2:
274 296 return x_buffer, y_buffer, z_buffer
275 297
276 298 deltas = x_buffer[1:] - x_buffer[0:-1]
277 299 x_median = numpy.median(deltas)
278 300
279 301 index = numpy.where(deltas > 5*x_median)
280 302
281 303 if len(index[0]) != 0:
282 304 z_buffer[::, index[0], ::] = self.__missing
283 305 z_buffer = numpy.ma.masked_inside(z_buffer,
284 306 0.99*self.__missing,
285 307 1.01*self.__missing)
286 308
287 309 return x_buffer, y_buffer, z_buffer
288 310
289 311 def decimate(self):
290 312
291 313 # dx = int(len(self.x)/self.__MAXNUMX) + 1
292 314 dy = int(len(self.y)/self.__MAXNUMY) + 1
293 315
294 316 # x = self.x[::dx]
295 317 x = self.x
296 318 y = self.y[::dy]
297 319 z = self.z[::, ::, ::dy]
298 320
299 321 return x, y, z
300 322
301 323 def format(self):
302 324 '''
303 325 Set min and max values, labels, ticks and titles
304 326 '''
305 327
306 328 if self.xmin is None:
307 329 xmin = self.min_time
308 330 else:
309 331 if self.xaxis is 'time':
310 dt = datetime.datetime.utcfromtimestamp(self.min_time)
332 dt = self.getDateTime(self.min_time)
311 333 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) - datetime.datetime(1970, 1, 1)).total_seconds()
334 if self.data.localtime:
335 xmin += time.timezone
312 336 else:
313 337 xmin = self.xmin
314 338
315 339 if self.xmax is None:
316 340 xmax = xmin+self.xrange*60*60
317 341 else:
318 342 if self.xaxis is 'time':
319 dt = datetime.datetime.utcfromtimestamp(self.min_time)
343 dt = self.getDateTime(self.max_time)
320 344 xmax = (dt.replace(hour=int(self.xmax), minute=0, second=0) - datetime.datetime(1970, 1, 1)).total_seconds()
345 if self.data.localtime:
346 xmax += time.timezone
321 347 else:
322 348 xmax = self.xmax
323 349
324 350 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
325 351 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
326 352
327 353 Y = numpy.array([10, 20, 50, 100, 200, 500, 1000, 2000])
328 354 i = 1 if numpy.where(ymax < Y)[0][0] < 0 else numpy.where(ymax < Y)[0][0]
329 355 ystep = Y[i-1]/5
330 356
331 357 for n, ax in enumerate(self.axes):
332 358 if ax.firsttime:
333 359 ax.set_facecolor(self.bgcolor)
334 360 ax.yaxis.set_major_locator(MultipleLocator(ystep))
335 361 if self.xaxis is 'time':
336 ax.xaxis.set_major_formatter(FuncFormatter(func))
362 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
337 363 ax.xaxis.set_major_locator(LinearLocator(9))
338 364 if self.xlabel is not None:
339 365 ax.set_xlabel(self.xlabel)
340 366 ax.set_ylabel(self.ylabel)
341 367 ax.firsttime = False
342 368 if self.showprofile:
343 369 self.pf_axes[n].set_ylim(ymin, ymax)
344 370 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
345 371 self.pf_axes[n].set_xlabel('dB')
346 372 self.pf_axes[n].grid(b=True, axis='x')
347 373 [tick.set_visible(False) for tick in self.pf_axes[n].get_yticklabels()]
348 374 if self.colorbar:
349 375 ax.cbar = plt.colorbar(ax.plt, ax=ax, pad=0.02, aspect=10)
350 376 ax.cbar.ax.tick_params(labelsize=8)
351 377 ax.cbar.ax.press = None
352 378 if self.cb_label:
353 379 ax.cbar.set_label(self.cb_label, size=8)
354 380 elif self.cb_labels:
355 381 ax.cbar.set_label(self.cb_labels[n], size=8)
356 382
357 383 ax.set_title('{} - {} {}'.format(
358 384 self.titles[n],
359 datetime.datetime.utcfromtimestamp(self.max_time).strftime('%H:%M:%S'),
385 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
360 386 self.time_label),
361 387 size=8)
362 388 ax.set_xlim(xmin, xmax)
363 389 ax.set_ylim(ymin, ymax)
364 390
365 391 def __plot(self):
366 392 '''
367 393 '''
368 394 log.success('Plotting', self.name)
369 395
370 396 self.plot()
371 397 self.format()
372 398
373 399 for n, fig in enumerate(self.figures):
374 400 if self.nrows == 0 or self.nplots == 0:
375 401 log.warning('No data', self.name)
376 continue
377 if self.show:
378 fig.show()
402 continue
379 403
380 404 fig.tight_layout()
381 405 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
382 datetime.datetime.utcfromtimestamp(self.max_time).strftime('%Y/%m/%d')))
406 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
383 407 # fig.canvas.draw()
384 408
385 409 if self.save and self.data.ended:
386 410 channels = range(self.nrows)
387 411 if self.oneFigure:
388 412 label = ''
389 413 else:
390 414 label = '_{}'.format(channels[n])
391 415 figname = os.path.join(
392 416 self.save,
393 417 '{}{}_{}.png'.format(
394 418 self.CODE,
395 419 label,
396 datetime.datetime.utcfromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')
420 self.getDateTime(self.saveTime).strftime('%y%m%d_%H%M%S')
397 421 )
398 422 )
399 423 print 'Saving figure: {}'.format(figname)
400 424 fig.savefig(figname)
401 425
402 426 def plot(self):
403 427 '''
404 428 '''
405 429 raise(NotImplementedError, 'Implement this method in child class')
406 430
407 431 def run(self):
408 432
409 433 log.success('Starting', self.name)
410 434
411 435 context = zmq.Context()
412 436 receiver = context.socket(zmq.SUB)
413 437 receiver.setsockopt(zmq.SUBSCRIBE, '')
414 438 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
415 439
416 440 if 'server' in self.kwargs['parent']:
417 441 receiver.connect('ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
418 442 else:
419 443 receiver.connect("ipc:///tmp/zmq.plots")
420 444
421 445 while True:
422 446 try:
423 447 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
424
425 if self.localtime:
448 if self.data.localtime and self.localtime:
449 self.times = self.data.times
450 elif self.data.localtime and not self.localtime:
451 self.times = self.data.times + time.timezone
452 elif not self.data.localtime and self.localtime:
426 453 self.times = self.data.times - time.timezone
427 454 else:
428 455 self.times = self.data.times
429
456
430 457 self.min_time = self.times[0]
431 458 self.max_time = self.times[-1]
432 459
433 460 if self.isConfig is False:
434 461 self.__setup()
435 462 self.isConfig = True
436 463
437 464 self.__plot()
438 465
439 466 except zmq.Again as e:
440 467 log.log('Waiting for data...')
441 468 if self.data:
442 plt.pause(self.data.throttle)
469 figpause(self.data.throttle)
443 470 else:
444 471 time.sleep(2)
445 472
446 473 def close(self):
447 474 if self.data:
448 475 self.__plot()
449 476
450 477 class PlotSpectraData(PlotData):
451 478 '''
452 479 Plot for Spectra data
453 480 '''
454 481
455 482 CODE = 'spc'
456 483 colormap = 'jro'
457 484
458 485 def setup(self):
459 486 self.nplots = len(self.data.channels)
460 487 self.ncols = int(numpy.sqrt(self.nplots)+ 0.9)
461 488 self.nrows = int((1.0*self.nplots/self.ncols) + 0.9)
462 489 self.width = 3.4*self.ncols
463 490 self.height = 3*self.nrows
464 491 self.cb_label = 'dB'
465 492 if self.showprofile:
466 493 self.width += 0.8*self.ncols
467 494
468 495 self.ylabel = 'Range [Km]'
469 496
470 497 def plot(self):
471 498 if self.xaxis == "frequency":
472 499 x = self.data.xrange[0]
473 500 self.xlabel = "Frequency (kHz)"
474 501 elif self.xaxis == "time":
475 502 x = self.data.xrange[1]
476 503 self.xlabel = "Time (ms)"
477 504 else:
478 505 x = self.data.xrange[2]
479 506 self.xlabel = "Velocity (m/s)"
480 507
481 508 if self.CODE == 'spc_mean':
482 509 x = self.data.xrange[2]
483 510 self.xlabel = "Velocity (m/s)"
484 511
485 512 self.titles = []
486 513
487 514 y = self.data.heights
488 515 self.y = y
489 516 z = self.data['spc']
490 517
491 518 for n, ax in enumerate(self.axes):
492 519 noise = self.data['noise'][n][-1]
493 520 if self.CODE == 'spc_mean':
494 521 mean = self.data['mean'][n][-1]
495 522 if ax.firsttime:
496 523 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
497 524 self.xmin = self.xmin if self.xmin else -self.xmax
498 525 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
499 526 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
500 527 ax.plt = ax.pcolormesh(x, y, z[n].T,
501 528 vmin=self.zmin,
502 529 vmax=self.zmax,
503 530 cmap=plt.get_cmap(self.colormap)
504 531 )
505 532
506 533 if self.showprofile:
507 534 ax.plt_profile= self.pf_axes[n].plot(self.data['rti'][n][-1], y)[0]
508 535 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
509 536 color="k", linestyle="dashed", lw=1)[0]
510 537 if self.CODE == 'spc_mean':
511 538 ax.plt_mean = ax.plot(mean, y, color='k')[0]
512 539 else:
513 540 ax.plt.set_array(z[n].T.ravel())
514 541 if self.showprofile:
515 542 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
516 543 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
517 544 if self.CODE == 'spc_mean':
518 545 ax.plt_mean.set_data(mean, y)
519 546
520 547 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
521 548 self.saveTime = self.max_time
522 549
523 550
524 551 class PlotCrossSpectraData(PlotData):
525 552
526 553 CODE = 'cspc'
527 554 zmin_coh = None
528 555 zmax_coh = None
529 556 zmin_phase = None
530 557 zmax_phase = None
531 558
532 559 def setup(self):
533 560
534 561 self.ncols = 4
535 562 self.nrows = len(self.data.pairs)
536 563 self.nplots = self.nrows*4
537 564 self.width = 3.4*self.ncols
538 565 self.height = 3*self.nrows
539 566 self.ylabel = 'Range [Km]'
540 567 self.showprofile = False
541 568
542 569 def plot(self):
543 570
544 571 if self.xaxis == "frequency":
545 572 x = self.data.xrange[0]
546 573 self.xlabel = "Frequency (kHz)"
547 574 elif self.xaxis == "time":
548 575 x = self.data.xrange[1]
549 576 self.xlabel = "Time (ms)"
550 577 else:
551 578 x = self.data.xrange[2]
552 579 self.xlabel = "Velocity (m/s)"
553 580
554 581 self.titles = []
555 582
556 583 y = self.data.heights
557 584 self.y = y
558 585 spc = self.data['spc']
559 586 cspc = self.data['cspc']
560 587
561 588 for n in range(self.nrows):
562 589 noise = self.data['noise'][n][-1]
563 590 pair = self.data.pairs[n]
564 591 ax = self.axes[4*n]
565 592 ax3 = self.axes[4*n+3]
566 593 if ax.firsttime:
567 594 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
568 595 self.xmin = self.xmin if self.xmin else -self.xmax
569 596 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
570 597 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
571 598 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
572 599 vmin=self.zmin,
573 600 vmax=self.zmax,
574 601 cmap=plt.get_cmap(self.colormap)
575 602 )
576 603 else:
577 604 ax.plt.set_array(spc[pair[0]].T.ravel())
578 605 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
579 606
580 607 ax = self.axes[4*n+1]
581 608 if ax.firsttime:
582 609 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
583 610 vmin=self.zmin,
584 611 vmax=self.zmax,
585 612 cmap=plt.get_cmap(self.colormap)
586 613 )
587 614 else:
588 615 ax.plt.set_array(spc[pair[1]].T.ravel())
589 616 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
590 617
591 618 out = cspc[n]/numpy.sqrt(spc[pair[0]]*spc[pair[1]])
592 619 coh = numpy.abs(out)
593 620 phase = numpy.arctan2(out.imag, out.real)*180/numpy.pi
594 621
595 622 ax = self.axes[4*n+2]
596 623 if ax.firsttime:
597 624 ax.plt = ax.pcolormesh(x, y, coh.T,
598 625 vmin=0,
599 626 vmax=1,
600 627 cmap=plt.get_cmap(self.colormap_coh)
601 628 )
602 629 else:
603 630 ax.plt.set_array(coh.T.ravel())
604 631 self.titles.append('Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
605 632
606 633 ax = self.axes[4*n+3]
607 634 if ax.firsttime:
608 635 ax.plt = ax.pcolormesh(x, y, phase.T,
609 636 vmin=-180,
610 637 vmax=180,
611 638 cmap=plt.get_cmap(self.colormap_phase)
612 639 )
613 640 else:
614 641 ax.plt.set_array(phase.T.ravel())
615 642 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
616 643
617 644 self.saveTime = self.max_time
618 645
619 646
620 647 class PlotSpectraMeanData(PlotSpectraData):
621 648 '''
622 649 Plot for Spectra and Mean
623 650 '''
624 651 CODE = 'spc_mean'
625 652 colormap = 'jro'
626 653
627 654
628 655 class PlotRTIData(PlotData):
629 656 '''
630 657 Plot for RTI data
631 658 '''
632 659
633 660 CODE = 'rti'
634 661 colormap = 'jro'
635 662
636 663 def setup(self):
637 664 self.xaxis = 'time'
638 665 self.ncols = 1
639 666 self.nrows = len(self.data.channels)
640 667 self.nplots = len(self.data.channels)
641 668 self.ylabel = 'Range [Km]'
642 669 self.cb_label = 'dB'
643 670 self.titles = ['{} Channel {}'.format(self.CODE.upper(), x) for x in range(self.nrows)]
644 671
645 672 def plot(self):
646 673 self.x = self.times
647 674 self.y = self.data.heights
648 675 self.z = self.data[self.CODE]
649 676 self.z = numpy.ma.masked_invalid(self.z)
650 677
651 678 for n, ax in enumerate(self.axes):
652 679 x, y, z = self.fill_gaps(*self.decimate())
653 680 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
654 681 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
655 682 if ax.firsttime:
656 683 ax.plt = ax.pcolormesh(x, y, z[n].T,
657 684 vmin=self.zmin,
658 685 vmax=self.zmax,
659 686 cmap=plt.get_cmap(self.colormap)
660 687 )
661 688 if self.showprofile:
662 689 ax.plot_profile= self.pf_axes[n].plot(self.data['rti'][n][-1], self.y)[0]
663 690 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
664 691 color="k", linestyle="dashed", lw=1)[0]
665 692 else:
666 693 ax.collections.remove(ax.collections[0])
667 694 ax.plt = ax.pcolormesh(x, y, z[n].T,
668 695 vmin=self.zmin,
669 696 vmax=self.zmax,
670 697 cmap=plt.get_cmap(self.colormap)
671 698 )
672 699 if self.showprofile:
673 700 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
674 701 ax.plot_noise.set_data(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y)
675 702
676 703 self.saveTime = self.min_time
677 704
678 705
679 706 class PlotCOHData(PlotRTIData):
680 707 '''
681 708 Plot for Coherence data
682 709 '''
683 710
684 711 CODE = 'coh'
685 712
686 713 def setup(self):
687 714 self.xaxis = 'time'
688 715 self.ncols = 1
689 716 self.nrows = len(self.data.pairs)
690 717 self.nplots = len(self.data.pairs)
691 718 self.ylabel = 'Range [Km]'
692 719 if self.CODE == 'coh':
693 720 self.cb_label = ''
694 721 self.titles = ['Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
695 722 else:
696 723 self.cb_label = 'Degrees'
697 724 self.titles = ['Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
698 725
699 726
700 727 class PlotPHASEData(PlotCOHData):
701 728 '''
702 729 Plot for Phase map data
703 730 '''
704 731
705 732 CODE = 'phase'
706 733 colormap = 'seismic'
707 734
708 735
709 736 class PlotNoiseData(PlotData):
710 737 '''
711 738 Plot for noise
712 739 '''
713 740
714 741 CODE = 'noise'
715 742
716 743 def setup(self):
717 744 self.xaxis = 'time'
718 745 self.ncols = 1
719 746 self.nrows = 1
720 747 self.nplots = 1
721 748 self.ylabel = 'Intensity [dB]'
722 749 self.titles = ['Noise']
723 750 self.colorbar = False
724 751
725 752 def plot(self):
726 753
727 754 x = self.times
728 755 xmin = self.min_time
729 756 xmax = xmin+self.xrange*60*60
730 757 Y = self.data[self.CODE]
731 758
732 759 if self.axes[0].firsttime:
733 760 for ch in self.data.channels:
734 761 y = Y[ch]
735 762 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
736 763 plt.legend()
737 764 else:
738 765 for ch in self.data.channels:
739 766 y = Y[ch]
740 767 self.axes[0].lines[ch].set_data(x, y)
741 768
742 769 self.ymin = numpy.nanmin(Y) - 5
743 770 self.ymax = numpy.nanmax(Y) + 5
744 771 self.saveTime = self.min_time
745 772
746 773
747 774 class PlotSNRData(PlotRTIData):
748 775 '''
749 776 Plot for SNR Data
750 777 '''
751 778
752 779 CODE = 'snr'
753 780 colormap = 'jet'
754 781
755 782
756 783 class PlotDOPData(PlotRTIData):
757 784 '''
758 785 Plot for DOPPLER Data
759 786 '''
760 787
761 788 CODE = 'dop'
762 789 colormap = 'jet'
763 790
764 791
765 792 class PlotSkyMapData(PlotData):
766 793 '''
767 794 Plot for meteors detection data
768 795 '''
769 796
770 797 CODE = 'met'
771 798
772 799 def setup(self):
773 800
774 801 self.ncols = 1
775 802 self.nrows = 1
776 803 self.width = 7.2
777 804 self.height = 7.2
778 805
779 806 self.xlabel = 'Zonal Zenith Angle (deg)'
780 807 self.ylabel = 'Meridional Zenith Angle (deg)'
781 808
782 809 if self.figure is None:
783 810 self.figure = plt.figure(figsize=(self.width, self.height),
784 811 edgecolor='k',
785 812 facecolor='w')
786 813 else:
787 814 self.figure.clf()
788 815
789 816 self.ax = plt.subplot2grid((self.nrows, self.ncols), (0, 0), 1, 1, polar=True)
790 817 self.ax.firsttime = True
791 818
792 819
793 820 def plot(self):
794 821
795 822 arrayParameters = numpy.concatenate([self.data['param'][t] for t in self.times])
796 823 error = arrayParameters[:,-1]
797 824 indValid = numpy.where(error == 0)[0]
798 825 finalMeteor = arrayParameters[indValid,:]
799 826 finalAzimuth = finalMeteor[:,3]
800 827 finalZenith = finalMeteor[:,4]
801 828
802 829 x = finalAzimuth*numpy.pi/180
803 830 y = finalZenith
804 831
805 832 if self.ax.firsttime:
806 833 self.ax.plot = self.ax.plot(x, y, 'bo', markersize=5)[0]
807 834 self.ax.set_ylim(0,90)
808 835 self.ax.set_yticks(numpy.arange(0,90,20))
809 836 self.ax.set_xlabel(self.xlabel)
810 837 self.ax.set_ylabel(self.ylabel)
811 838 self.ax.yaxis.labelpad = 40
812 839 self.ax.firsttime = False
813 840 else:
814 841 self.ax.plot.set_data(x, y)
815 842
816 843
817 dt1 = datetime.datetime.utcfromtimestamp(self.min_time).strftime('%y/%m/%d %H:%M:%S')
818 dt2 = datetime.datetime.utcfromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')
844 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
845 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
819 846 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
820 847 dt2,
821 848 len(x))
822 849 self.ax.set_title(title, size=8)
823 850
824 851 self.saveTime = self.max_time
825 852
826 853 class PlotParamData(PlotRTIData):
827 854 '''
828 855 Plot for data_param object
829 856 '''
830 857
831 858 CODE = 'param'
832 859 colormap = 'seismic'
833 860
834 861 def setup(self):
835 862 self.xaxis = 'time'
836 863 self.ncols = 1
837 864 self.nrows = self.data.shape(self.CODE)[0]
838 865 self.nplots = self.nrows
839 866 if self.showSNR:
840 867 self.nrows += 1
841 868 self.nplots += 1
842 869
843 870 self.ylabel = 'Height [Km]'
844 871 self.titles = self.data.parameters \
845 872 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
846 873 if self.showSNR:
847 874 self.titles.append('SNR')
848 875
849 876 def plot(self):
850 877 self.data.normalize_heights()
851 878 self.x = self.times
852 879 self.y = self.data.heights
853 880 if self.showSNR:
854 881 self.z = numpy.concatenate(
855 882 (self.data[self.CODE], self.data['snr'])
856 883 )
857 884 else:
858 885 self.z = self.data[self.CODE]
859 886
860 887 self.z = numpy.ma.masked_invalid(self.z)
861 888
862 889 for n, ax in enumerate(self.axes):
863 890
864 891 x, y, z = self.fill_gaps(*self.decimate())
865 892 self.zmax = self.zmax if self.zmax is not None else numpy.max(self.z[n])
866 893 self.zmin = self.zmin if self.zmin is not None else numpy.min(self.z[n])
867 894
868 895 if ax.firsttime:
869 896 if self.zlimits is not None:
870 897 self.zmin, self.zmax = self.zlimits[n]
871 898
872 899 ax.plt = ax.pcolormesh(x, y, z[n].T*self.factors[n],
873 900 vmin=self.zmin,
874 901 vmax=self.zmax,
875 902 cmap=self.cmaps[n]
876 903 )
877 904 else:
878 905 if self.zlimits is not None:
879 906 self.zmin, self.zmax = self.zlimits[n]
880 907 ax.collections.remove(ax.collections[0])
881 908 ax.plt = ax.pcolormesh(x, y, z[n].T*self.factors[n],
882 909 vmin=self.zmin,
883 910 vmax=self.zmax,
884 911 cmap=self.cmaps[n]
885 912 )
886 913
887 914 self.saveTime = self.min_time
888 915
889 916 class PlotOutputData(PlotParamData):
890 917 '''
891 918 Plot data_output object
892 919 '''
893 920
894 921 CODE = 'output'
895 922 colormap = 'seismic'
@@ -1,607 +1,619
1 1 '''
2 2 @author: Juan C. Espinoza
3 3 '''
4 4
5 5 import time
6 6 import json
7 7 import numpy
8 8 import paho.mqtt.client as mqtt
9 9 import zmq
10 10 import datetime
11 11 from zmq.utils.monitor import recv_monitor_message
12 12 from functools import wraps
13 13 from threading import Thread
14 14 from multiprocessing import Process
15 15
16 16 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit
17 17 from schainpy.model.data.jrodata import JROData
18 18 from schainpy.utils import log
19 19
20 20 MAXNUMX = 100
21 21 MAXNUMY = 100
22 22
23 23 class PrettyFloat(float):
24 24 def __repr__(self):
25 25 return '%.2f' % self
26 26
27 27 def roundFloats(obj):
28 28 if isinstance(obj, list):
29 29 return map(roundFloats, obj)
30 30 elif isinstance(obj, float):
31 31 return round(obj, 2)
32 32
33 33 def decimate(z, MAXNUMY):
34 34 dy = int(len(z[0])/MAXNUMY) + 1
35 35
36 36 return z[::, ::dy]
37 37
38 38 class throttle(object):
39 39 '''
40 40 Decorator that prevents a function from being called more than once every
41 41 time period.
42 42 To create a function that cannot be called more than once a minute, but
43 43 will sleep until it can be called:
44 44 @throttle(minutes=1)
45 45 def foo():
46 46 pass
47 47
48 48 for i in range(10):
49 49 foo()
50 50 print "This function has run %s times." % i
51 51 '''
52 52
53 53 def __init__(self, seconds=0, minutes=0, hours=0):
54 54 self.throttle_period = datetime.timedelta(
55 55 seconds=seconds, minutes=minutes, hours=hours
56 56 )
57 57
58 58 self.time_of_last_call = datetime.datetime.min
59 59
60 60 def __call__(self, fn):
61 61 @wraps(fn)
62 62 def wrapper(*args, **kwargs):
63 63 now = datetime.datetime.now()
64 64 time_since_last_call = now - self.time_of_last_call
65 65 time_left = self.throttle_period - time_since_last_call
66 66
67 67 if time_left > datetime.timedelta(seconds=0):
68 68 return
69 69
70 70 self.time_of_last_call = datetime.datetime.now()
71 71 return fn(*args, **kwargs)
72 72
73 73 return wrapper
74 74
75 75 class Data(object):
76 76 '''
77 77 Object to hold data to be plotted
78 78 '''
79 79
80 80 def __init__(self, plottypes, throttle_value):
81 81 self.plottypes = plottypes
82 82 self.throttle = throttle_value
83 83 self.ended = False
84 self.__times = []
84 self.localtime = False
85 self.__times = []
86 self.__heights = []
85 87
86 88 def __str__(self):
87 89 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
88 90 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
89 91
90 92 def __len__(self):
91 93 return len(self.__times)
92 94
93 95 def __getitem__(self, key):
94 96 if key not in self.data:
95 97 raise KeyError(log.error('Missing key: {}'.format(key)))
96 98
97 99 if 'spc' in key:
98 100 ret = self.data[key]
99 101 else:
100 102 ret = numpy.array([self.data[key][x] for x in self.times])
101 103 if ret.ndim > 1:
102 104 ret = numpy.swapaxes(ret, 0, 1)
103 105 return ret
104 106
105 107 def setup(self):
106 108 '''
107 109 Configure object
108 110 '''
109 111
110 112 self.ended = False
111 113 self.data = {}
112 114 self.__times = []
113 115 self.__heights = []
114 116 self.__all_heights = set()
115 117 for plot in self.plottypes:
116 118 if 'snr' in plot:
117 119 plot = 'snr'
118 120 self.data[plot] = {}
119 121
120 122 def shape(self, key):
121 123 '''
122 124 Get the shape of the one-element data for the given key
123 125 '''
124 126
125 127 if len(self.data[key]):
126 128 if 'spc' in key:
127 129 return self.data[key].shape
128 130 return self.data[key][self.__times[0]].shape
129 131 return (0,)
130 132
131 133 def update(self, dataOut):
132 134 '''
133 135 Update data object with new dataOut
134 136 '''
135 137
136 138 tm = dataOut.utctime
137 139 if tm in self.__times:
138 140 return
139 141
140 142 self.parameters = getattr(dataOut, 'parameters', [])
141 143 self.pairs = dataOut.pairsList
142 144 self.channels = dataOut.channelList
143 145 self.interval = dataOut.getTimeInterval()
146 self.localtime = dataOut.useLocalTime
144 147 if 'spc' in self.plottypes or 'cspc' in self.plottypes:
145 148 self.xrange = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
146 149 self.__heights.append(dataOut.heightList)
147 150 self.__all_heights.update(dataOut.heightList)
148 151 self.__times.append(tm)
149 152
150 153 for plot in self.plottypes:
151 154 if plot == 'spc':
152 155 z = dataOut.data_spc/dataOut.normFactor
153 156 self.data[plot] = 10*numpy.log10(z)
154 157 if plot == 'cspc':
155 158 self.data[plot] = dataOut.data_cspc
156 159 if plot == 'noise':
157 160 self.data[plot][tm] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
158 161 if plot == 'rti':
159 162 self.data[plot][tm] = dataOut.getPower()
160 163 if plot == 'snr_db':
161 164 self.data['snr'][tm] = dataOut.data_SNR
162 165 if plot == 'snr':
163 166 self.data[plot][tm] = 10*numpy.log10(dataOut.data_SNR)
164 167 if plot == 'dop':
165 168 self.data[plot][tm] = 10*numpy.log10(dataOut.data_DOP)
166 169 if plot == 'mean':
167 170 self.data[plot][tm] = dataOut.data_MEAN
168 171 if plot == 'std':
169 172 self.data[plot][tm] = dataOut.data_STD
170 173 if plot == 'coh':
171 174 self.data[plot][tm] = dataOut.getCoherence()
172 175 if plot == 'phase':
173 176 self.data[plot][tm] = dataOut.getCoherence(phase=True)
174 177 if plot == 'output':
175 178 self.data[plot][tm] = dataOut.data_output
176 179 if plot == 'param':
177 180 self.data[plot][tm] = dataOut.data_param
178 181
179 182 def normalize_heights(self):
180 183 '''
181 184 Ensure same-dimension of the data for different heighList
182 185 '''
183 186
184 187 H = numpy.array(list(self.__all_heights))
185 188 H.sort()
186 189 for key in self.data:
187 190 shape = self.shape(key)[:-1] + H.shape
188 191 for tm, obj in self.data[key].items():
189 192 h = self.__heights[self.__times.index(tm)]
190 193 if H.size == h.size:
191 194 continue
192 195 index = numpy.where(numpy.in1d(H, h))[0]
193 196 dummy = numpy.zeros(shape) + numpy.nan
194 197 if len(shape) == 2:
195 198 dummy[:, index] = obj
196 199 else:
197 200 dummy[index] = obj
198 201 self.data[key][tm] = dummy
199 202
200 203 self.__heights = [H for tm in self.__times]
201 204
202 205 def jsonify(self, decimate=False):
203 206 '''
204 207 Convert data to json
205 208 '''
206 209
207 210 ret = {}
208 211 tm = self.times[-1]
209 212
210 213 for key, value in self.data:
211 214 if key in ('spc', 'cspc'):
212 215 ret[key] = roundFloats(self.data[key].to_list())
213 216 else:
214 217 ret[key] = roundFloats(self.data[key][tm].to_list())
215 218
216 219 ret['timestamp'] = tm
217 220 ret['interval'] = self.interval
218 221
219 222 @property
220 223 def times(self):
221 224 '''
222 225 Return the list of times of the current data
223 226 '''
224 227
225 228 ret = numpy.array(self.__times)
226 229 ret.sort()
227 230 return ret
228 231
229 232 @property
230 233 def heights(self):
231 234 '''
232 235 Return the list of heights of the current data
233 236 '''
234 237
235 238 return numpy.array(self.__heights[-1])
236 239
237 240 class PublishData(Operation):
238 241 '''
239 242 Operation to send data over zmq.
240 243 '''
241 244
242 245 def __init__(self, **kwargs):
243 246 """Inicio."""
244 247 Operation.__init__(self, **kwargs)
245 248 self.isConfig = False
246 249 self.client = None
247 250 self.zeromq = None
248 251 self.mqtt = None
249 252
250 253 def on_disconnect(self, client, userdata, rc):
251 254 if rc != 0:
252 255 log.warning('Unexpected disconnection.')
253 256 self.connect()
254 257
255 258 def connect(self):
256 259 log.warning('trying to connect')
257 260 try:
258 261 self.client.connect(
259 262 host=self.host,
260 263 port=self.port,
261 264 keepalive=60*10,
262 265 bind_address='')
263 266 self.client.loop_start()
264 267 # self.client.publish(
265 268 # self.topic + 'SETUP',
266 269 # json.dumps(setup),
267 270 # retain=True
268 271 # )
269 272 except:
270 273 log.error('MQTT Conection error.')
271 274 self.client = False
272 275
273 276 def setup(self, port=1883, username=None, password=None, clientId="user", zeromq=1, verbose=True, **kwargs):
274 277 self.counter = 0
275 278 self.topic = kwargs.get('topic', 'schain')
276 279 self.delay = kwargs.get('delay', 0)
277 280 self.plottype = kwargs.get('plottype', 'spectra')
278 281 self.host = kwargs.get('host', "10.10.10.82")
279 282 self.port = kwargs.get('port', 3000)
280 283 self.clientId = clientId
281 284 self.cnt = 0
282 285 self.zeromq = zeromq
283 286 self.mqtt = kwargs.get('plottype', 0)
284 287 self.client = None
285 288 self.verbose = verbose
286 289 setup = []
287 290 if mqtt is 1:
288 291 self.client = mqtt.Client(
289 292 client_id=self.clientId + self.topic + 'SCHAIN',
290 293 clean_session=True)
291 294 self.client.on_disconnect = self.on_disconnect
292 295 self.connect()
293 296 for plot in self.plottype:
294 297 setup.append({
295 298 'plot': plot,
296 299 'topic': self.topic + plot,
297 300 'title': getattr(self, plot + '_' + 'title', False),
298 301 'xlabel': getattr(self, plot + '_' + 'xlabel', False),
299 302 'ylabel': getattr(self, plot + '_' + 'ylabel', False),
300 303 'xrange': getattr(self, plot + '_' + 'xrange', False),
301 304 'yrange': getattr(self, plot + '_' + 'yrange', False),
302 305 'zrange': getattr(self, plot + '_' + 'zrange', False),
303 306 })
304 307 if zeromq is 1:
305 308 context = zmq.Context()
306 309 self.zmq_socket = context.socket(zmq.PUSH)
307 310 server = kwargs.get('server', 'zmq.pipe')
308 311
309 312 if 'tcp://' in server:
310 313 address = server
311 314 else:
312 315 address = 'ipc:///tmp/%s' % server
313 316
314 317 self.zmq_socket.connect(address)
315 318 time.sleep(1)
316 319
317 320
318 321 def publish_data(self):
319 322 self.dataOut.finished = False
320 323 if self.mqtt is 1:
321 324 yData = self.dataOut.heightList[:2].tolist()
322 325 if self.plottype == 'spectra':
323 326 data = getattr(self.dataOut, 'data_spc')
324 327 z = data/self.dataOut.normFactor
325 328 zdB = 10*numpy.log10(z)
326 329 xlen, ylen = zdB[0].shape
327 330 dx = int(xlen/MAXNUMX) + 1
328 331 dy = int(ylen/MAXNUMY) + 1
329 332 Z = [0 for i in self.dataOut.channelList]
330 333 for i in self.dataOut.channelList:
331 334 Z[i] = zdB[i][::dx, ::dy].tolist()
332 335 payload = {
333 336 'timestamp': self.dataOut.utctime,
334 337 'data': roundFloats(Z),
335 338 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
336 339 'interval': self.dataOut.getTimeInterval(),
337 340 'type': self.plottype,
338 341 'yData': yData
339 342 }
340 343
341 344 elif self.plottype in ('rti', 'power'):
342 345 data = getattr(self.dataOut, 'data_spc')
343 346 z = data/self.dataOut.normFactor
344 347 avg = numpy.average(z, axis=1)
345 348 avgdB = 10*numpy.log10(avg)
346 349 xlen, ylen = z[0].shape
347 350 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
348 351 AVG = [0 for i in self.dataOut.channelList]
349 352 for i in self.dataOut.channelList:
350 353 AVG[i] = avgdB[i][::dy].tolist()
351 354 payload = {
352 355 'timestamp': self.dataOut.utctime,
353 356 'data': roundFloats(AVG),
354 357 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
355 358 'interval': self.dataOut.getTimeInterval(),
356 359 'type': self.plottype,
357 360 'yData': yData
358 361 }
359 362 elif self.plottype == 'noise':
360 363 noise = self.dataOut.getNoise()/self.dataOut.normFactor
361 364 noisedB = 10*numpy.log10(noise)
362 365 payload = {
363 366 'timestamp': self.dataOut.utctime,
364 367 'data': roundFloats(noisedB.reshape(-1, 1).tolist()),
365 368 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
366 369 'interval': self.dataOut.getTimeInterval(),
367 370 'type': self.plottype,
368 371 'yData': yData
369 372 }
370 373 elif self.plottype == 'snr':
371 374 data = getattr(self.dataOut, 'data_SNR')
372 375 avgdB = 10*numpy.log10(data)
373 376
374 377 ylen = data[0].size
375 378 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
376 379 AVG = [0 for i in self.dataOut.channelList]
377 380 for i in self.dataOut.channelList:
378 381 AVG[i] = avgdB[i][::dy].tolist()
379 382 payload = {
380 383 'timestamp': self.dataOut.utctime,
381 384 'data': roundFloats(AVG),
382 385 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
383 386 'type': self.plottype,
384 387 'yData': yData
385 388 }
386 389 else:
387 390 print "Tipo de grafico invalido"
388 391 payload = {
389 392 'data': 'None',
390 393 'timestamp': 'None',
391 394 'type': None
392 395 }
393 396
394 397 self.client.publish(self.topic + self.plottype, json.dumps(payload), qos=0)
395 398
396 399 if self.zeromq is 1:
397 400 if self.verbose:
398 401 log.log(
399 '{} - {}'.format(self.dataOut.type, self.dataOut.datatime),
400 'Sending'
402 'Sending {} - {}'.format(self.dataOut.type, self.dataOut.datatime),
403 self.name
401 404 )
402 405 self.zmq_socket.send_pyobj(self.dataOut)
403 406
404 407 def run(self, dataOut, **kwargs):
405 408 self.dataOut = dataOut
406 409 if not self.isConfig:
407 410 self.setup(**kwargs)
408 411 self.isConfig = True
409 412
410 413 self.publish_data()
411 414 time.sleep(self.delay)
412 415
413 416 def close(self):
414 417 if self.zeromq is 1:
415 418 self.dataOut.finished = True
416 419 self.zmq_socket.send_pyobj(self.dataOut)
417 420 time.sleep(0.1)
418 421 self.zmq_socket.close()
419 422 if self.client:
420 423 self.client.loop_stop()
421 424 self.client.disconnect()
422 425
423 426
424 427 class ReceiverData(ProcessingUnit):
425 428
426 429 def __init__(self, **kwargs):
427 430
428 431 ProcessingUnit.__init__(self, **kwargs)
429 432
430 433 self.isConfig = False
431 434 server = kwargs.get('server', 'zmq.pipe')
432 435 if 'tcp://' in server:
433 436 address = server
434 437 else:
435 438 address = 'ipc:///tmp/%s' % server
436 439
437 440 self.address = address
438 441 self.dataOut = JROData()
439 442
440 443 def setup(self):
441 444
442 445 self.context = zmq.Context()
443 446 self.receiver = self.context.socket(zmq.PULL)
444 447 self.receiver.bind(self.address)
445 448 time.sleep(0.5)
446 449 log.success('ReceiverData from {}'.format(self.address))
447 450
448 451
449 452 def run(self):
450 453
451 454 if not self.isConfig:
452 455 self.setup()
453 456 self.isConfig = True
454 457
455 458 self.dataOut = self.receiver.recv_pyobj()
456 459 log.log('{} - {}'.format(self.dataOut.type,
457 460 self.dataOut.datatime.ctime(),),
458 461 'Receiving')
459 462
460 463
461 464 class PlotterReceiver(ProcessingUnit, Process):
462 465
463 466 throttle_value = 5
464 467
465 468 def __init__(self, **kwargs):
466 469
467 470 ProcessingUnit.__init__(self, **kwargs)
468 471 Process.__init__(self)
469 472 self.mp = False
470 473 self.isConfig = False
471 474 self.isWebConfig = False
472 475 self.connections = 0
473 476 server = kwargs.get('server', 'zmq.pipe')
474 477 plot_server = kwargs.get('plot_server', 'zmq.web')
475 478 if 'tcp://' in server:
476 479 address = server
477 480 else:
478 481 address = 'ipc:///tmp/%s' % server
479 482
480 483 if 'tcp://' in plot_server:
481 484 plot_address = plot_server
482 485 else:
483 486 plot_address = 'ipc:///tmp/%s' % plot_server
484 487
485 488 self.address = address
486 489 self.plot_address = plot_address
487 490 self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')]
488 491 self.realtime = kwargs.get('realtime', False)
492 self.localtime = kwargs.get('localtime', True)
489 493 self.throttle_value = kwargs.get('throttle', 5)
490 494 self.sendData = self.initThrottle(self.throttle_value)
491 495 self.dates = []
492 496 self.setup()
493 497
494 498 def setup(self):
495 499
496 500 self.data = Data(self.plottypes, self.throttle_value)
497 501 self.isConfig = True
498 502
499 503 def event_monitor(self, monitor):
500 504
501 505 events = {}
502 506
503 507 for name in dir(zmq):
504 508 if name.startswith('EVENT_'):
505 509 value = getattr(zmq, name)
506 510 events[value] = name
507 511
508 512 while monitor.poll():
509 513 evt = recv_monitor_message(monitor)
510 514 if evt['event'] == 32:
511 515 self.connections += 1
512 516 if evt['event'] == 512:
513 517 pass
514 518
515 519 evt.update({'description': events[evt['event']]})
516 520
517 521 if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
518 522 break
519 523 monitor.close()
520 524 print('event monitor thread done!')
521 525
522 526 def initThrottle(self, throttle_value):
523 527
524 528 @throttle(seconds=throttle_value)
525 529 def sendDataThrottled(fn_sender, data):
526 530 fn_sender(data)
527 531
528 532 return sendDataThrottled
529 533
530 534 def send(self, data):
531 535 log.success('Sending {}'.format(data), self.name)
532 536 self.sender.send_pyobj(data)
533 537
534 538 def run(self):
535 539
536 540 log.success(
537 541 'Starting from {}'.format(self.address),
538 542 self.name
539 543 )
540 544
541 545 self.context = zmq.Context()
542 546 self.receiver = self.context.socket(zmq.PULL)
543 547 self.receiver.bind(self.address)
544 548 monitor = self.receiver.get_monitor_socket()
545 549 self.sender = self.context.socket(zmq.PUB)
546 550 if self.realtime:
547 551 self.sender_web = self.context.socket(zmq.PUB)
548 552 self.sender_web.connect(self.plot_address)
549 553 time.sleep(1)
550 554
551 555 if 'server' in self.kwargs:
552 556 self.sender.bind("ipc:///tmp/{}.plots".format(self.kwargs['server']))
553 557 else:
554 558 self.sender.bind("ipc:///tmp/zmq.plots")
555 559
556 560 time.sleep(2)
557 561
558 562 t = Thread(target=self.event_monitor, args=(monitor,))
559 563 t.start()
560 564
561 565 while True:
562 566 dataOut = self.receiver.recv_pyobj()
563 dt = datetime.datetime.utcfromtimestamp(dataOut.utctime).date()
567 tm = dataOut.utctime
568 if dataOut.useLocalTime:
569 if not self.localtime:
570 tm += time.timezone
571 dt = datetime.datetime.fromtimestamp(tm).date()
572 else:
573 if self.localtime:
574 tm -= time.timezone
575 dt = datetime.datetime.utcfromtimestamp(tm).date()
564 576 sended = False
565 577 if dt not in self.dates:
566 578 if self.data:
567 579 self.data.ended = True
568 580 self.send(self.data)
569 581 sended = True
570 582 self.data.setup()
571 583 self.dates.append(dt)
572 584
573 585 self.data.update(dataOut)
574 586
575 587 if dataOut.finished is True:
576 588 self.connections -= 1
577 589 if self.connections == 0 and dt in self.dates:
578 590 self.data.ended = True
579 591 self.send(self.data)
580 592 self.data.setup()
581 593 else:
582 594 if self.realtime:
583 595 self.send(self.data)
584 596 # self.sender_web.send_string(self.data.jsonify())
585 597 else:
586 598 if not sended:
587 599 self.sendData(self.send, self.data)
588 600
589 601 return
590 602
591 603 def sendToWeb(self):
592 604
593 605 if not self.isWebConfig:
594 606 context = zmq.Context()
595 607 sender_web_config = context.socket(zmq.PUB)
596 608 if 'tcp://' in self.plot_address:
597 609 dum, address, port = self.plot_address.split(':')
598 610 conf_address = '{}:{}:{}'.format(dum, address, int(port)+1)
599 611 else:
600 612 conf_address = self.plot_address + '.config'
601 613 sender_web_config.bind(conf_address)
602 614 time.sleep(1)
603 615 for kwargs in self.operationKwargs.values():
604 616 if 'plot' in kwargs:
605 617 log.success('[Sending] Config data to web for {}'.format(kwargs['code'].upper()))
606 618 sender_web_config.send_string(json.dumps(kwargs))
607 self.isWebConfig = True No newline at end of file
619 self.isWebConfig = True
General Comments 0
You need to be logged in to leave comments. Login now