##// END OF EJS Templates
Add angles to Block360 fix plotting codes
Juan C. Espinoza -
r1589:0234d27936fd
parent child
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,750 +1,752
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
36 36 from .plotting_codes import register_cmap
37 37
38 38 from schainpy.model.data.jrodata import PlotterData
39 39 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
40 40 from schainpy.utils import log
41 41
42 42
43 43 EARTH_RADIUS = 6.3710e3
44 44
45 45 register_cmap()
46 46
47 47 def ll2xy(lat1, lon1, lat2, lon2):
48 48
49 49 p = 0.017453292519943295
50 50 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
51 51 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
52 52 r = 12742 * numpy.arcsin(numpy.sqrt(a))
53 53 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
54 54 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
55 55 theta = -theta + numpy.pi/2
56 56 return r*numpy.cos(theta), r*numpy.sin(theta)
57 57
58 58
59 59 def km2deg(km):
60 60 '''
61 61 Convert distance in km to degrees
62 62 '''
63 63
64 64 return numpy.rad2deg(km/EARTH_RADIUS)
65 65
66 66
67 67 def figpause(interval):
68 68 backend = plt.rcParams['backend']
69 69 if backend in matplotlib.rcsetup.interactive_bk:
70 70 figManager = matplotlib._pylab_helpers.Gcf.get_active()
71 71 if figManager is not None:
72 72 canvas = figManager.canvas
73 73 if canvas.figure.stale:
74 74 canvas.draw()
75 75 try:
76 76 canvas.start_event_loop(interval)
77 77 except:
78 78 pass
79 79 return
80 80
81 81 def popup(message):
82 82 '''
83 83 '''
84 84
85 85 fig = plt.figure(figsize=(12, 8), facecolor='r')
86 86 text = '\n'.join([s.strip() for s in message.split(':')])
87 87 fig.text(0.01, 0.5, text, ha='left', va='center',
88 88 size='20', weight='heavy', color='w')
89 89 fig.show()
90 90 figpause(1000)
91 91
92 92
93 93 class Throttle(object):
94 94 '''
95 95 Decorator that prevents a function from being called more than once every
96 96 time period.
97 97 To create a function that cannot be called more than once a minute, but
98 98 will sleep until it can be called:
99 99 @Throttle(minutes=1)
100 100 def foo():
101 101 pass
102 102
103 103 for i in range(10):
104 104 foo()
105 105 print "This function has run %s times." % i
106 106 '''
107 107
108 108 def __init__(self, seconds=0, minutes=0, hours=0):
109 109 self.throttle_period = datetime.timedelta(
110 110 seconds=seconds, minutes=minutes, hours=hours
111 111 )
112 112
113 113 self.time_of_last_call = datetime.datetime.min
114 114
115 115 def __call__(self, fn):
116 116 @wraps(fn)
117 117 def wrapper(*args, **kwargs):
118 118 coerce = kwargs.pop('coerce', None)
119 119 if coerce:
120 120 self.time_of_last_call = datetime.datetime.now()
121 121 return fn(*args, **kwargs)
122 122 else:
123 123 now = datetime.datetime.now()
124 124 time_since_last_call = now - self.time_of_last_call
125 125 time_left = self.throttle_period - time_since_last_call
126 126
127 127 if time_left > datetime.timedelta(seconds=0):
128 128 return
129 129
130 130 self.time_of_last_call = datetime.datetime.now()
131 131 return fn(*args, **kwargs)
132 132
133 133 return wrapper
134 134
135 135 def apply_throttle(value):
136 136
137 137 @Throttle(seconds=value)
138 138 def fnThrottled(fn):
139 139 fn()
140 140
141 141 return fnThrottled
142 142
143 143
144 144 @MPDecorator
145 145 class Plot(Operation):
146 146 """Base class for Schain plotting operations
147 147
148 148 This class should never be use directtly you must subclass a new operation,
149 149 children classes must be defined as follow:
150 150
151 151 ExamplePlot(Plot):
152 152
153 153 CODE = 'code'
154 154 colormap = 'jet'
155 155 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
156 156
157 157 def setup(self):
158 158 pass
159 159
160 160 def plot(self):
161 161 pass
162 162
163 163 """
164 164
165 165 CODE = 'Figure'
166 166 colormap = 'jet'
167 167 bgcolor = 'white'
168 168 buffering = True
169 169 __missing = 1E30
170 170 projection = None
171 171
172 172 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
173 173 'showprofile']
174 174
175 175 def __init__(self):
176 176
177 177 Operation.__init__(self)
178 178 self.isConfig = False
179 179 self.isPlotConfig = False
180 180 self.save_time = 0
181 181 self.sender_time = 0
182 182 self.data = None
183 183 self.firsttime = True
184 184 self.sender_queue = deque(maxlen=10)
185 185 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
186 186
187 187 def __fmtTime(self, x, pos):
188 188 '''
189 189 '''
190 190
191 191 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
192 192
193 193 def __setup(self, **kwargs):
194 194 '''
195 195 Initialize variables
196 196 '''
197 197
198 198 self.figures = []
199 199 self.axes = []
200 200 self.cb_axes = []
201 201 self.localtime = kwargs.pop('localtime', True)
202 202 self.show = kwargs.get('show', True)
203 203 self.save = kwargs.get('save', False)
204 204 self.save_period = kwargs.get('save_period', 0)
205 205 self.colormap = kwargs.get('colormap', self.colormap)
206 206 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
207 207 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
208 208 self.colormaps = kwargs.get('colormaps', None)
209 209 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
210 210 self.showprofile = kwargs.get('showprofile', False)
211 211 self.title = kwargs.get('wintitle', self.CODE.upper())
212 212 self.cb_label = kwargs.get('cb_label', None)
213 213 self.cb_labels = kwargs.get('cb_labels', None)
214 214 self.labels = kwargs.get('labels', None)
215 215 self.xaxis = kwargs.get('xaxis', 'frequency')
216 216 self.zmin = kwargs.get('zmin', None)
217 217 self.zmax = kwargs.get('zmax', None)
218 218 self.zlimits = kwargs.get('zlimits', None)
219 219 self.xmin = kwargs.get('xmin', None)
220 220 self.xmax = kwargs.get('xmax', None)
221 221 self.xrange = kwargs.get('xrange', 12)
222 222 self.xscale = kwargs.get('xscale', None)
223 223 self.ymin = kwargs.get('ymin', None)
224 224 self.ymax = kwargs.get('ymax', None)
225 225 self.yscale = kwargs.get('yscale', None)
226 226 self.xlabel = kwargs.get('xlabel', None)
227 227 self.attr_time = kwargs.get('attr_time', 'utctime')
228 228 self.attr_data = kwargs.get('attr_data', 'data_param')
229 229 self.decimation = kwargs.get('decimation', None)
230 230 self.oneFigure = kwargs.get('oneFigure', True)
231 231 self.width = kwargs.get('width', None)
232 232 self.height = kwargs.get('height', None)
233 233 self.colorbar = kwargs.get('colorbar', True)
234 234 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
235 235 self.channels = kwargs.get('channels', None)
236 236 self.titles = kwargs.get('titles', [])
237 237 self.polar = False
238 238 self.type = kwargs.get('type', 'iq')
239 239 self.grid = kwargs.get('grid', False)
240 240 self.pause = kwargs.get('pause', False)
241 241 self.save_code = kwargs.get('save_code', self.CODE)
242 242 self.throttle = kwargs.get('throttle', 0)
243 243 self.exp_code = kwargs.get('exp_code', None)
244 244 self.server = kwargs.get('server', False)
245 245 self.sender_period = kwargs.get('sender_period', 60)
246 246 self.tag = kwargs.get('tag', '')
247 247 self.height_index = kwargs.get('height_index', None)
248 248 self.__throttle_plot = apply_throttle(self.throttle)
249 249 code = self.attr_data if self.attr_data else self.CODE
250 250 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
251 251 self.ang_min = kwargs.get('ang_min', None)
252 252 self.ang_max = kwargs.get('ang_max', None)
253 253 self.mode = kwargs.get('mode', None)
254 254 self.mask = kwargs.get('mask', False)
255 255 self.shapes = kwargs.get('shapes', './')
256 256
257 257 if self.server:
258 258 if not self.server.startswith('tcp://'):
259 259 self.server = 'tcp://{}'.format(self.server)
260 260 log.success(
261 261 'Sending to server: {}'.format(self.server),
262 262 self.name
263 263 )
264 264
265 265 if isinstance(self.attr_data, str):
266 266 self.attr_data = [self.attr_data]
267 267
268 268 def __setup_plot(self):
269 269 '''
270 270 Common setup for all figures, here figures and axes are created
271 271 '''
272 272
273 273 self.setup()
274 274
275 275 self.time_label = 'LT' if self.localtime else 'UTC'
276 276
277 277 if self.width is None:
278 278 self.width = 8
279 279
280 280 self.figures = {'PPI':[], 'RHI':[]}
281 281 self.axes = {'PPI':[], 'RHI':[]}
282 282 self.cb_axes = []
283 283 self.pf_axes = []
284 284 self.cmaps = []
285 285
286 286 size = '15%' if self.ncols == 1 else '30%'
287 287 pad = '4%' if self.ncols == 1 else '8%'
288 288
289 289 if self.oneFigure:
290 290 if self.height is None:
291 291 self.height = 1.4 * self.nrows + 1
292 292 fig_p = plt.figure(figsize=(self.width, self.height),
293 293 edgecolor='k',
294 294 facecolor='w')
295 295 fig_r = plt.figure(figsize=(self.width, 4),
296 296 edgecolor='k',
297 297 facecolor='w')
298 298 self.figures['PPI'].append(fig_p)
299 299 self.figures['RHI'].append(fig_r)
300 300 for n in range(self.nplots):
301 301 ax_p = fig_p.add_subplot(self.nrows, self.ncols, n+1, polar=self.polar, projection=self.projection)
302 302 ax_r = fig_r.add_subplot(self.nrows, self.ncols, n+1, polar=self.polar)
303 303 ax_p.tick_params(labelsize=8)
304 304 ax_p.firsttime = True
305 305 ax_p.index = 0
306 306 ax_p.press = None
307 307 ax_r.tick_params(labelsize=8)
308 308 ax_r.firsttime = True
309 309 ax_r.index = 0
310 310 ax_r.press = None
311 311
312 312 self.axes['PPI'].append(ax_p)
313 313 self.axes['RHI'].append(ax_r)
314 314
315 315 if self.showprofile:
316 316 cax = self.__add_axes(ax, size=size, pad=pad)
317 317 cax.tick_params(labelsize=8)
318 318 self.pf_axes.append(cax)
319 319 else:
320 320 if self.height is None:
321 321 self.height = 3
322 322 for n in range(self.nplots):
323 323 fig = plt.figure(figsize=(self.width, self.height),
324 324 edgecolor='k',
325 325 facecolor='w')
326 326 ax_p = fig.add_subplot(1, 1, 1, polar=self.polar, projection=self.projection)
327 327 ax_r = fig.add_subplot(1, 1, 1, polar=self.polar)
328 328 ax_p.tick_params(labelsize=8)
329 329 ax_p.firsttime = True
330 330 ax_p.index = 0
331 331 ax_p.press = None
332 332 ax_r.tick_params(labelsize=8)
333 333 ax_r.firsttime = True
334 334 ax_r.index = 0
335 335 ax_r.press = None
336 336 self.figures.append(fig)
337 337 self.axes['PPI'].append(ax_p)
338 338 self.axes['RHI'].append(ax_r)
339 339 if self.showprofile:
340 340 cax = self.__add_axes(ax, size=size, pad=pad)
341 341 cax.tick_params(labelsize=8)
342 342 self.pf_axes.append(cax)
343 343
344 344 # for n in range(self.nrows):
345 345 # if self.colormaps is not None:
346 346 # cmap = plt.get_cmap(self.colormaps[n])
347 347 # else:
348 348 # cmap = plt.get_cmap(self.colormap)
349 349 # cmap.set_bad(self.bgcolor, 1.)
350 350 # self.cmaps.append(cmap)
351 351
352 352 def __add_axes(self, ax, size='30%', pad='8%'):
353 353 '''
354 354 Add new axes to the given figure
355 355 '''
356 356 divider = make_axes_locatable(ax)
357 357 nax = divider.new_horizontal(size=size, pad=pad)
358 358 ax.figure.add_axes(nax)
359 359 return nax
360 360
361 361 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
362 362 '''
363 363 Create a masked array for missing data
364 364 '''
365 365 if x_buffer.shape[0] < 2:
366 366 return x_buffer, y_buffer, z_buffer
367 367
368 368 deltas = x_buffer[1:] - x_buffer[0:-1]
369 369 x_median = numpy.median(deltas)
370 370
371 371 index = numpy.where(deltas > 5 * x_median)
372 372
373 373 if len(index[0]) != 0:
374 374 z_buffer[::, index[0], ::] = self.__missing
375 375 z_buffer = numpy.ma.masked_inside(z_buffer,
376 376 0.99 * self.__missing,
377 377 1.01 * self.__missing)
378 378
379 379 return x_buffer, y_buffer, z_buffer
380 380
381 381 def decimate(self):
382 382
383 383 # dx = int(len(self.x)/self.__MAXNUMX) + 1
384 384 dy = int(len(self.y) / self.decimation) + 1
385 385
386 386 # x = self.x[::dx]
387 387 x = self.x
388 388 y = self.y[::dy]
389 389 z = self.z[::, ::, ::dy]
390 390
391 391 return x, y, z
392 392
393 393 def format(self):
394 394 '''
395 395 Set min and max values, labels, ticks and titles
396 396 '''
397 397
398 398 for n, ax in enumerate(self.axes[self.mode]):
399 399 if ax.firsttime:
400 400 if self.xaxis != 'time':
401 401 xmin = self.xmin
402 402 xmax = self.xmax
403 403 else:
404 404 xmin = self.tmin
405 405 xmax = self.tmin + self.xrange*60*60
406 406 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
407 407 ax.xaxis.set_major_locator(LinearLocator(9))
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
411 411 ax.set_facecolor(self.bgcolor)
412 412
413 413 if self.xscale:
414 414 ax.xaxis.set_major_formatter(FuncFormatter(
415 415 lambda x, pos: '{0:g}'.format(x*self.xscale)))
416 416 if self.yscale:
417 417 ax.yaxis.set_major_formatter(FuncFormatter(
418 418 lambda x, pos: '{0:g}'.format(x*self.yscale)))
419 419 if self.xlabel is not None:
420 420 ax.set_xlabel(self.xlabel)
421 421 if self.ylabel is not None:
422 422 ax.set_ylabel(self.ylabel)
423 423 if self.showprofile:
424 424 self.pf_axes[n].set_ylim(ymin, ymax)
425 425 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
426 426 self.pf_axes[n].set_xlabel('dB')
427 427 self.pf_axes[n].grid(b=True, axis='x')
428 428 [tick.set_visible(False)
429 429 for tick in self.pf_axes[n].get_yticklabels()]
430 430 if self.colorbar:
431 431 ax.cbar = plt.colorbar(
432 432 ax.plt, ax=ax, fraction=0.05, pad=0.06, aspect=10)
433 433 if self.colormap=='sophy_r':
434 434 ax.cbar.set_ticks([0.2, 0.73, 0.83, 0.93, 0.96, 0.99, 1.02, 1.05])
435 elif self.colormap=='sophy_d':
436 ax.cbar.set_ticks([-9, -6, -3, 0, 3, 6, 9, 12])
435 437 ax.cbar.ax.tick_params(labelsize=8)
436 438 ax.cbar.ax.press = None
437 439 if self.cb_label:
438 440 ax.cbar.set_label(self.cb_label, size=8)
439 441 elif self.cb_labels:
440 442 ax.cbar.set_label(self.cb_labels[n], size=8)
441 443 else:
442 444 ax.cbar = None
443 445 if self.mode == 'RHI':
444 446 ax.set_xlim(xmin, xmax)
445 447 ax.set_ylim(ymin, ymax)
446 448 ax.firsttime = False
447 449 if self.grid:
448 450 ax.grid(True)
449 451 if not self.polar:
450 452 ax.set_title('{} {} {}'.format(
451 453 self.titles[n],
452 454 self.getDateTime(self.data.max_time).strftime(
453 455 '%Y-%m-%d %H:%M:%S'),
454 456 self.time_label),
455 457 size=8)
456 458 else:
457 459 #ax.set_title('{}'.format(self.titles[n]), size=8)
458 460 ax.set_title('{} {} {}'.format(
459 461 self.titles[n],
460 462 self.getDateTime(self.data.max_time).strftime(
461 463 '%Y-%m-%d %H:%M:%S'),
462 464 self.time_label),
463 465 size=8)
464 466 ax.set_ylim(0, self.ymax)
465 467 if self.mode == 'PPI':
466 468 ax.set_yticks(ax.get_yticks(), labels=ax.get_yticks(), color='white')
467 469 ax.yaxis.labelpad = 28
468 470 elif self.mode == 'RHI':
469 471 ax.xaxis.labelpad = 16
470 472
471 473 if self.firsttime:
472 474 for fig in self.figures['PPI'] + self.figures['RHI']:
473 475 fig.subplots_adjust(**self.plots_adjust)
474 476 self.firsttime = False
475 477
476 478 def clear_figures(self):
477 479 '''
478 480 Reset axes for redraw plots
479 481 '''
480 482
481 483 axes = self.pf_axes + self.cb_axes + self.axes[self.mode]
482 484
483 485 for ax in axes:
484 486 ax.clear()
485 487 ax.firsttime = True
486 488 if hasattr(ax, 'cbar') and ax.cbar:
487 489 ax.cbar.remove()
488 490
489 491 def __plot(self):
490 492 '''
491 493 Main function to plot, format and save figures
492 494 '''
493 495
494 496 self.plot()
495 497 self.format()
496 498 figures = self.figures[self.mode]
497 499 for n, fig in enumerate(figures):
498 500 if self.nrows == 0 or self.nplots == 0:
499 501 log.warning('No data', self.name)
500 502 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
501 503 fig.canvas.manager.set_window_title(self.CODE)
502 504 continue
503 505
504 506 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
505 507 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
506 508 fig.canvas.draw()
507 509 if self.show:
508 510 fig.show()
509 511 figpause(0.01)
510 512
511 513 if self.save:
512 514 self.save_figure(n)
513 515
514 516 if self.server:
515 517 if self.mode and self.mode == 'RHI':
516 518 return
517 519 self.send_to_server()
518 520
519 521 def __update(self, dataOut, timestamp):
520 522 '''
521 523 '''
522 524
523 525 metadata = {
524 526 'yrange': dataOut.heightList,
525 527 'interval': dataOut.timeInterval,
526 528 'channels': dataOut.channelList
527 529 }
528 530
529 531 data, meta = self.update(dataOut)
530 532 metadata.update(meta)
531 533 self.data.update(data, timestamp, metadata)
532 534
533 535 def save_figure(self, n):
534 536 '''
535 537 '''
536 538 if self.mode is not None:
537 539 ang = 'AZ' if self.mode == 'RHI' else 'EL'
538 540 folder = '_{}_{}_{}'.format(self.mode, ang, self.mode_value)
539 541 label = '{}{}_{}'.format(ang[0], self.mode_value, self.save_code)
540 542 else:
541 543 folder = ''
542 544 label = ''
543 545
544 546 if self.oneFigure:
545 547 if (self.data.max_time - self.save_time) <= self.save_period:
546 548 return
547 549
548 550 self.save_time = self.data.max_time
549 551
550 552 fig = self.figures[self.mode][n]
551 553
552 554 if self.throttle == 0:
553 555 if self.oneFigure:
554 556 figname = os.path.join(
555 557 self.save,
556 558 self.save_code + folder,
557 559 '{}_{}_{}.png'.format(
558 560 'SOPHY',
559 561 self.getDateTime(self.data.max_time).strftime(
560 562 '%Y%m%d_%H%M%S'
561 563 ),
562 564 label
563 565 )
564 566 )
565 567 else:
566 568 figname = os.path.join(
567 569 self.save,
568 570 self.save_code,
569 571 '{}_ch{}_{}.png'.format(
570 572 self.save_code, n,
571 573 self.getDateTime(self.data.max_time).strftime(
572 574 '%Y%m%d_%H%M%S'
573 575 ),
574 576 )
575 577 )
576 578 log.log('Saving figure: {}'.format(figname), self.name)
577 579 if not os.path.isdir(os.path.dirname(figname)):
578 580 os.makedirs(os.path.dirname(figname))
579 581 fig.savefig(figname)
580 582
581 583 figname = os.path.join(
582 584 self.save,
583 585 '{}_{}.png'.format(
584 586 self.save_code,
585 587 self.getDateTime(self.data.min_time).strftime(
586 588 '%Y%m%d'
587 589 ),
588 590 )
589 591 )
590 592
591 593 log.log('Saving figure: {}'.format(figname), self.name)
592 594 if not os.path.isdir(os.path.dirname(figname)):
593 595 os.makedirs(os.path.dirname(figname))
594 596 fig.savefig(figname)
595 597
596 598 def send_to_server(self):
597 599 '''
598 600 '''
599 601
600 602 if self.exp_code == None:
601 603 log.warning('Missing `exp_code` skipping sending to server...')
602 604
603 605 last_time = self.data.max_time
604 606 interval = last_time - self.sender_time
605 607 if interval < self.sender_period:
606 608 return
607 609
608 610 self.sender_time = last_time
609 611
610 612 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
611 613 for attr in attrs:
612 614 value = getattr(self, attr)
613 615 if value:
614 616 if isinstance(value, (numpy.float32, numpy.float64)):
615 617 value = round(float(value), 2)
616 618 self.data.meta[attr] = value
617 619 if self.colormap == 'jet' or self.colormap == 'sophy_w':
618 620 self.data.meta['colormap'] = 'Jet'
619 621 elif 'sophy_v' in self.colormap:
620 622 self.data.meta['colormap'] = 'RdBu'
621 623 else:
622 624 self.data.meta['colormap'] = 'Viridis'
623 625 self.data.meta['interval'] = int(interval)
624 626
625 627 self.sender_queue.append(last_time)
626 628
627 629 while True:
628 630 try:
629 631 tm = self.sender_queue.popleft()
630 632 except IndexError:
631 633 break
632 634 msg = self.data.jsonify(tm, self.save_code, self.plot_type, key='var')
633 635 self.socket.send_string(msg)
634 636 socks = dict(self.poll.poll(2000))
635 637 if socks.get(self.socket) == zmq.POLLIN:
636 638 reply = self.socket.recv_string()
637 639 if reply == 'ok':
638 640 log.log("Response from server ok", self.name)
639 641 time.sleep(0.1)
640 642 continue
641 643 else:
642 644 log.warning(
643 645 "Malformed reply from server: {}".format(reply), self.name)
644 646 else:
645 647 log.warning(
646 648 "No response from server, retrying...", self.name)
647 649 self.sender_queue.appendleft(tm)
648 650 self.socket.setsockopt(zmq.LINGER, 0)
649 651 self.socket.close()
650 652 self.poll.unregister(self.socket)
651 653 self.socket = self.context.socket(zmq.REQ)
652 654 self.socket.connect(self.server)
653 655 self.poll.register(self.socket, zmq.POLLIN)
654 656 break
655 657
656 658 def setup(self):
657 659 '''
658 660 This method should be implemented in the child class, the following
659 661 attributes should be set:
660 662
661 663 self.nrows: number of rows
662 664 self.ncols: number of cols
663 665 self.nplots: number of plots (channels or pairs)
664 666 self.ylabel: label for Y axes
665 667 self.titles: list of axes title
666 668
667 669 '''
668 670 raise NotImplementedError
669 671
670 672 def plot(self):
671 673 '''
672 674 Must be defined in the child class, the actual plotting method
673 675 '''
674 676 raise NotImplementedError
675 677
676 678 def update(self, dataOut):
677 679 '''
678 680 Must be defined in the child class, update self.data with new data
679 681 '''
680 682
681 683 data = {
682 684 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
683 685 }
684 686 meta = {}
685 687
686 688 return data, meta
687 689
688 690 def run(self, dataOut, **kwargs):
689 691 '''
690 692 Main plotting routine
691 693 '''
692 694
693 695 if self.isConfig is False:
694 696 self.__setup(**kwargs)
695 697
696 698 if self.localtime:
697 699 self.getDateTime = datetime.datetime.fromtimestamp
698 700 else:
699 701 self.getDateTime = datetime.datetime.utcfromtimestamp
700 702
701 703 self.data.setup()
702 704 self.isConfig = True
703 705 if self.server:
704 706 self.context = zmq.Context()
705 707 self.socket = self.context.socket(zmq.REQ)
706 708 self.socket.connect(self.server)
707 709 self.poll = zmq.Poller()
708 710 self.poll.register(self.socket, zmq.POLLIN)
709 711
710 712 tm = getattr(dataOut, self.attr_time)
711 713
712 714 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
713 715 self.save_time = tm
714 716 self.__plot()
715 717 self.tmin += self.xrange*60*60
716 718 self.data.setup()
717 719 self.clear_figures()
718 720
719 721 self.__update(dataOut, tm)
720 722
721 723 if self.isPlotConfig is False:
722 724 self.__setup_plot()
723 725 self.isPlotConfig = True
724 726 if self.xaxis == 'time':
725 727 dt = self.getDateTime(tm)
726 728 if self.xmin is None:
727 729 self.tmin = tm
728 730 self.xmin = dt.hour
729 731 minutes = (self.xmin-int(self.xmin)) * 60
730 732 seconds = (minutes - int(minutes)) * 60
731 733 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
732 734 datetime.datetime(1970, 1, 1)).total_seconds()
733 735 if self.localtime:
734 736 self.tmin += time.timezone
735 737
736 738 if self.xmin is not None and self.xmax is not None:
737 739 self.xrange = self.xmax - self.xmin
738 740
739 741 if self.throttle == 0:
740 742 self.__plot()
741 743 else:
742 744 self.__throttle_plot(self.__plot)#, coerce=coerce)
743 745
744 746 def close(self):
745 747
746 748 if self.data and not self.data.flagNoData:
747 749 self.save_time = 0
748 750 self.__plot()
749 751 if self.data and not self.data.flagNoData and self.pause:
750 752 figpause(10)
@@ -1,113 +1,113
1 1 '''
2 2 @author: roj-idl71
3 3 '''
4 4
5 5 import matplotlib
6 6
7 7 #USED IN jroplot_spectra.py
8 8 RTI_CODE = 0 #Range time intensity (RTI).
9 9 SPEC_CODE = 1 #Spectra (and Cross-spectra) information.
10 10 CROSS_CODE = 2 #Cross-Correlation information.
11 11 COH_CODE = 3 #Coherence map.
12 12 BASE_CODE = 4 #Base lines graphic.
13 13 ROW_CODE = 5 #Row Spectra.
14 14 TOTAL_CODE = 6 #Total Power.
15 15 DRIFT_CODE = 7 #Drifts graphics.
16 16 HEIGHT_CODE = 8 #Height profile.
17 17 PHASE_CODE = 9 #Signal Phase.
18 18
19 19 POWER_CODE = 16
20 20 NOISE_CODE = 17
21 21 BEACON_CODE = 18
22 22
23 23 #USED IN jroplot_parameters.py
24 24 WIND_CODE = 22
25 25 MSKYMAP_CODE = 23
26 26 MPHASE_CODE = 24
27 27
28 28 MOMENTS_CODE = 25
29 29 PARMS_CODE = 26
30 30 SPECFIT_CODE = 27
31 31 EWDRIFT_CODE = 28
32 32
33 33
34 34 #COLOR TABLES
35 35
36 36 refl = [
37 37 "#2a323b", "#3f4c59", "#556576", "#6a7f94", "#7f99b2",
38 38 "#00ffff", "#007fff", "#0000ff", "#00ff00", "#00bf00",
39 39 "#007f00", "#ffff00", "#ffbf00", "#ff7f00", "#ff0000",
40 40 "#bf0000", "#7f0000", "#fe00fe", "#8e59ff", "#f0f0f0",
41 41 ]
42 42
43 refl_bounds = [-20, -15, -10, -5, 0, 5, 10 ,15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80]
43 #refl_bounds = [-25, -20, -15, -10, -5, 0, 5, 10 ,15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80]
44 44
45 45 doppler = [
46 46 "#003300", "#005500", "#007700", "#009900", "#00bb00", "#24ce24", "#6cd26c", "#b4d6b4",
47 47 "#d6b4b4", "#d26c6c", "#ce2424", "#bb0000", "#980000", "#760000", "#540000", "#330000",
48 48 ]
49 49
50 50 width = [
51 51 "#00ffff", "#00aaf2", "#0055e5", "#0000d8",
52 52 "#007f00", "#00aa00", "#00d400", "#00ff00",
53 53 "#ffff00", "#ffd400", "#ffaa00", "#ff7f00",
54 54 "#ff0000", "#d40000", "#aa0000", "#7f0000",
55 55 "#ff00ff", "#d400d4", "#aa00aa", "#7f007f",
56 56 "#9938ff", "#832ed8", "#6e25b2", "#591c8c",
57 57 ]
58 58
59 59 zdr = [
60 60 "#7333cc", "#7e3cd5", "#8945de", "#944ee7", "#9f57f0", "#aa5ff8",
61 "#82345c", "#984272", "#ae4f88", "#c55c9f", "#db6ab5", "#db6ab5",
61 "#82345c", "#984272", "#ae4f88", "#c55c9f", "#db6ab5", "#f177cb",
62 62 "#b5842d", "#c29a4c", "#d0b16b", "#ddc78a", "#ebddaa", "#f8f4c9",
63 63 "#f0f5ff", "#c4d8ff", "#97bbff", "#6a9eff", "#3e81ff", "#1164ff",
64 64 "#17f576", "#13df60", "#0ec949", "#0ab233", "#059c1d", "#018606",
65 65 "#fff300", "#ffdd00", "#ffc700", "#ffb000", "#ff9a00", "#ff8400",
66 66 "#f10000", "#db0000", "#c40000", "#ae0000", "#980000", "#810000",
67 67 ]
68 68
69 69 phi = [
70 70 "#ff3f40", "#ec3b6d", "#bf2f7e", "#92247c", "#7b1f7f", "#732492", "#782fbf", "#6f3bec",
71 71 "#513fff", "#3b4bec", "#2f57bf", "#245592", "#1f5a7f", "#247992", "#2fb4bf", "#3bece0",
72 72 "#3fffd8", "#3becb1", "#2fbf7d", "#249253", "#1f7f3d", "#24923b", "#2fbf3e", "#3bec3b",
73 73 "#50ff3f", "#5aec3b", "#55bf2f", "#4a9224", "#487f1f", "#5a9224", "#80bf2f", "#aaec3b",
74 74 "#c4ff3f", "#c0ec3b", "#a4bf2f", "#839224", "#777f1f", "#8e9224", "#bfbc2f", "#ece03b",
75 75 "#ffea3f", "#ecd13b", "#bfa42f", "#927924", "#7f661f", "#927124", "#bf8f2f", "#ecac3b",
76 76 "#ffb43f", "#eca23b", "#bf7f2f", "#925e24", "#7f501f", "#925924", "#bf712f", "#ec883b",
77 77 "#ff8f3f", "#ec813b", "#bf662f", "#924c24", "#7f401f", "#924824", "#bf5c2f", "#ec6f3b",
78 78 ]
79 79
80 80 rho = [
81 81 "#2a323b", "#3f4c59", "#556576", "#6a7f94", "#7f99b2",
82 82 "#00ffff", "#00bff5", "#007feb", "#003fe2", "#0000d8",
83 83 "#00ff00", "#00df00", "#00bf00", "#009f00", "#007f00",
84 84 "#ffff00", "#ffdf00", "#ffbf00", "#ff9f00", "#ff7f00",
85 85 "#ff0000", "#df0000", "#bf0000", "#9f0000", "#7f0000",
86 86 "#ff00ff", "#df00df", "#bf00bf", "#9f009f", "#7f007f",
87 87 "#9938ff", "#8931e2", "#792ac5", "#6923a8", "#591c8c",
88 88 ]
89 89
90 90 rho_bounds = [0.2, 0.306, 0.412, 0.518, 0.624, 0.73,
91 91 0.75, 0.77, 0.79, 0.81, 0.83,
92 92 0.85, 0.87, 0.89, 0.91, 0.93,
93 93 0.936, 0.942, 0.948, 0.954, 0.96,
94 94 0.966, 0.972, 0.978, 0.984, 0.99,
95 95 0.996, 1.002, 1.008, 1.014, 1.02,
96 96 1.026, 1.032, 1.038, 1.044, 1.05, 1.056]
97 97
98 98 cb_tables = {
99 99 'sophy_z': {'colors': refl, 'norm': None },
100 100 'sophy_v': {'colors': doppler, 'norm': None },
101 101 'sophy_w': {'colors': width, 'norm': None },
102 'sophy_d': {'colors': zdr, 'norm': None },
102 'sophy_d': {'colors': zdr, 'norm': None},
103 103 'sophy_p': {'colors': phi, 'norm': None },
104 104 'sophy_r': {'colors': rho, 'norm': matplotlib.colors.BoundaryNorm(rho_bounds, 37), 'extremes': ['#15191d', '#333899']},
105 105 }
106 106
107 107 def register_cmap():
108 108
109 109 for colormap in cb_tables:
110 110 cmap = matplotlib.colors.ListedColormap(cb_tables[colormap]['colors'], name=colormap)
111 111 if 'extremes' in cb_tables[colormap]:
112 112 cmap = cmap.with_extremes(under=cb_tables[colormap]['extremes'][0], over=cb_tables[colormap]['extremes'][1])
113 113 matplotlib.pyplot.register_cmap(cmap=cmap)
1 NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now