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