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