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