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