##// END OF EJS Templates
fix line 461 y 665
avaldez -
r1791:e4984c469c9f isr
parent child
Show More
@@ -1,705 +1,705
1 1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
2 2 # All rights reserved.
3 3 #
4 4 # Distributed under the terms of the BSD 3-clause license.
5 5 """Base class to create plot operations
6 6
7 7 """
8 8
9 9 import os
10 10 import sys
11 11 import zmq
12 12 import time
13 13 import numpy
14 14 import datetime
15 15 from collections import deque
16 16 from functools import wraps
17 17 from threading import Thread
18 18 import matplotlib
19 19
20 20 if 'BACKEND' in os.environ:
21 21 matplotlib.use(os.environ['BACKEND'])
22 22 elif 'linux' in sys.platform:
23 23 matplotlib.use("TkAgg")
24 24 elif 'darwin' in sys.platform:
25 25 matplotlib.use('MacOSX')
26 26 else:
27 27 from schainpy.utils import log
28 28 log.warning('Using default Backend="Agg"', 'INFO')
29 29 matplotlib.use('Agg')
30 30
31 31 import matplotlib.pyplot as plt
32 32 from matplotlib.patches import Polygon
33 33 from mpl_toolkits.axes_grid1 import make_axes_locatable
34 34 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
35 35
36 36 from schainpy.model.data.jrodata import PlotterData
37 37 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
38 38 from schainpy.utils import log
39 39
40 40 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
41 41 blu_values = matplotlib.pyplot.get_cmap(
42 42 'seismic_r', 20)(numpy.arange(20))[10:15]
43 43 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
44 44 'jro', numpy.vstack((blu_values, jet_values)))
45 matplotlib.pyplot.register_cmap(cmap=ncmap)
46 45
46 matplotlib.pyplot.register_cmap(cmap=ncmap)
47 #matplotlib.register_cmap(cmap=ncmap)
47 48 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
48 49 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
49 50
50 51 EARTH_RADIUS = 6.3710e3
51 52
52 53 def ll2xy(lat1, lon1, lat2, lon2):
53 54
54 55 p = 0.017453292519943295
55 56 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
56 57 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
57 58 r = 12742 * numpy.arcsin(numpy.sqrt(a))
58 59 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
59 60 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
60 61 theta = -theta + numpy.pi/2
61 62 return r*numpy.cos(theta), r*numpy.sin(theta)
62 63
63 64
64 65 def km2deg(km):
65 66 '''
66 67 Convert distance in km to degrees
67 68 '''
68 69
69 70 return numpy.rad2deg(km/EARTH_RADIUS)
70 71
71 72
72 73 def figpause(interval):
73 74 backend = plt.rcParams['backend']
74 75 if backend in matplotlib.rcsetup.interactive_bk:
75 76 figManager = matplotlib._pylab_helpers.Gcf.get_active()
76 77 if figManager is not None:
77 78 canvas = figManager.canvas
78 79 if canvas.figure.stale:
79 80 canvas.draw()
80 81 try:
81 82 canvas.start_event_loop(interval)
82 83 except:
83 84 pass
84 85 return
85 86
86 87 def popup(message):
87 88 '''
88 89 '''
89 90
90 91 fig = plt.figure(figsize=(12, 8), facecolor='r')
91 92 text = '\n'.join([s.strip() for s in message.split(':')])
92 93 fig.text(0.01, 0.5, text, ha='left', va='center',
93 94 size='20', weight='heavy', color='w')
94 95 fig.show()
95 96 figpause(1000)
96 97
97 98
98 99 class Throttle(object):
99 100 '''
100 101 Decorator that prevents a function from being called more than once every
101 102 time period.
102 103 To create a function that cannot be called more than once a minute, but
103 104 will sleep until it can be called:
104 105 @Throttle(minutes=1)
105 106 def foo():
106 107 pass
107 108
108 109 for i in range(10):
109 110 foo()
110 111 print "This function has run %s times." % i
111 112 '''
112 113
113 114 def __init__(self, seconds=0, minutes=0, hours=0):
114 115 self.throttle_period = datetime.timedelta(
115 116 seconds=seconds, minutes=minutes, hours=hours
116 117 )
117 118
118 119 self.time_of_last_call = datetime.datetime.min
119 120
120 121 def __call__(self, fn):
121 122 @wraps(fn)
122 123 def wrapper(*args, **kwargs):
123 124 coerce = kwargs.pop('coerce', None)
124 125 if coerce:
125 126 self.time_of_last_call = datetime.datetime.now()
126 127 return fn(*args, **kwargs)
127 128 else:
128 129 now = datetime.datetime.now()
129 130 time_since_last_call = now - self.time_of_last_call
130 131 time_left = self.throttle_period - time_since_last_call
131 132
132 133 if time_left > datetime.timedelta(seconds=0):
133 134 return
134 135
135 136 self.time_of_last_call = datetime.datetime.now()
136 137 return fn(*args, **kwargs)
137 138
138 139 return wrapper
139 140
140 141 def apply_throttle(value):
141 142
142 143 @Throttle(seconds=value)
143 144 def fnThrottled(fn):
144 145 fn()
145 146
146 147 return fnThrottled
147 148
148 149
149 150 @MPDecorator
150 151 class Plot(Operation):
151 152 """Base class for Schain plotting operations
152 153
153 154 This class should never be use directtly you must subclass a new operation,
154 155 children classes must be defined as follow:
155 156
156 157 ExamplePlot(Plot):
157 158
158 159 CODE = 'code'
159 160 colormap = 'jet'
160 161 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
161 162
162 163 def setup(self):
163 164 pass
164 165
165 166 def plot(self):
166 167 pass
167 168
168 169 """
169 170
170 171 CODE = 'Figure'
171 172 colormap = 'jet'
172 173 bgcolor = 'white'
173 174 buffering = True
174 175 __missing = 1E30
175 176
176 177 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
177 178 'showprofile']
178 179
179 180 def __init__(self):
180 181
181 182 Operation.__init__(self)
182 183 self.isConfig = False
183 184 self.isPlotConfig = False
184 185 self.save_time = 0
185 186 self.sender_time = 0
186 187 self.data = None
187 188 self.firsttime = True
188 189 self.sender_queue = deque(maxlen=10)
189 190 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
190 191
191 192 def __fmtTime(self, x, pos):
192 193 '''
193 194 '''
194 195
195 196 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
196 197
197 198 def __setup(self, **kwargs):
198 199 '''
199 200 Initialize variables
200 201 '''
201 202
202 203 self.figures = []
203 204 self.axes = []
204 205 self.cb_axes = []
205 206 self.localtime = kwargs.pop('localtime', True)
206 207 self.show = kwargs.get('show', True)
207 208 self.save = kwargs.get('save', False)
208 209 self.save_period = kwargs.get('save_period', 0)
209 210 self.colormap = kwargs.get('colormap', self.colormap)
210 211 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
211 212 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
212 213 self.colormaps = kwargs.get('colormaps', None)
213 214 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
214 215 self.showprofile = kwargs.get('showprofile', False)
215 216 self.title = kwargs.get('wintitle', self.CODE.upper())
216 217 self.cb_label = kwargs.get('cb_label', None)
217 218 self.cb_labels = kwargs.get('cb_labels', None)
218 219 self.labels = kwargs.get('labels', None)
219 220 self.xaxis = kwargs.get('xaxis', 'frequency')
220 221 self.zmin = kwargs.get('zmin', None)
221 222 self.zmax = kwargs.get('zmax', None)
222 223 self.zlimits = kwargs.get('zlimits', None)
223 224 self.xlimits = kwargs.get('xlimits', None)
224 225 self.xstep_given = kwargs.get('xstep_given', None)
225 226 self.ystep_given = kwargs.get('ystep_given', None)
226 227 self.autoxticks = kwargs.get('autoxticks', True)
227 228 self.xmin = kwargs.get('xmin', None)
228 229 self.xmax = kwargs.get('xmax', None)
229 230 self.xrange = kwargs.get('xrange', 12)
230 231 self.xscale = kwargs.get('xscale', None)
231 232 self.ymin = kwargs.get('ymin', None)
232 233 self.ymax = kwargs.get('ymax', None)
233 234 self.yscale = kwargs.get('yscale', None)
234 235 self.xlabel = kwargs.get('xlabel', None)
235 236 self.attr_time = kwargs.get('attr_time', 'utctime')
236 237 self.attr_data = kwargs.get('attr_data', 'data_param')
237 238 self.decimation = kwargs.get('decimation', None)
238 239 self.oneFigure = kwargs.get('oneFigure', True)
239 240 self.width = kwargs.get('width', None)
240 241 self.height = kwargs.get('height', None)
241 242 self.colorbar = kwargs.get('colorbar', True)
242 243 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
243 244 self.channels = kwargs.get('channels', None)
244 245 self.titles = kwargs.get('titles', [])
245 246 self.polar = False
246 247 self.type = kwargs.get('type', 'iq')
247 248 self.grid = kwargs.get('grid', False)
248 249 self.pause = kwargs.get('pause', False)
249 250 self.save_code = kwargs.get('save_code', self.CODE)
250 251 self.throttle = kwargs.get('throttle', 0)
251 252 self.exp_code = kwargs.get('exp_code', None)
252 253 self.server = kwargs.get('server', False)
253 254 self.sender_period = kwargs.get('sender_period', 60)
254 255 self.tag = kwargs.get('tag', '')
255 256 self.height_index = kwargs.get('height_index', None)
256 257 self.__throttle_plot = apply_throttle(self.throttle)
257 258 code = self.attr_data if self.attr_data else self.CODE
258 259 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
259 260 #self.EEJtype = kwargs.get('EEJtype', 2)
260 261
261 262 if self.server:
262 263 if not self.server.startswith('tcp://'):
263 264 self.server = 'tcp://{}'.format(self.server)
264 265 log.success(
265 266 'Sending to server: {}'.format(self.server),
266 267 self.name
267 268 )
268 269
269 270 if isinstance(self.attr_data, str):
270 271 self.attr_data = [self.attr_data]
271 272
272 273 def __setup_plot(self):
273 274 '''
274 275 Common setup for all figures, here figures and axes are created
275 276 '''
276 277
277 278 self.setup()
278 279
279 280 self.time_label = 'LT' if self.localtime else 'UTC'
280 281
281 282 if self.width is None:
282 283 self.width = 8
283 284
284 285 self.figures = []
285 286 self.axes = []
286 287 self.cb_axes = []
287 288 self.pf_axes = []
288 289 self.cmaps = []
289 290
290 291 size = '15%' if self.ncols == 1 else '30%'
291 292 pad = '4%' if self.ncols == 1 else '8%'
292 293
293 294 if self.oneFigure:
294 295 if self.height is None:
295 296 self.height = 1.4 * self.nrows + 1
296 297 fig = plt.figure(figsize=(self.width, self.height),
297 298 edgecolor='k',
298 299 facecolor='w')
299 300 self.figures.append(fig)
300 301 for n in range(self.nplots):
301 302 ax = fig.add_subplot(self.nrows, self.ncols,
302 303 n + 1, polar=self.polar)
303 304 ax.tick_params(labelsize=8)
304 305 ax.firsttime = True
305 306 ax.index = 0
306 307 ax.press = None
307 308 ax.cbar = None
308 309 self.axes.append(ax)
309 310 if self.showprofile:
310 311 cax = self.__add_axes(ax, size=size, pad=pad)
311 312 cax.tick_params(labelsize=8)
312 313 self.pf_axes.append(cax)
313 314 else:
314 315 if self.height is None:
315 316 self.height = 3
316 317 for n in range(self.nplots):
317 318 fig = plt.figure(figsize=(self.width, self.height),
318 319 edgecolor='k',
319 320 facecolor='w')
320 321 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
321 322 ax.tick_params(labelsize=8)
322 323 ax.firsttime = True
323 324 ax.index = 0
324 325 ax.press = None
325 326 self.figures.append(fig)
326 327 self.axes.append(ax)
327 328 if self.showprofile:
328 329 cax = self.__add_axes(ax, size=size, pad=pad)
329 330 cax.tick_params(labelsize=8)
330 331 self.pf_axes.append(cax)
331 332
332 333 for n in range(self.nrows):
333 334 if self.colormaps is not None:
334 335 cmap = plt.get_cmap(self.colormaps[n])
335 336 else:
336 337 cmap = plt.get_cmap(self.colormap)
337 338 cmap.set_bad(self.bgcolor, 1.)
338 339 self.cmaps.append(cmap)
339 340
340 341 def __add_axes(self, ax, size='30%', pad='8%'):
341 342 '''
342 343 Add new axes to the given figure
343 344 '''
344 345 divider = make_axes_locatable(ax)
345 346 nax = divider.new_horizontal(size=size, pad=pad)
346 347 ax.figure.add_axes(nax)
347 348 return nax
348 349
349 350 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
350 351 '''
351 352 Create a masked array for missing data
352 353 '''
353 354 if x_buffer.shape[0] < 2:
354 355 return x_buffer, y_buffer, z_buffer
355 356
356 357 deltas = x_buffer[1:] - x_buffer[0:-1]
357 358 x_median = numpy.median(deltas)
358 359
359 360 index = numpy.where(deltas > 5 * x_median)
360 361
361 362 if len(index[0]) != 0:
362 363 z_buffer[::, index[0], ::] = self.__missing
363 364 z_buffer = numpy.ma.masked_inside(z_buffer,
364 365 0.99 * self.__missing,
365 366 1.01 * self.__missing)
366 367
367 368 return x_buffer, y_buffer, z_buffer
368 369
369 370 def decimate(self):
370 371
371 372 # dx = int(len(self.x)/self.__MAXNUMX) + 1
372 373 dy = int(len(self.y) / self.decimation) + 1
373 374
374 375 # x = self.x[::dx]
375 376 x = self.x
376 377 y = self.y[::dy]
377 378 z = self.z[::, ::, ::dy]
378 379
379 380 return x, y, z
380 381
381 382 def format(self):
382 383 '''
383 384 Set min and max values, labels, ticks and titles
384 385 '''
385 386
386 387 for n, ax in enumerate(self.axes):
387 388 if ax.firsttime:
388 389 if self.xaxis != 'time':
389 390 xmin = self.xmin
390 391 xmax = self.xmax
391 392 else:
392 393 xmin = self.tmin
393 394 xmax = self.tmin + self.xrange*60*60
394 395 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
395 396 ax.xaxis.set_major_locator(LinearLocator(9))
396 397 ymin = self.ymin if self.ymin is not None else numpy.nanmin(self.y[numpy.isfinite(self.y)])
397 398 ymax = self.ymax if self.ymax is not None else numpy.nanmax(self.y[numpy.isfinite(self.y)])
398 399 ax.set_facecolor(self.bgcolor)
399 400 if self.xscale:
400 401 ax.xaxis.set_major_formatter(FuncFormatter(
401 402 lambda x, pos: '{0:g}'.format(x*self.xscale)))
402 403 if self.yscale:
403 404 ax.yaxis.set_major_formatter(FuncFormatter(
404 405 lambda x, pos: '{0:g}'.format(x*self.yscale)))
405 406 if self.xlabel is not None:
406 407 ax.set_xlabel(self.xlabel)
407 408 if self.ylabel is not None:
408 409 ax.set_ylabel(self.ylabel)
409 410 if self.showprofile:
410 411 if self.zlimits is not None:
411 412 self.zmin, self.zmax = self.zlimits[n]
412 413 self.pf_axes[n].set_ylim(ymin, ymax)
413 414 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
414 415 self.pf_axes[n].set_xlabel('dB')
415 416 self.pf_axes[n].grid(b=True, axis='x')
416 417 [tick.set_visible(False)
417 418 for tick in self.pf_axes[n].get_yticklabels()]
418 419 if self.colorbar and ax.cbar == None:
419 420 ax.cbar = plt.colorbar(
420 421 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
421 422 ax.cbar.ax.tick_params(labelsize=8)
422 423 ax.cbar.ax.press = None
423 424 if self.cb_label:
424 425 ax.cbar.set_label(self.cb_label, size=8)
425 426 elif self.cb_labels:
426 427 ax.cbar.set_label(self.cb_labels[n], size=8)
427 428 else:
428 429 ax.cbar = None
429 430 ax.set_xlim(xmin, xmax)
430 431 ax.set_ylim(ymin, ymax)
431 432 ax.firsttime = False
432 433 if self.grid:
433 434 ax.grid(True)
434 435 if not self.polar:
435 436 ax.set_title('{} {} {}'.format(
436 437 self.titles[n],
437 438 self.getDateTime(self.data.max_time).strftime(
438 439 '%Y-%m-%d %H:%M:%S'),
439 440 self.time_label),
440 441 size=8)
441 442 else:
442 443 ax.set_title('{}'.format(self.titles[n]), size=8)
443 444 ax.set_ylim(0, 90)
444 445 ax.set_yticks(numpy.arange(0, 90, 20))
445 446 ax.yaxis.labelpad = 40
446 447
447 448 if self.firsttime:
448 449 for n, fig in enumerate(self.figures):
449 450 fig.subplots_adjust(**self.plots_adjust)
450 451 self.firsttime = False
451 452
452 453 def clear_figures(self):
453 454 '''
454 455 Reset axes for redraw plots
455 456 '''
456 457
457 458 for ax in self.axes+self.pf_axes+self.cb_axes:
458 459 ax.clear()
459 460 ax.firsttime = True
460 if hasattr(ax, 'cbar') and ax.cbar:
461 ax.cbar.remove()
461 #if hasattr(ax, 'cbar') and ax.cbar:
462 # ax.cbar.remove()
462 463
463 464 def __plot(self):
464 465 '''
465 466 Main function to plot, format and save figures
466 467 '''
467 468
468 469 self.plot()
469 470 self.format()
470 471
471 472 for n, fig in enumerate(self.figures):
472 473 if self.nrows == 0 or self.nplots == 0:
473 474 log.warning('No data', self.name)
474 475 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
475 476 fig.canvas.manager.set_window_title(self.CODE)
476 477 continue
477 478
478 479 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
479 480 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
480 481 fig.canvas.draw()
481 482 if self.show:
482 483 fig.show()
483 484 figpause(0.01)
484 485
485 486 if self.save:
486 487 self.save_figure(n)
487 488
488 489 if self.server:
489 490 self.send_to_server()
490 491
491 492 def __update(self, dataOut, timestamp):
492 493 '''
493 494 '''
494 495
495 496 metadata = {
496 497 'yrange': dataOut.heightList,
497 498 'interval': dataOut.timeInterval,
498 499 'channels': dataOut.channelList
499 500 }
500 501
501 502 data, meta = self.update(dataOut)
502 503 metadata.update(meta)
503 504 self.data.update(data, timestamp, metadata)
504 505
505 506 def save_figure(self, n):
506 507 '''
507 508 '''
508 509
509 510 if (self.data.max_time - self.save_time) <= self.save_period:
510 511 return
511 512
512 513 self.save_time = self.data.max_time
513 514
514 515 fig = self.figures[n]
515 516
516 517 if self.throttle == 0:
517 518 figname = os.path.join(
518 519 self.save,
519 520 self.save_code,
520 521 '{}_{}.png'.format(
521 522 self.save_code,
522 523 self.getDateTime(self.data.max_time).strftime(
523 524 '%Y%m%d_%H%M%S'
524 525 ),
525 526 )
526 527 )
527 528 log.log('Saving figure: {}'.format(figname), self.name)
528 529 if not os.path.isdir(os.path.dirname(figname)):
529 530 os.makedirs(os.path.dirname(figname))
530 531 fig.savefig(figname)
531 532
532 533 figname = os.path.join(
533 534 self.save,
534 535 #self.save_code,
535 536 '{}_{}.png'.format(
536 537 self.save_code,
537 538 self.getDateTime(self.data.min_time).strftime(
538 539 '%Y%m%d'
539 540 ),
540 541 )
541 542 )
542 543 log.log('Saving figure: {}'.format(figname), self.name)
543 544 if not os.path.isdir(os.path.dirname(figname)):
544 545 os.makedirs(os.path.dirname(figname))
545 546 fig.savefig(figname)
546 547
547 548 def send_to_server(self):
548 549 '''
549 550 '''
550 551
551 552 if self.exp_code == None:
552 553 log.warning('Missing `exp_code` skipping sending to server...')
553 554
554 555 last_time = self.data.max_time
555 556 interval = last_time - self.sender_time
556 557 if interval < self.sender_period:
557 558 return
558 559
559 560 self.sender_time = last_time
560 561
561 562 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax', 'zlimits']
562 563 for attr in attrs:
563 564 value = getattr(self, attr)
564 565 if value:
565 566 if isinstance(value, (numpy.float32, numpy.float64)):
566 567 value = round(float(value), 2)
567 568 self.data.meta[attr] = value
568 569 if self.colormap == 'jet':
569 570 self.data.meta['colormap'] = 'Jet'
570 571 elif 'RdBu' in self.colormap:
571 572 self.data.meta['colormap'] = 'RdBu'
572 573 else:
573 574 self.data.meta['colormap'] = 'Viridis'
574 575 self.data.meta['interval'] = int(interval)
575 576 #print(last_time)
576 577 #print(time.time())
577 578 #exit(1)
578 579 self.sender_queue.append(last_time)
579 580
580 581 while True:
581 582 try:
582 583 tm = self.sender_queue.popleft()
583 584 except IndexError:
584 585 break
585 586 msg = self.data.jsonify(tm, self.save_code, self.plot_type)
586 587 self.socket.send_string(msg)
587 588 socks = dict(self.poll.poll(2000))
588 589 if socks.get(self.socket) == zmq.POLLIN:
589 590 reply = self.socket.recv_string()
590 591 if reply == 'ok':
591 592 log.log("Response from server ok", self.name)
592 593 time.sleep(0.1)
593 594 continue
594 595 else:
595 596 log.warning(
596 597 "Malformed reply from server: {}".format(reply), self.name)
597 598 else:
598 599 log.warning(
599 600 "No response from server, retrying...", self.name)
600 601 self.sender_queue.appendleft(tm)
601 602 self.socket.setsockopt(zmq.LINGER, 0)
602 603 self.socket.close()
603 604 self.poll.unregister(self.socket)
604 605 self.socket = self.context.socket(zmq.REQ)
605 606 self.socket.connect(self.server)
606 607 self.poll.register(self.socket, zmq.POLLIN)
607 608 break
608 609
609 610 def setup(self):
610 611 '''
611 612 This method should be implemented in the child class, the following
612 613 attributes should be set:
613 614
614 615 self.nrows: number of rows
615 616 self.ncols: number of cols
616 617 self.nplots: number of plots (channels or pairs)
617 618 self.ylabel: label for Y axes
618 619 self.titles: list of axes title
619 620
620 621 '''
621 622 raise NotImplementedError
622 623
623 624 def plot(self):
624 625 '''
625 626 Must be defined in the child class, the actual plotting method
626 627 '''
627 628 raise NotImplementedError
628 629
629 630 def update(self, dataOut):
630 631 '''
631 632 Must be defined in the child class, update self.data with new data
632 633 '''
633 634
634 635 data = {
635 636 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
636 637 }
637 638 meta = {}
638 639
639 640 return data, meta
640 641
641 642 def run(self, dataOut, **kwargs):
642 643 '''
643 644 Main plotting routine
644 645 '''
645 646
646 647 if self.isConfig is False:
647 648 self.__setup(**kwargs)
648 649
649 650 if self.localtime:
650 651 self.getDateTime = datetime.datetime.fromtimestamp
651 652 else:
652 653 self.getDateTime = datetime.datetime.utcfromtimestamp
653 654
654 655 self.data.setup()
655 656 self.isConfig = True
656 657 if self.server:
657 658 self.context = zmq.Context()
658 659 self.socket = self.context.socket(zmq.REQ)
659 660 self.socket.connect(self.server)
660 661 self.poll = zmq.Poller()
661 662 self.poll.register(self.socket, zmq.POLLIN)
662 663
663 664 tm = getattr(dataOut, self.attr_time)
664 665 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
665 666 self.save_time = tm
667 self.tmin += self.xrange*60*60 #Modified by R. Flores
668 #self.tmin += 24*60*60 #Modified by R. Flores
666 669 self.__plot()
667 #self.tmin += self.xrange*60*60 #Modified by R. Flores
668 self.tmin += 24*60*60 #Modified by R. Flores
669
670 670 self.data.setup()
671 671 self.clear_figures()
672 672
673 673 self.__update(dataOut, tm)
674 674
675 675 if self.isPlotConfig is False:
676 676 self.__setup_plot()
677 677 self.isPlotConfig = True
678 678 if self.xaxis == 'time':
679 679 dt = self.getDateTime(tm)
680 680
681 681 if self.xmin is None:
682 682 self.tmin = tm
683 683 self.xmin = dt.hour
684 684 minutes = (self.xmin-int(self.xmin)) * 60
685 685 seconds = (minutes - int(minutes)) * 60
686 686 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
687 687 datetime.datetime(1970, 1, 1)).total_seconds()
688 688 if self.localtime:
689 689 self.tmin += time.timezone
690 690
691 691 if self.xmin is not None and self.xmax is not None:
692 692 self.xrange = self.xmax - self.xmin
693 693
694 694 if self.throttle == 0:
695 695 self.__plot()
696 696 else:
697 697 self.__throttle_plot(self.__plot)#, coerce=coerce)
698 698
699 699 def close(self):
700 700
701 701 if self.data and not self.data.flagNoData:
702 702 self.save_time = 0
703 703 self.__plot()
704 704 if self.data and not self.data.flagNoData and self.pause:
705 705 figpause(10)
General Comments 0
You need to be logged in to leave comments. Login now