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