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