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