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