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