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