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