##// END OF EJS Templates
Fix px1000 reading online
jespinoza -
r1138:c6cf5a83f48e
parent child
Show More
@@ -1,1042 +1,1042
1
1
2 import os
2 import os
3 import time
3 import time
4 import glob
4 import glob
5 import datetime
5 import datetime
6 from multiprocessing import Process
6 from multiprocessing import Process
7
7
8 import zmq
8 import zmq
9 import numpy
9 import numpy
10 import matplotlib
10 import matplotlib
11 import matplotlib.pyplot as plt
11 import matplotlib.pyplot as plt
12 from mpl_toolkits.axes_grid1 import make_axes_locatable
12 from mpl_toolkits.axes_grid1 import make_axes_locatable
13 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
13 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
14
14
15 from schainpy.model.proc.jroproc_base import Operation
15 from schainpy.model.proc.jroproc_base import Operation
16 from schainpy.utils import log
16 from schainpy.utils import log
17
17
18 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
18 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
19 blu_values = matplotlib.pyplot.get_cmap(
19 blu_values = matplotlib.pyplot.get_cmap(
20 'seismic_r', 20)(numpy.arange(20))[10:15]
20 'seismic_r', 20)(numpy.arange(20))[10:15]
21 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
21 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
22 'jro', numpy.vstack((blu_values, jet_values)))
22 'jro', numpy.vstack((blu_values, jet_values)))
23 matplotlib.pyplot.register_cmap(cmap=ncmap)
23 matplotlib.pyplot.register_cmap(cmap=ncmap)
24
24
25 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis', 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm', 'spectral')]
25 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis', 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm', 'spectral')]
26
26
27
27
28 def figpause(interval):
28 def figpause(interval):
29 backend = plt.rcParams['backend']
29 backend = plt.rcParams['backend']
30 if backend in matplotlib.rcsetup.interactive_bk:
30 if backend in matplotlib.rcsetup.interactive_bk:
31 figManager = matplotlib._pylab_helpers.Gcf.get_active()
31 figManager = matplotlib._pylab_helpers.Gcf.get_active()
32 if figManager is not None:
32 if figManager is not None:
33 canvas = figManager.canvas
33 canvas = figManager.canvas
34 if canvas.figure.stale:
34 if canvas.figure.stale:
35 canvas.draw()
35 canvas.draw()
36 canvas.start_event_loop(interval)
36 canvas.start_event_loop(interval)
37 return
37 return
38
38
39
39
40 class PlotData(Operation, Process):
40 class PlotData(Operation, Process):
41 '''
41 '''
42 Base class for Schain plotting operations
42 Base class for Schain plotting operations
43 '''
43 '''
44
44
45 CODE = 'Figure'
45 CODE = 'Figure'
46 colormap = 'jro'
46 colormap = 'jro'
47 bgcolor = 'white'
47 bgcolor = 'white'
48 CONFLATE = False
48 CONFLATE = False
49 __missing = 1E30
49 __missing = 1E30
50
50
51 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
51 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
52 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title',
52 'zlimits', 'xlabel', 'ylabel', 'xaxis','cb_label', 'title',
53 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
53 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
54 'showprofile', 'decimation', 'ftp']
54 'showprofile', 'decimation', 'ftp']
55
55
56 def __init__(self, **kwargs):
56 def __init__(self, **kwargs):
57
57
58 Operation.__init__(self, plot=True, **kwargs)
58 Operation.__init__(self, plot=True, **kwargs)
59 Process.__init__(self)
59 Process.__init__(self)
60
60
61 self.kwargs['code'] = self.CODE
61 self.kwargs['code'] = self.CODE
62 self.mp = False
62 self.mp = False
63 self.data = None
63 self.data = None
64 self.isConfig = False
64 self.isConfig = False
65 self.figures = []
65 self.figures = []
66 self.axes = []
66 self.axes = []
67 self.cb_axes = []
67 self.cb_axes = []
68 self.localtime = kwargs.pop('localtime', True)
68 self.localtime = kwargs.pop('localtime', True)
69 self.show = kwargs.get('show', True)
69 self.show = kwargs.get('show', True)
70 self.save = kwargs.get('save', False)
70 self.save = kwargs.get('save', False)
71 self.ftp = kwargs.get('ftp', False)
71 self.ftp = kwargs.get('ftp', False)
72 self.colormap = kwargs.get('colormap', self.colormap)
72 self.colormap = kwargs.get('colormap', self.colormap)
73 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
73 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
74 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
74 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
75 self.colormaps = kwargs.get('colormaps', None)
75 self.colormaps = kwargs.get('colormaps', None)
76 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
76 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
77 self.showprofile = kwargs.get('showprofile', False)
77 self.showprofile = kwargs.get('showprofile', False)
78 self.title = kwargs.get('wintitle', self.CODE.upper())
78 self.title = kwargs.get('wintitle', self.CODE.upper())
79 self.cb_label = kwargs.get('cb_label', None)
79 self.cb_label = kwargs.get('cb_label', None)
80 self.cb_labels = kwargs.get('cb_labels', None)
80 self.cb_labels = kwargs.get('cb_labels', None)
81 self.labels = kwargs.get('labels', None)
81 self.labels = kwargs.get('labels', None)
82 self.xaxis = kwargs.get('xaxis', 'frequency')
82 self.xaxis = kwargs.get('xaxis', 'frequency')
83 self.zmin = kwargs.get('zmin', None)
83 self.zmin = kwargs.get('zmin', None)
84 self.zmax = kwargs.get('zmax', None)
84 self.zmax = kwargs.get('zmax', None)
85 self.zlimits = kwargs.get('zlimits', None)
85 self.zlimits = kwargs.get('zlimits', None)
86 self.xmin = kwargs.get('xmin', None)
86 self.xmin = kwargs.get('xmin', None)
87 self.xmax = kwargs.get('xmax', None)
87 self.xmax = kwargs.get('xmax', None)
88 self.xrange = kwargs.get('xrange', 24)
88 self.xrange = kwargs.get('xrange', 24)
89 self.xscale = kwargs.get('xscale', None)
89 self.xscale = kwargs.get('xscale', None)
90 self.ymin = kwargs.get('ymin', None)
90 self.ymin = kwargs.get('ymin', None)
91 self.ymax = kwargs.get('ymax', None)
91 self.ymax = kwargs.get('ymax', None)
92 self.yscale = kwargs.get('yscale', None)
92 self.yscale = kwargs.get('yscale', None)
93 self.xlabel = kwargs.get('xlabel', None)
93 self.xlabel = kwargs.get('xlabel', None)
94 self.decimation = kwargs.get('decimation', None)
94 self.decimation = kwargs.get('decimation', None)
95 self.showSNR = kwargs.get('showSNR', False)
95 self.showSNR = kwargs.get('showSNR', False)
96 self.oneFigure = kwargs.get('oneFigure', True)
96 self.oneFigure = kwargs.get('oneFigure', True)
97 self.width = kwargs.get('width', None)
97 self.width = kwargs.get('width', None)
98 self.height = kwargs.get('height', None)
98 self.height = kwargs.get('height', None)
99 self.colorbar = kwargs.get('colorbar', True)
99 self.colorbar = kwargs.get('colorbar', True)
100 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
100 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
101 self.channels = kwargs.get('channels', None)
101 self.channels = kwargs.get('channels', None)
102 self.titles = kwargs.get('titles', [])
102 self.titles = kwargs.get('titles', [])
103 self.polar = False
103 self.polar = False
104
104
105 def __fmtTime(self, x, pos):
105 def __fmtTime(self, x, pos):
106 '''
106 '''
107 '''
107 '''
108
108
109 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
109 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
110
110
111 def __setup(self):
111 def __setup(self):
112 '''
112 '''
113 Common setup for all figures, here figures and axes are created
113 Common setup for all figures, here figures and axes are created
114 '''
114 '''
115
115
116 if self.CODE not in self.data:
116 if self.CODE not in self.data:
117 raise ValueError(log.error('Missing data for {}'.format(self.CODE),
117 raise ValueError(log.error('Missing data for {}'.format(self.CODE),
118 self.name))
118 self.name))
119
119
120 self.setup()
120 self.setup()
121
121
122 self.time_label = 'LT' if self.localtime else 'UTC'
122 self.time_label = 'LT' if self.localtime else 'UTC'
123 if self.data.localtime:
123 if self.data.localtime:
124 self.getDateTime = datetime.datetime.fromtimestamp
124 self.getDateTime = datetime.datetime.fromtimestamp
125 else:
125 else:
126 self.getDateTime = datetime.datetime.utcfromtimestamp
126 self.getDateTime = datetime.datetime.utcfromtimestamp
127
127
128 if self.width is None:
128 if self.width is None:
129 self.width = 8
129 self.width = 8
130
130
131 self.figures = []
131 self.figures = []
132 self.axes = []
132 self.axes = []
133 self.cb_axes = []
133 self.cb_axes = []
134 self.pf_axes = []
134 self.pf_axes = []
135 self.cmaps = []
135 self.cmaps = []
136
136
137 size = '15%' if self.ncols == 1 else '30%'
137 size = '15%' if self.ncols == 1 else '30%'
138 pad = '4%' if self.ncols == 1 else '8%'
138 pad = '4%' if self.ncols == 1 else '8%'
139
139
140 if self.oneFigure:
140 if self.oneFigure:
141 if self.height is None:
141 if self.height is None:
142 self.height = 1.4 * self.nrows + 1
142 self.height = 1.4 * self.nrows + 1
143 fig = plt.figure(figsize=(self.width, self.height),
143 fig = plt.figure(figsize=(self.width, self.height),
144 edgecolor='k',
144 edgecolor='k',
145 facecolor='w')
145 facecolor='w')
146 self.figures.append(fig)
146 self.figures.append(fig)
147 for n in range(self.nplots):
147 for n in range(self.nplots):
148 ax = fig.add_subplot(self.nrows, self.ncols,
148 ax = fig.add_subplot(self.nrows, self.ncols,
149 n + 1, polar=self.polar)
149 n + 1, polar=self.polar)
150 ax.tick_params(labelsize=8)
150 ax.tick_params(labelsize=8)
151 ax.firsttime = True
151 ax.firsttime = True
152 ax.index = 0
152 ax.index = 0
153 ax.press = None
153 ax.press = None
154 self.axes.append(ax)
154 self.axes.append(ax)
155 if self.showprofile:
155 if self.showprofile:
156 cax = self.__add_axes(ax, size=size, pad=pad)
156 cax = self.__add_axes(ax, size=size, pad=pad)
157 cax.tick_params(labelsize=8)
157 cax.tick_params(labelsize=8)
158 self.pf_axes.append(cax)
158 self.pf_axes.append(cax)
159 else:
159 else:
160 if self.height is None:
160 if self.height is None:
161 self.height = 3
161 self.height = 3
162 for n in range(self.nplots):
162 for n in range(self.nplots):
163 fig = plt.figure(figsize=(self.width, self.height),
163 fig = plt.figure(figsize=(self.width, self.height),
164 edgecolor='k',
164 edgecolor='k',
165 facecolor='w')
165 facecolor='w')
166 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
166 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
167 ax.tick_params(labelsize=8)
167 ax.tick_params(labelsize=8)
168 ax.firsttime = True
168 ax.firsttime = True
169 ax.index = 0
169 ax.index = 0
170 ax.press = None
170 ax.press = None
171 self.figures.append(fig)
171 self.figures.append(fig)
172 self.axes.append(ax)
172 self.axes.append(ax)
173 if self.showprofile:
173 if self.showprofile:
174 cax = self.__add_axes(ax, size=size, pad=pad)
174 cax = self.__add_axes(ax, size=size, pad=pad)
175 cax.tick_params(labelsize=8)
175 cax.tick_params(labelsize=8)
176 self.pf_axes.append(cax)
176 self.pf_axes.append(cax)
177
177
178 for n in range(self.nrows):
178 for n in range(self.nrows):
179 if self.colormaps is not None:
179 if self.colormaps is not None:
180 cmap = plt.get_cmap(self.colormaps[n])
180 cmap = plt.get_cmap(self.colormaps[n])
181 else:
181 else:
182 cmap = plt.get_cmap(self.colormap)
182 cmap = plt.get_cmap(self.colormap)
183 cmap.set_bad(self.bgcolor, 1.)
183 cmap.set_bad(self.bgcolor, 1.)
184 self.cmaps.append(cmap)
184 self.cmaps.append(cmap)
185
185
186 for fig in self.figures:
186 for fig in self.figures:
187 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
187 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
188 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
188 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
189 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
189 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
190 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
190 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
191 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
191 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
192 if self.show:
192 if self.show:
193 fig.show()
193 fig.show()
194
194
195 def OnKeyPress(self, event):
195 def OnKeyPress(self, event):
196 '''
196 '''
197 Event for pressing keys (up, down) change colormap
197 Event for pressing keys (up, down) change colormap
198 '''
198 '''
199 ax = event.inaxes
199 ax = event.inaxes
200 if ax in self.axes:
200 if ax in self.axes:
201 if event.key == 'down':
201 if event.key == 'down':
202 ax.index += 1
202 ax.index += 1
203 elif event.key == 'up':
203 elif event.key == 'up':
204 ax.index -= 1
204 ax.index -= 1
205 if ax.index < 0:
205 if ax.index < 0:
206 ax.index = len(CMAPS) - 1
206 ax.index = len(CMAPS) - 1
207 elif ax.index == len(CMAPS):
207 elif ax.index == len(CMAPS):
208 ax.index = 0
208 ax.index = 0
209 cmap = CMAPS[ax.index]
209 cmap = CMAPS[ax.index]
210 ax.cbar.set_cmap(cmap)
210 ax.cbar.set_cmap(cmap)
211 ax.cbar.draw_all()
211 ax.cbar.draw_all()
212 ax.plt.set_cmap(cmap)
212 ax.plt.set_cmap(cmap)
213 ax.cbar.patch.figure.canvas.draw()
213 ax.cbar.patch.figure.canvas.draw()
214 self.colormap = cmap.name
214 self.colormap = cmap.name
215
215
216 def OnBtnScroll(self, event):
216 def OnBtnScroll(self, event):
217 '''
217 '''
218 Event for scrolling, scale figure
218 Event for scrolling, scale figure
219 '''
219 '''
220 cb_ax = event.inaxes
220 cb_ax = event.inaxes
221 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
221 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
222 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
222 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
223 pt = ax.cbar.ax.bbox.get_points()[:, 1]
223 pt = ax.cbar.ax.bbox.get_points()[:, 1]
224 nrm = ax.cbar.norm
224 nrm = ax.cbar.norm
225 vmin, vmax, p0, p1, pS = (
225 vmin, vmax, p0, p1, pS = (
226 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
226 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
227 scale = 2 if event.step == 1 else 0.5
227 scale = 2 if event.step == 1 else 0.5
228 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
228 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
229 ax.cbar.norm.vmin = point - scale * (point - vmin)
229 ax.cbar.norm.vmin = point - scale * (point - vmin)
230 ax.cbar.norm.vmax = point - scale * (point - vmax)
230 ax.cbar.norm.vmax = point - scale * (point - vmax)
231 ax.plt.set_norm(ax.cbar.norm)
231 ax.plt.set_norm(ax.cbar.norm)
232 ax.cbar.draw_all()
232 ax.cbar.draw_all()
233 ax.cbar.patch.figure.canvas.draw()
233 ax.cbar.patch.figure.canvas.draw()
234
234
235 def onBtnPress(self, event):
235 def onBtnPress(self, event):
236 '''
236 '''
237 Event for mouse button press
237 Event for mouse button press
238 '''
238 '''
239 cb_ax = event.inaxes
239 cb_ax = event.inaxes
240 if cb_ax is None:
240 if cb_ax is None:
241 return
241 return
242
242
243 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
243 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
244 cb_ax.press = event.x, event.y
244 cb_ax.press = event.x, event.y
245 else:
245 else:
246 cb_ax.press = None
246 cb_ax.press = None
247
247
248 def onMotion(self, event):
248 def onMotion(self, event):
249 '''
249 '''
250 Event for move inside colorbar
250 Event for move inside colorbar
251 '''
251 '''
252 cb_ax = event.inaxes
252 cb_ax = event.inaxes
253 if cb_ax is None:
253 if cb_ax is None:
254 return
254 return
255 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
255 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
256 return
256 return
257 if cb_ax.press is None:
257 if cb_ax.press is None:
258 return
258 return
259
259
260 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
260 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
261 xprev, yprev = cb_ax.press
261 xprev, yprev = cb_ax.press
262 dx = event.x - xprev
262 dx = event.x - xprev
263 dy = event.y - yprev
263 dy = event.y - yprev
264 cb_ax.press = event.x, event.y
264 cb_ax.press = event.x, event.y
265 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
265 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
266 perc = 0.03
266 perc = 0.03
267
267
268 if event.button == 1:
268 if event.button == 1:
269 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
269 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
270 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
270 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
271 elif event.button == 3:
271 elif event.button == 3:
272 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
272 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
273 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
273 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
274
274
275 ax.cbar.draw_all()
275 ax.cbar.draw_all()
276 ax.plt.set_norm(ax.cbar.norm)
276 ax.plt.set_norm(ax.cbar.norm)
277 ax.cbar.patch.figure.canvas.draw()
277 ax.cbar.patch.figure.canvas.draw()
278
278
279 def onBtnRelease(self, event):
279 def onBtnRelease(self, event):
280 '''
280 '''
281 Event for mouse button release
281 Event for mouse button release
282 '''
282 '''
283 cb_ax = event.inaxes
283 cb_ax = event.inaxes
284 if cb_ax is not None:
284 if cb_ax is not None:
285 cb_ax.press = None
285 cb_ax.press = None
286
286
287 def __add_axes(self, ax, size='30%', pad='8%'):
287 def __add_axes(self, ax, size='30%', pad='8%'):
288 '''
288 '''
289 Add new axes to the given figure
289 Add new axes to the given figure
290 '''
290 '''
291 divider = make_axes_locatable(ax)
291 divider = make_axes_locatable(ax)
292 nax = divider.new_horizontal(size=size, pad=pad)
292 nax = divider.new_horizontal(size=size, pad=pad)
293 ax.figure.add_axes(nax)
293 ax.figure.add_axes(nax)
294 return nax
294 return nax
295
295
296 self.setup()
296 self.setup()
297
297
298 def setup(self):
298 def setup(self):
299 '''
299 '''
300 This method should be implemented in the child class, the following
300 This method should be implemented in the child class, the following
301 attributes should be set:
301 attributes should be set:
302
302
303 self.nrows: number of rows
303 self.nrows: number of rows
304 self.ncols: number of cols
304 self.ncols: number of cols
305 self.nplots: number of plots (channels or pairs)
305 self.nplots: number of plots (channels or pairs)
306 self.ylabel: label for Y axes
306 self.ylabel: label for Y axes
307 self.titles: list of axes title
307 self.titles: list of axes title
308
308
309 '''
309 '''
310 raise(NotImplementedError, 'Implement this method in child class')
310 raise(NotImplementedError, 'Implement this method in child class')
311
311
312 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
312 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
313 '''
313 '''
314 Create a masked array for missing data
314 Create a masked array for missing data
315 '''
315 '''
316 if x_buffer.shape[0] < 2:
316 if x_buffer.shape[0] < 2:
317 return x_buffer, y_buffer, z_buffer
317 return x_buffer, y_buffer, z_buffer
318
318
319 deltas = x_buffer[1:] - x_buffer[0:-1]
319 deltas = x_buffer[1:] - x_buffer[0:-1]
320 x_median = numpy.median(deltas)
320 x_median = numpy.median(deltas)
321
321
322 index = numpy.where(deltas > 5 * x_median)
322 index = numpy.where(deltas > 5 * x_median)
323
323
324 if len(index[0]) != 0:
324 if len(index[0]) != 0:
325 z_buffer[::, index[0], ::] = self.__missing
325 z_buffer[::, index[0], ::] = self.__missing
326 z_buffer = numpy.ma.masked_inside(z_buffer,
326 z_buffer = numpy.ma.masked_inside(z_buffer,
327 0.99 * self.__missing,
327 0.99 * self.__missing,
328 1.01 * self.__missing)
328 1.01 * self.__missing)
329
329
330 return x_buffer, y_buffer, z_buffer
330 return x_buffer, y_buffer, z_buffer
331
331
332 def decimate(self):
332 def decimate(self):
333
333
334 # dx = int(len(self.x)/self.__MAXNUMX) + 1
334 # dx = int(len(self.x)/self.__MAXNUMX) + 1
335 dy = int(len(self.y) / self.decimation) + 1
335 dy = int(len(self.y) / self.decimation) + 1
336
336
337 # x = self.x[::dx]
337 # x = self.x[::dx]
338 x = self.x
338 x = self.x
339 y = self.y[::dy]
339 y = self.y[::dy]
340 z = self.z[::, ::, ::dy]
340 z = self.z[::, ::, ::dy]
341
341
342 return x, y, z
342 return x, y, z
343
343
344 def format(self):
344 def format(self):
345 '''
345 '''
346 Set min and max values, labels, ticks and titles
346 Set min and max values, labels, ticks and titles
347 '''
347 '''
348
348
349 if self.xmin is None:
349 if self.xmin is None:
350 xmin = self.min_time
350 xmin = self.min_time
351 else:
351 else:
352 if self.xaxis is 'time':
352 if self.xaxis is 'time':
353 dt = self.getDateTime(self.min_time)
353 dt = self.getDateTime(self.min_time)
354 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
354 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
355 datetime.datetime(1970, 1, 1)).total_seconds()
355 datetime.datetime(1970, 1, 1)).total_seconds()
356 if self.data.localtime:
356 if self.data.localtime:
357 xmin += time.timezone
357 xmin += time.timezone
358 else:
358 else:
359 xmin = self.xmin
359 xmin = self.xmin
360
360
361 if self.xmax is None:
361 if self.xmax is None:
362 xmax = xmin + self.xrange * 60 * 60
362 xmax = xmin + self.xrange * 60 * 60
363 else:
363 else:
364 if self.xaxis is 'time':
364 if self.xaxis is 'time':
365 dt = self.getDateTime(self.max_time)
365 dt = self.getDateTime(self.max_time)
366 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
366 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
367 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
367 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
368 if self.data.localtime:
368 if self.data.localtime:
369 xmax += time.timezone
369 xmax += time.timezone
370 else:
370 else:
371 xmax = self.xmax
371 xmax = self.xmax
372
372
373 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
373 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
374 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
374 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
375
375
376 Y = numpy.array([5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000])
376 Y = numpy.array([5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000])
377 i = 1 if numpy.where(abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
377 i = 1 if numpy.where(abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
378 ystep = Y[i] / 5.
378 ystep = Y[i] / 5.
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 ax.set_facecolor(self.bgcolor)
382 ax.set_facecolor(self.bgcolor)
383 ax.yaxis.set_major_locator(MultipleLocator(ystep))
383 ax.yaxis.set_major_locator(MultipleLocator(ystep))
384 ax.xaxis.set_major_locator(MultipleLocator(ystep))
384 ax.xaxis.set_major_locator(MultipleLocator(ystep))
385 if self.xscale:
385 if self.xscale:
386 ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{0:g}'.format(x*self.xscale)))
386 ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{0:g}'.format(x*self.xscale)))
387 if self.xscale:
387 if self.xscale:
388 ax.yaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{0:g}'.format(x*self.yscale)))
388 ax.yaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{0:g}'.format(x*self.yscale)))
389 if self.xaxis is 'time':
389 if self.xaxis is 'time':
390 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
390 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
391 ax.xaxis.set_major_locator(LinearLocator(9))
391 ax.xaxis.set_major_locator(LinearLocator(9))
392 if self.xlabel is not None:
392 if self.xlabel is not None:
393 ax.set_xlabel(self.xlabel)
393 ax.set_xlabel(self.xlabel)
394 ax.set_ylabel(self.ylabel)
394 ax.set_ylabel(self.ylabel)
395 ax.firsttime = False
395 ax.firsttime = False
396 if self.showprofile:
396 if self.showprofile:
397 self.pf_axes[n].set_ylim(ymin, ymax)
397 self.pf_axes[n].set_ylim(ymin, ymax)
398 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
398 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
399 self.pf_axes[n].set_xlabel('dB')
399 self.pf_axes[n].set_xlabel('dB')
400 self.pf_axes[n].grid(b=True, axis='x')
400 self.pf_axes[n].grid(b=True, axis='x')
401 [tick.set_visible(False)
401 [tick.set_visible(False)
402 for tick in self.pf_axes[n].get_yticklabels()]
402 for tick in self.pf_axes[n].get_yticklabels()]
403 if self.colorbar:
403 if self.colorbar:
404 ax.cbar = plt.colorbar(
404 ax.cbar = plt.colorbar(
405 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
405 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
406 ax.cbar.ax.tick_params(labelsize=8)
406 ax.cbar.ax.tick_params(labelsize=8)
407 ax.cbar.ax.press = None
407 ax.cbar.ax.press = None
408 if self.cb_label:
408 if self.cb_label:
409 ax.cbar.set_label(self.cb_label, size=8)
409 ax.cbar.set_label(self.cb_label, size=8)
410 elif self.cb_labels:
410 elif self.cb_labels:
411 ax.cbar.set_label(self.cb_labels[n], size=8)
411 ax.cbar.set_label(self.cb_labels[n], size=8)
412 else:
412 else:
413 ax.cbar = None
413 ax.cbar = None
414
414
415 if not self.polar:
415 if not self.polar:
416 ax.set_xlim(xmin, xmax)
416 ax.set_xlim(xmin, xmax)
417 ax.set_ylim(ymin, ymax)
417 ax.set_ylim(ymin, ymax)
418 ax.set_title('{} - {} {}'.format(
418 ax.set_title('{} - {} {}'.format(
419 self.titles[n],
419 self.titles[n],
420 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
420 self.getDateTime(self.max_time).strftime('%H:%M:%S'),
421 self.time_label),
421 self.time_label),
422 size=8)
422 size=8)
423 else:
423 else:
424 ax.set_title('{}'.format(self.titles[n]), size=8)
424 ax.set_title('{}'.format(self.titles[n]), size=8)
425 ax.set_ylim(0, 90)
425 ax.set_ylim(0, 90)
426 ax.set_yticks(numpy.arange(0, 90, 20))
426 ax.set_yticks(numpy.arange(0, 90, 20))
427 ax.yaxis.labelpad = 40
427 ax.yaxis.labelpad = 40
428
428
429 def __plot(self):
429 def __plot(self):
430 '''
430 '''
431 '''
431 '''
432 log.log('Plotting', self.name)
432 log.log('Plotting', self.name)
433
433
434 try:
434 try:
435 self.plot()
435 self.plot()
436 self.format()
436 self.format()
437 except:
437 except:
438 log.warning('{} Plot could not be updated... check data'.format(self.CODE), self.name)
438 log.warning('{} Plot could not be updated... check data'.format(self.CODE), self.name)
439
439
440 for n, fig in enumerate(self.figures):
440 for n, fig in enumerate(self.figures):
441 if self.nrows == 0 or self.nplots == 0:
441 if self.nrows == 0 or self.nplots == 0:
442 log.warning('No data', self.name)
442 log.warning('No data', self.name)
443 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
443 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
444 fig.canvas.manager.set_window_title(self.CODE)
444 fig.canvas.manager.set_window_title(self.CODE)
445 continue
445 continue
446
446
447 fig.tight_layout()
447 fig.tight_layout()
448 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
448 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
449 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
449 self.getDateTime(self.max_time).strftime('%Y/%m/%d')))
450 fig.canvas.draw()
450 fig.canvas.draw()
451
451
452 if self.save and (self.data.ended or not self.data.buffering):
452 if self.save and (self.data.ended or not self.data.buffering):
453
453
454 if self.labels:
454 if self.labels:
455 labels = self.labels
455 labels = self.labels
456 else:
456 else:
457 labels = range(self.nrows)
457 labels = range(self.nrows)
458
458
459 if self.oneFigure:
459 if self.oneFigure:
460 label = ''
460 label = ''
461 else:
461 else:
462 label = '-{}'.format(labels[n])
462 label = '-{}'.format(labels[n])
463 figname = os.path.join(
463 figname = os.path.join(
464 self.save,
464 self.save,
465 self.CODE,
465 self.CODE,
466 '{}{}_{}.png'.format(
466 '{}{}_{}.png'.format(
467 self.CODE,
467 self.CODE,
468 label,
468 label,
469 self.getDateTime(self.saveTime).strftime(
469 self.getDateTime(self.saveTime).strftime(
470 '%Y%m%d_%H%M%S'),
470 '%Y%m%d_%H%M%S'),
471 )
471 )
472 )
472 )
473 log.log('Saving figure: {}'.format(figname), self.name)
473 log.log('Saving figure: {}'.format(figname), self.name)
474 if not os.path.isdir(os.path.dirname(figname)):
474 if not os.path.isdir(os.path.dirname(figname)):
475 os.makedirs(os.path.dirname(figname))
475 os.makedirs(os.path.dirname(figname))
476 fig.savefig(figname)
476 fig.savefig(figname)
477
477
478 def plot(self):
478 def plot(self):
479 '''
479 '''
480 '''
480 '''
481 raise(NotImplementedError, 'Implement this method in child class')
481 raise(NotImplementedError, 'Implement this method in child class')
482
482
483 def run(self):
483 def run(self):
484
484
485 log.log('Starting', self.name)
485 log.log('Starting', self.name)
486
486
487 context = zmq.Context()
487 context = zmq.Context()
488 receiver = context.socket(zmq.SUB)
488 receiver = context.socket(zmq.SUB)
489 receiver.setsockopt(zmq.SUBSCRIBE, '')
489 receiver.setsockopt(zmq.SUBSCRIBE, '')
490 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
490 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
491
491
492 if 'server' in self.kwargs['parent']:
492 if 'server' in self.kwargs['parent']:
493 receiver.connect(
493 receiver.connect(
494 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
494 'ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
495 else:
495 else:
496 receiver.connect("ipc:///tmp/zmq.plots")
496 receiver.connect("ipc:///tmp/zmq.plots")
497
497
498 while True:
498 while True:
499 try:
499 try:
500 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
500 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
501 if self.data.localtime and self.localtime:
501 if self.data.localtime and self.localtime:
502 self.times = self.data.times
502 self.times = self.data.times
503 elif self.data.localtime and not self.localtime:
503 elif self.data.localtime and not self.localtime:
504 self.times = self.data.times + time.timezone
504 self.times = self.data.times + time.timezone
505 elif not self.data.localtime and self.localtime:
505 elif not self.data.localtime and self.localtime:
506 self.times = self.data.times - time.timezone
506 self.times = self.data.times - time.timezone
507 else:
507 else:
508 self.times = self.data.times
508 self.times = self.data.times
509
509
510 self.min_time = self.times[0]
510 self.min_time = self.times[0]
511 self.max_time = self.times[-1]
511 self.max_time = self.times[-1]
512
512
513 if self.isConfig is False:
513 if self.isConfig is False:
514 self.__setup()
514 self.__setup()
515 self.isConfig = True
515 self.isConfig = True
516
516
517 self.__plot()
517 self.__plot()
518
518
519 except zmq.Again as e:
519 except zmq.Again as e:
520 log.log('.', tag='', nl=False)
520 # log.log('.', tag='', nl=False)
521 if self.data:
521 if self.data:
522 figpause(self.data.throttle)
522 figpause(self.data.throttle)
523 else:
523 else:
524 time.sleep(2)
524 time.sleep(2)
525
525
526 def close(self):
526 def close(self):
527 if self.data:
527 if self.data:
528 self.__plot()
528 self.__plot()
529
529
530
530
531 class PlotSpectraData(PlotData):
531 class PlotSpectraData(PlotData):
532 '''
532 '''
533 Plot for Spectra data
533 Plot for Spectra data
534 '''
534 '''
535
535
536 CODE = 'spc'
536 CODE = 'spc'
537 colormap = 'jro'
537 colormap = 'jro'
538
538
539 def setup(self):
539 def setup(self):
540 self.nplots = len(self.data.channels)
540 self.nplots = len(self.data.channels)
541 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
541 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
542 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
542 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
543 self.width = 3.4 * self.ncols
543 self.width = 3.4 * self.ncols
544 self.height = 3 * self.nrows
544 self.height = 3 * self.nrows
545 self.cb_label = 'dB'
545 self.cb_label = 'dB'
546 if self.showprofile:
546 if self.showprofile:
547 self.width += 0.8 * self.ncols
547 self.width += 0.8 * self.ncols
548
548
549 self.ylabel = 'Range [km]'
549 self.ylabel = 'Range [km]'
550
550
551 def plot(self):
551 def plot(self):
552 if self.xaxis == "frequency":
552 if self.xaxis == "frequency":
553 x = self.data.xrange[0]
553 x = self.data.xrange[0]
554 self.xlabel = "Frequency (kHz)"
554 self.xlabel = "Frequency (kHz)"
555 elif self.xaxis == "time":
555 elif self.xaxis == "time":
556 x = self.data.xrange[1]
556 x = self.data.xrange[1]
557 self.xlabel = "Time (ms)"
557 self.xlabel = "Time (ms)"
558 else:
558 else:
559 x = self.data.xrange[2]
559 x = self.data.xrange[2]
560 self.xlabel = "Velocity (m/s)"
560 self.xlabel = "Velocity (m/s)"
561
561
562 if self.CODE == 'spc_mean':
562 if self.CODE == 'spc_mean':
563 x = self.data.xrange[2]
563 x = self.data.xrange[2]
564 self.xlabel = "Velocity (m/s)"
564 self.xlabel = "Velocity (m/s)"
565
565
566 self.titles = []
566 self.titles = []
567
567
568 y = self.data.heights
568 y = self.data.heights
569 self.y = y
569 self.y = y
570 z = self.data['spc']
570 z = self.data['spc']
571
571
572 for n, ax in enumerate(self.axes):
572 for n, ax in enumerate(self.axes):
573 noise = self.data['noise'][n][-1]
573 noise = self.data['noise'][n][-1]
574 if self.CODE == 'spc_mean':
574 if self.CODE == 'spc_mean':
575 mean = self.data['mean'][n][-1]
575 mean = self.data['mean'][n][-1]
576 if ax.firsttime:
576 if ax.firsttime:
577 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
577 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
578 self.xmin = self.xmin if self.xmin else -self.xmax
578 self.xmin = self.xmin if self.xmin else -self.xmax
579 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
579 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
580 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
580 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
581 ax.plt = ax.pcolormesh(x, y, z[n].T,
581 ax.plt = ax.pcolormesh(x, y, z[n].T,
582 vmin=self.zmin,
582 vmin=self.zmin,
583 vmax=self.zmax,
583 vmax=self.zmax,
584 cmap=plt.get_cmap(self.colormap)
584 cmap=plt.get_cmap(self.colormap)
585 )
585 )
586
586
587 if self.showprofile:
587 if self.showprofile:
588 ax.plt_profile = self.pf_axes[n].plot(
588 ax.plt_profile = self.pf_axes[n].plot(
589 self.data['rti'][n][-1], y)[0]
589 self.data['rti'][n][-1], y)[0]
590 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
590 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
591 color="k", linestyle="dashed", lw=1)[0]
591 color="k", linestyle="dashed", lw=1)[0]
592 if self.CODE == 'spc_mean':
592 if self.CODE == 'spc_mean':
593 ax.plt_mean = ax.plot(mean, y, color='k')[0]
593 ax.plt_mean = ax.plot(mean, y, color='k')[0]
594 else:
594 else:
595 ax.plt.set_array(z[n].T.ravel())
595 ax.plt.set_array(z[n].T.ravel())
596 if self.showprofile:
596 if self.showprofile:
597 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
597 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
598 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
598 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
599 if self.CODE == 'spc_mean':
599 if self.CODE == 'spc_mean':
600 ax.plt_mean.set_data(mean, y)
600 ax.plt_mean.set_data(mean, y)
601
601
602 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
602 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
603 self.saveTime = self.max_time
603 self.saveTime = self.max_time
604
604
605
605
606 class PlotCrossSpectraData(PlotData):
606 class PlotCrossSpectraData(PlotData):
607
607
608 CODE = 'cspc'
608 CODE = 'cspc'
609 zmin_coh = None
609 zmin_coh = None
610 zmax_coh = None
610 zmax_coh = None
611 zmin_phase = None
611 zmin_phase = None
612 zmax_phase = None
612 zmax_phase = None
613
613
614 def setup(self):
614 def setup(self):
615
615
616 self.ncols = 4
616 self.ncols = 4
617 self.nrows = len(self.data.pairs)
617 self.nrows = len(self.data.pairs)
618 self.nplots = self.nrows * 4
618 self.nplots = self.nrows * 4
619 self.width = 3.4 * self.ncols
619 self.width = 3.4 * self.ncols
620 self.height = 3 * self.nrows
620 self.height = 3 * self.nrows
621 self.ylabel = 'Range [km]'
621 self.ylabel = 'Range [km]'
622 self.showprofile = False
622 self.showprofile = False
623
623
624 def plot(self):
624 def plot(self):
625
625
626 if self.xaxis == "frequency":
626 if self.xaxis == "frequency":
627 x = self.data.xrange[0]
627 x = self.data.xrange[0]
628 self.xlabel = "Frequency (kHz)"
628 self.xlabel = "Frequency (kHz)"
629 elif self.xaxis == "time":
629 elif self.xaxis == "time":
630 x = self.data.xrange[1]
630 x = self.data.xrange[1]
631 self.xlabel = "Time (ms)"
631 self.xlabel = "Time (ms)"
632 else:
632 else:
633 x = self.data.xrange[2]
633 x = self.data.xrange[2]
634 self.xlabel = "Velocity (m/s)"
634 self.xlabel = "Velocity (m/s)"
635
635
636 self.titles = []
636 self.titles = []
637
637
638 y = self.data.heights
638 y = self.data.heights
639 self.y = y
639 self.y = y
640 spc = self.data['spc']
640 spc = self.data['spc']
641 cspc = self.data['cspc']
641 cspc = self.data['cspc']
642
642
643 for n in range(self.nrows):
643 for n in range(self.nrows):
644 noise = self.data['noise'][n][-1]
644 noise = self.data['noise'][n][-1]
645 pair = self.data.pairs[n]
645 pair = self.data.pairs[n]
646 ax = self.axes[4 * n]
646 ax = self.axes[4 * n]
647 ax3 = self.axes[4 * n + 3]
647 ax3 = self.axes[4 * n + 3]
648 if ax.firsttime:
648 if ax.firsttime:
649 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
649 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
650 self.xmin = self.xmin if self.xmin else -self.xmax
650 self.xmin = self.xmin if self.xmin else -self.xmax
651 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
651 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
652 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
652 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
653 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
653 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
654 vmin=self.zmin,
654 vmin=self.zmin,
655 vmax=self.zmax,
655 vmax=self.zmax,
656 cmap=plt.get_cmap(self.colormap)
656 cmap=plt.get_cmap(self.colormap)
657 )
657 )
658 else:
658 else:
659 ax.plt.set_array(spc[pair[0]].T.ravel())
659 ax.plt.set_array(spc[pair[0]].T.ravel())
660 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
660 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
661
661
662 ax = self.axes[4 * n + 1]
662 ax = self.axes[4 * n + 1]
663 if ax.firsttime:
663 if ax.firsttime:
664 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
664 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
665 vmin=self.zmin,
665 vmin=self.zmin,
666 vmax=self.zmax,
666 vmax=self.zmax,
667 cmap=plt.get_cmap(self.colormap)
667 cmap=plt.get_cmap(self.colormap)
668 )
668 )
669 else:
669 else:
670 ax.plt.set_array(spc[pair[1]].T.ravel())
670 ax.plt.set_array(spc[pair[1]].T.ravel())
671 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
671 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
672
672
673 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
673 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
674 coh = numpy.abs(out)
674 coh = numpy.abs(out)
675 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
675 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
676
676
677 ax = self.axes[4 * n + 2]
677 ax = self.axes[4 * n + 2]
678 if ax.firsttime:
678 if ax.firsttime:
679 ax.plt = ax.pcolormesh(x, y, coh.T,
679 ax.plt = ax.pcolormesh(x, y, coh.T,
680 vmin=0,
680 vmin=0,
681 vmax=1,
681 vmax=1,
682 cmap=plt.get_cmap(self.colormap_coh)
682 cmap=plt.get_cmap(self.colormap_coh)
683 )
683 )
684 else:
684 else:
685 ax.plt.set_array(coh.T.ravel())
685 ax.plt.set_array(coh.T.ravel())
686 self.titles.append(
686 self.titles.append(
687 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
687 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
688
688
689 ax = self.axes[4 * n + 3]
689 ax = self.axes[4 * n + 3]
690 if ax.firsttime:
690 if ax.firsttime:
691 ax.plt = ax.pcolormesh(x, y, phase.T,
691 ax.plt = ax.pcolormesh(x, y, phase.T,
692 vmin=-180,
692 vmin=-180,
693 vmax=180,
693 vmax=180,
694 cmap=plt.get_cmap(self.colormap_phase)
694 cmap=plt.get_cmap(self.colormap_phase)
695 )
695 )
696 else:
696 else:
697 ax.plt.set_array(phase.T.ravel())
697 ax.plt.set_array(phase.T.ravel())
698 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
698 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
699
699
700 self.saveTime = self.max_time
700 self.saveTime = self.max_time
701
701
702
702
703 class PlotSpectraMeanData(PlotSpectraData):
703 class PlotSpectraMeanData(PlotSpectraData):
704 '''
704 '''
705 Plot for Spectra and Mean
705 Plot for Spectra and Mean
706 '''
706 '''
707 CODE = 'spc_mean'
707 CODE = 'spc_mean'
708 colormap = 'jro'
708 colormap = 'jro'
709
709
710
710
711 class PlotRTIData(PlotData):
711 class PlotRTIData(PlotData):
712 '''
712 '''
713 Plot for RTI data
713 Plot for RTI data
714 '''
714 '''
715
715
716 CODE = 'rti'
716 CODE = 'rti'
717 colormap = 'jro'
717 colormap = 'jro'
718
718
719 def setup(self):
719 def setup(self):
720 self.xaxis = 'time'
720 self.xaxis = 'time'
721 self.ncols = 1
721 self.ncols = 1
722 self.nrows = len(self.data.channels)
722 self.nrows = len(self.data.channels)
723 self.nplots = len(self.data.channels)
723 self.nplots = len(self.data.channels)
724 self.ylabel = 'Range [km]'
724 self.ylabel = 'Range [km]'
725 self.cb_label = 'dB'
725 self.cb_label = 'dB'
726 self.titles = ['{} Channel {}'.format(
726 self.titles = ['{} Channel {}'.format(
727 self.CODE.upper(), x) for x in range(self.nrows)]
727 self.CODE.upper(), x) for x in range(self.nrows)]
728
728
729 def plot(self):
729 def plot(self):
730 self.x = self.times
730 self.x = self.times
731 self.y = self.data.heights
731 self.y = self.data.heights
732 self.z = self.data[self.CODE]
732 self.z = self.data[self.CODE]
733 self.z = numpy.ma.masked_invalid(self.z)
733 self.z = numpy.ma.masked_invalid(self.z)
734
734
735 if self.decimation is None:
735 if self.decimation is None:
736 x, y, z = self.fill_gaps(self.x, self.y, self.z)
736 x, y, z = self.fill_gaps(self.x, self.y, self.z)
737 else:
737 else:
738 x, y, z = self.fill_gaps(*self.decimate())
738 x, y, z = self.fill_gaps(*self.decimate())
739
739
740 for n, ax in enumerate(self.axes):
740 for n, ax in enumerate(self.axes):
741 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
741 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
742 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
742 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
743 if ax.firsttime:
743 if ax.firsttime:
744 ax.plt = ax.pcolormesh(x, y, z[n].T,
744 ax.plt = ax.pcolormesh(x, y, z[n].T,
745 vmin=self.zmin,
745 vmin=self.zmin,
746 vmax=self.zmax,
746 vmax=self.zmax,
747 cmap=plt.get_cmap(self.colormap)
747 cmap=plt.get_cmap(self.colormap)
748 )
748 )
749 if self.showprofile:
749 if self.showprofile:
750 ax.plot_profile = self.pf_axes[n].plot(
750 ax.plot_profile = self.pf_axes[n].plot(
751 self.data['rti'][n][-1], self.y)[0]
751 self.data['rti'][n][-1], self.y)[0]
752 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
752 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
753 color="k", linestyle="dashed", lw=1)[0]
753 color="k", linestyle="dashed", lw=1)[0]
754 else:
754 else:
755 ax.collections.remove(ax.collections[0])
755 ax.collections.remove(ax.collections[0])
756 ax.plt = ax.pcolormesh(x, y, z[n].T,
756 ax.plt = ax.pcolormesh(x, y, z[n].T,
757 vmin=self.zmin,
757 vmin=self.zmin,
758 vmax=self.zmax,
758 vmax=self.zmax,
759 cmap=plt.get_cmap(self.colormap)
759 cmap=plt.get_cmap(self.colormap)
760 )
760 )
761 if self.showprofile:
761 if self.showprofile:
762 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
762 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
763 ax.plot_noise.set_data(numpy.repeat(
763 ax.plot_noise.set_data(numpy.repeat(
764 self.data['noise'][n][-1], len(self.y)), self.y)
764 self.data['noise'][n][-1], len(self.y)), self.y)
765
765
766 self.saveTime = self.min_time
766 self.saveTime = self.min_time
767
767
768
768
769 class PlotCOHData(PlotRTIData):
769 class PlotCOHData(PlotRTIData):
770 '''
770 '''
771 Plot for Coherence data
771 Plot for Coherence data
772 '''
772 '''
773
773
774 CODE = 'coh'
774 CODE = 'coh'
775
775
776 def setup(self):
776 def setup(self):
777 self.xaxis = 'time'
777 self.xaxis = 'time'
778 self.ncols = 1
778 self.ncols = 1
779 self.nrows = len(self.data.pairs)
779 self.nrows = len(self.data.pairs)
780 self.nplots = len(self.data.pairs)
780 self.nplots = len(self.data.pairs)
781 self.ylabel = 'Range [km]'
781 self.ylabel = 'Range [km]'
782 if self.CODE == 'coh':
782 if self.CODE == 'coh':
783 self.cb_label = ''
783 self.cb_label = ''
784 self.titles = [
784 self.titles = [
785 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
785 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
786 else:
786 else:
787 self.cb_label = 'Degrees'
787 self.cb_label = 'Degrees'
788 self.titles = [
788 self.titles = [
789 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
789 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
790
790
791
791
792 class PlotPHASEData(PlotCOHData):
792 class PlotPHASEData(PlotCOHData):
793 '''
793 '''
794 Plot for Phase map data
794 Plot for Phase map data
795 '''
795 '''
796
796
797 CODE = 'phase'
797 CODE = 'phase'
798 colormap = 'seismic'
798 colormap = 'seismic'
799
799
800
800
801 class PlotNoiseData(PlotData):
801 class PlotNoiseData(PlotData):
802 '''
802 '''
803 Plot for noise
803 Plot for noise
804 '''
804 '''
805
805
806 CODE = 'noise'
806 CODE = 'noise'
807
807
808 def setup(self):
808 def setup(self):
809 self.xaxis = 'time'
809 self.xaxis = 'time'
810 self.ncols = 1
810 self.ncols = 1
811 self.nrows = 1
811 self.nrows = 1
812 self.nplots = 1
812 self.nplots = 1
813 self.ylabel = 'Intensity [dB]'
813 self.ylabel = 'Intensity [dB]'
814 self.titles = ['Noise']
814 self.titles = ['Noise']
815 self.colorbar = False
815 self.colorbar = False
816
816
817 def plot(self):
817 def plot(self):
818
818
819 x = self.times
819 x = self.times
820 xmin = self.min_time
820 xmin = self.min_time
821 xmax = xmin + self.xrange * 60 * 60
821 xmax = xmin + self.xrange * 60 * 60
822 Y = self.data[self.CODE]
822 Y = self.data[self.CODE]
823
823
824 if self.axes[0].firsttime:
824 if self.axes[0].firsttime:
825 for ch in self.data.channels:
825 for ch in self.data.channels:
826 y = Y[ch]
826 y = Y[ch]
827 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
827 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
828 plt.legend()
828 plt.legend()
829 else:
829 else:
830 for ch in self.data.channels:
830 for ch in self.data.channels:
831 y = Y[ch]
831 y = Y[ch]
832 self.axes[0].lines[ch].set_data(x, y)
832 self.axes[0].lines[ch].set_data(x, y)
833
833
834 self.ymin = numpy.nanmin(Y) - 5
834 self.ymin = numpy.nanmin(Y) - 5
835 self.ymax = numpy.nanmax(Y) + 5
835 self.ymax = numpy.nanmax(Y) + 5
836 self.saveTime = self.min_time
836 self.saveTime = self.min_time
837
837
838
838
839 class PlotSNRData(PlotRTIData):
839 class PlotSNRData(PlotRTIData):
840 '''
840 '''
841 Plot for SNR Data
841 Plot for SNR Data
842 '''
842 '''
843
843
844 CODE = 'snr'
844 CODE = 'snr'
845 colormap = 'jet'
845 colormap = 'jet'
846
846
847
847
848 class PlotDOPData(PlotRTIData):
848 class PlotDOPData(PlotRTIData):
849 '''
849 '''
850 Plot for DOPPLER Data
850 Plot for DOPPLER Data
851 '''
851 '''
852
852
853 CODE = 'dop'
853 CODE = 'dop'
854 colormap = 'jet'
854 colormap = 'jet'
855
855
856
856
857 class PlotSkyMapData(PlotData):
857 class PlotSkyMapData(PlotData):
858 '''
858 '''
859 Plot for meteors detection data
859 Plot for meteors detection data
860 '''
860 '''
861
861
862 CODE = 'param'
862 CODE = 'param'
863
863
864 def setup(self):
864 def setup(self):
865
865
866 self.ncols = 1
866 self.ncols = 1
867 self.nrows = 1
867 self.nrows = 1
868 self.width = 7.2
868 self.width = 7.2
869 self.height = 7.2
869 self.height = 7.2
870 self.nplots = 1
870 self.nplots = 1
871 self.xlabel = 'Zonal Zenith Angle (deg)'
871 self.xlabel = 'Zonal Zenith Angle (deg)'
872 self.ylabel = 'Meridional Zenith Angle (deg)'
872 self.ylabel = 'Meridional Zenith Angle (deg)'
873 self.polar = True
873 self.polar = True
874 self.ymin = -180
874 self.ymin = -180
875 self.ymax = 180
875 self.ymax = 180
876 self.colorbar = False
876 self.colorbar = False
877
877
878 def plot(self):
878 def plot(self):
879
879
880 arrayParameters = numpy.concatenate(self.data['param'])
880 arrayParameters = numpy.concatenate(self.data['param'])
881 error = arrayParameters[:, -1]
881 error = arrayParameters[:, -1]
882 indValid = numpy.where(error == 0)[0]
882 indValid = numpy.where(error == 0)[0]
883 finalMeteor = arrayParameters[indValid, :]
883 finalMeteor = arrayParameters[indValid, :]
884 finalAzimuth = finalMeteor[:, 3]
884 finalAzimuth = finalMeteor[:, 3]
885 finalZenith = finalMeteor[:, 4]
885 finalZenith = finalMeteor[:, 4]
886
886
887 x = finalAzimuth * numpy.pi / 180
887 x = finalAzimuth * numpy.pi / 180
888 y = finalZenith
888 y = finalZenith
889
889
890 ax = self.axes[0]
890 ax = self.axes[0]
891
891
892 if ax.firsttime:
892 if ax.firsttime:
893 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
893 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
894 else:
894 else:
895 ax.plot.set_data(x, y)
895 ax.plot.set_data(x, y)
896
896
897 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
897 dt1 = self.getDateTime(self.min_time).strftime('%y/%m/%d %H:%M:%S')
898 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
898 dt2 = self.getDateTime(self.max_time).strftime('%y/%m/%d %H:%M:%S')
899 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
899 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
900 dt2,
900 dt2,
901 len(x))
901 len(x))
902 self.titles[0] = title
902 self.titles[0] = title
903 self.saveTime = self.max_time
903 self.saveTime = self.max_time
904
904
905
905
906 class PlotParamData(PlotRTIData):
906 class PlotParamData(PlotRTIData):
907 '''
907 '''
908 Plot for data_param object
908 Plot for data_param object
909 '''
909 '''
910
910
911 CODE = 'param'
911 CODE = 'param'
912 colormap = 'seismic'
912 colormap = 'seismic'
913
913
914 def setup(self):
914 def setup(self):
915 self.xaxis = 'time'
915 self.xaxis = 'time'
916 self.ncols = 1
916 self.ncols = 1
917 self.nrows = self.data.shape(self.CODE)[0]
917 self.nrows = self.data.shape(self.CODE)[0]
918 self.nplots = self.nrows
918 self.nplots = self.nrows
919 if self.showSNR:
919 if self.showSNR:
920 self.nrows += 1
920 self.nrows += 1
921 self.nplots += 1
921 self.nplots += 1
922
922
923 self.ylabel = 'Height [km]'
923 self.ylabel = 'Height [km]'
924 if not self.titles:
924 if not self.titles:
925 self.titles = self.data.parameters \
925 self.titles = self.data.parameters \
926 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
926 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
927 if self.showSNR:
927 if self.showSNR:
928 self.titles.append('SNR')
928 self.titles.append('SNR')
929
929
930 def plot(self):
930 def plot(self):
931 self.data.normalize_heights()
931 self.data.normalize_heights()
932 self.x = self.times
932 self.x = self.times
933 self.y = self.data.heights
933 self.y = self.data.heights
934 if self.showSNR:
934 if self.showSNR:
935 self.z = numpy.concatenate(
935 self.z = numpy.concatenate(
936 (self.data[self.CODE], self.data['snr'])
936 (self.data[self.CODE], self.data['snr'])
937 )
937 )
938 else:
938 else:
939 self.z = self.data[self.CODE]
939 self.z = self.data[self.CODE]
940
940
941 self.z = numpy.ma.masked_invalid(self.z)
941 self.z = numpy.ma.masked_invalid(self.z)
942
942
943 if self.decimation is None:
943 if self.decimation is None:
944 x, y, z = self.fill_gaps(self.x, self.y, self.z)
944 x, y, z = self.fill_gaps(self.x, self.y, self.z)
945 else:
945 else:
946 x, y, z = self.fill_gaps(*self.decimate())
946 x, y, z = self.fill_gaps(*self.decimate())
947
947
948 for n, ax in enumerate(self.axes):
948 for n, ax in enumerate(self.axes):
949
949
950 self.zmax = self.zmax if self.zmax is not None else numpy.max(
950 self.zmax = self.zmax if self.zmax is not None else numpy.max(
951 self.z[n])
951 self.z[n])
952 self.zmin = self.zmin if self.zmin is not None else numpy.min(
952 self.zmin = self.zmin if self.zmin is not None else numpy.min(
953 self.z[n])
953 self.z[n])
954
954
955 if ax.firsttime:
955 if ax.firsttime:
956 if self.zlimits is not None:
956 if self.zlimits is not None:
957 self.zmin, self.zmax = self.zlimits[n]
957 self.zmin, self.zmax = self.zlimits[n]
958
958
959 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
959 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
960 vmin=self.zmin,
960 vmin=self.zmin,
961 vmax=self.zmax,
961 vmax=self.zmax,
962 cmap=self.cmaps[n]
962 cmap=self.cmaps[n]
963 )
963 )
964 else:
964 else:
965 if self.zlimits is not None:
965 if self.zlimits is not None:
966 self.zmin, self.zmax = self.zlimits[n]
966 self.zmin, self.zmax = self.zlimits[n]
967 ax.collections.remove(ax.collections[0])
967 ax.collections.remove(ax.collections[0])
968 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
968 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
969 vmin=self.zmin,
969 vmin=self.zmin,
970 vmax=self.zmax,
970 vmax=self.zmax,
971 cmap=self.cmaps[n]
971 cmap=self.cmaps[n]
972 )
972 )
973
973
974 self.saveTime = self.min_time
974 self.saveTime = self.min_time
975
975
976
976
977 class PlotOutputData(PlotParamData):
977 class PlotOutputData(PlotParamData):
978 '''
978 '''
979 Plot data_output object
979 Plot data_output object
980 '''
980 '''
981
981
982 CODE = 'output'
982 CODE = 'output'
983 colormap = 'seismic'
983 colormap = 'seismic'
984
984
985
985
986 class PlotPolarMapData(PlotData):
986 class PlotPolarMapData(PlotData):
987 '''
987 '''
988 Plot for meteors detection data
988 Plot for meteors detection data
989 '''
989 '''
990
990
991 CODE = 'param'
991 CODE = 'param'
992 colormap = 'seismic'
992 colormap = 'seismic'
993
993
994 def setup(self):
994 def setup(self):
995 self.ncols = 1
995 self.ncols = 1
996 self.nrows = 1
996 self.nrows = 1
997 self.width = 9
997 self.width = 9
998 self.height = 8
998 self.height = 8
999 if self.channels is not None:
999 if self.channels is not None:
1000 self.nplots = len(self.channels)
1000 self.nplots = len(self.channels)
1001 self.nrows = len(self.channels)
1001 self.nrows = len(self.channels)
1002 else:
1002 else:
1003 self.nplots = self.data.shape(self.CODE)[0]
1003 self.nplots = self.data.shape(self.CODE)[0]
1004 self.nrows = self.nplots
1004 self.nrows = self.nplots
1005 self.channels = range(self.nplots)
1005 self.channels = range(self.nplots)
1006 self.xlabel = 'Zonal Distance (km)'
1006 self.xlabel = 'Zonal Distance (km)'
1007 self.ylabel = 'Meridional Distance (km)'
1007 self.ylabel = 'Meridional Distance (km)'
1008 self.bgcolor = 'white'
1008 self.bgcolor = 'white'
1009
1009
1010 def plot(self):
1010 def plot(self):
1011
1011
1012 for n, ax in enumerate(self.axes):
1012 for n, ax in enumerate(self.axes):
1013 data = self.data['param'][self.channels[n]]
1013 data = self.data['param'][self.channels[n]]
1014
1014
1015 zeniths = numpy.arange(data.shape[1])
1015 zeniths = numpy.arange(data.shape[1])
1016 azimuths = -numpy.radians(self.data.heights)+numpy.pi/2
1016 azimuths = -numpy.radians(self.data.heights)+numpy.pi/2
1017 self.y = zeniths
1017 self.y = zeniths
1018
1018
1019 r, theta = numpy.meshgrid(zeniths, azimuths)
1019 r, theta = numpy.meshgrid(zeniths, azimuths)
1020 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
1020 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
1021
1021
1022 if ax.firsttime:
1022 if ax.firsttime:
1023 if self.zlimits is not None:
1023 if self.zlimits is not None:
1024 self.zmin, self.zmax = self.zlimits[n]
1024 self.zmin, self.zmax = self.zlimits[n]
1025 ax.plt = ax.pcolormesh(x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
1025 ax.plt = ax.pcolormesh(x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
1026 vmin=self.zmin,
1026 vmin=self.zmin,
1027 vmax=self.zmax,
1027 vmax=self.zmax,
1028 cmap=self.cmaps[n])
1028 cmap=self.cmaps[n])
1029 else:
1029 else:
1030 if self.zlimits is not None:
1030 if self.zlimits is not None:
1031 self.zmin, self.zmax = self.zlimits[n]
1031 self.zmin, self.zmax = self.zlimits[n]
1032 ax.collections.remove(ax.collections[0])
1032 ax.collections.remove(ax.collections[0])
1033 ax.plt = ax.pcolormesh(x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
1033 ax.plt = ax.pcolormesh(x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
1034 vmin=self.zmin,
1034 vmin=self.zmin,
1035 vmax=self.zmax,
1035 vmax=self.zmax,
1036 cmap=self.cmaps[n])
1036 cmap=self.cmaps[n])
1037
1037
1038
1038
1039 title = ''
1039 title = ''
1040
1040
1041 self.titles = [self.data.parameters[x] for x in self.channels]
1041 self.titles = [self.data.parameters[x] for x in self.channels]
1042 self.saveTime = self.max_time
1042 self.saveTime = self.max_time
@@ -1,351 +1,354
1 '''
1 '''
2 Created on Dec 27, 2017
2 Created on Dec 27, 2017
3
3
4 @author: Juan C. Espinoza
4 @author: Juan C. Espinoza
5 '''
5 '''
6
6
7 import os
7 import os
8 import sys
8 import sys
9 import time
9 import time
10 import json
10 import json
11 import glob
11 import glob
12 import datetime
12 import datetime
13 import tarfile
13 import tarfile
14
14
15 import numpy
15 import numpy
16 from netCDF4 import Dataset
16 from netCDF4 import Dataset
17
17
18 from schainpy.model.io.jroIO_base import JRODataReader
18 from schainpy.model.io.jroIO_base import JRODataReader
19 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation
19 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation
20 from schainpy.model.data.jrodata import Parameters
20 from schainpy.model.data.jrodata import Parameters
21 from schainpy.utils import log
21 from schainpy.utils import log
22
22
23 UT1970 = datetime.datetime(1970, 1, 1) - datetime.timedelta(seconds=time.timezone)
23 UT1970 = datetime.datetime(1970, 1, 1) - datetime.timedelta(seconds=time.timezone)
24
24
25 def load_json(obj):
25 def load_json(obj):
26 '''
26 '''
27 Parse json as string instead of unicode
27 Parse json as string instead of unicode
28 '''
28 '''
29
29
30 if isinstance(obj, str):
30 if isinstance(obj, str):
31 iterable = json.loads(obj)
31 iterable = json.loads(obj)
32 else:
32 else:
33 iterable = obj
33 iterable = obj
34
34
35 if isinstance(iterable, dict):
35 if isinstance(iterable, dict):
36 return {str(k): load_json(v) if isinstance(v, dict) else str(v) if isinstance(v, unicode) else v
36 return {str(k): load_json(v) if isinstance(v, dict) else str(v) if isinstance(v, unicode) else v
37 for k, v in iterable.items()}
37 for k, v in iterable.items()}
38 elif isinstance(iterable, (list, tuple)):
38 elif isinstance(iterable, (list, tuple)):
39 return [str(v) if isinstance(v, unicode) else v for v in iterable]
39 return [str(v) if isinstance(v, unicode) else v for v in iterable]
40
40
41 return iterable
41 return iterable
42
42
43
43
44 class NCDFReader(JRODataReader, ProcessingUnit):
44 class NCDFReader(JRODataReader, ProcessingUnit):
45
45
46 def __init__(self, **kwargs):
46 def __init__(self, **kwargs):
47
47
48 ProcessingUnit.__init__(self, **kwargs)
48 ProcessingUnit.__init__(self, **kwargs)
49
49
50 self.dataOut = Parameters()
50 self.dataOut = Parameters()
51 self.counter_records = 0
51 self.counter_records = 0
52 self.nrecords = None
52 self.nrecords = None
53 self.flagNoMoreFiles = 0
53 self.flagNoMoreFiles = 0
54 self.isConfig = False
54 self.isConfig = False
55 self.filename = None
55 self.filename = None
56 self.intervals = set()
56 self.intervals = set()
57 self.ext = ('.nc', '.tgz')
57 self.ext = ('.nc', '.tgz')
58 self.online_mode = False
58 self.online_mode = False
59
59
60 def setup(self,
60 def setup(self,
61 path=None,
61 path=None,
62 startDate=None,
62 startDate=None,
63 endDate=None,
63 endDate=None,
64 format=None,
64 format=None,
65 startTime=datetime.time(0, 0, 0),
65 startTime=datetime.time(0, 0, 0),
66 endTime=datetime.time(23, 59, 59),
66 endTime=datetime.time(23, 59, 59),
67 walk=False,
67 walk=False,
68 **kwargs):
68 **kwargs):
69
69
70 self.path = path
70 self.path = path
71 self.startDate = startDate
71 self.startDate = startDate
72 self.endDate = endDate
72 self.endDate = endDate
73 self.startTime = startTime
73 self.startTime = startTime
74 self.endTime = endTime
74 self.endTime = endTime
75 self.datatime = datetime.datetime(1900,1,1)
75 self.datatime = datetime.datetime(1900,1,1)
76 self.walk = walk
76 self.walk = walk
77 self.nTries = kwargs.get('nTries', 3)
77 self.nTries = kwargs.get('nTries', 3)
78 self.online = kwargs.get('online', False)
78 self.online = kwargs.get('online', False)
79 self.delay = kwargs.get('delay', 30)
79 self.delay = kwargs.get('delay', 30)
80 self.ele = kwargs.get('ext', '')
80
81
81 if self.path is None:
82 if self.path is None:
82 raise ValueError, 'The path is not valid'
83 raise ValueError, 'The path is not valid'
83
84
84 self.search_files(path, startDate, endDate, startTime, endTime, walk)
85 self.search_files(path, startDate, endDate, startTime, endTime, walk)
85 self.cursor = 0
86 self.cursor = 0
86 self.counter_records = 0
87 self.counter_records = 0
87
88
88 if not self.files:
89 if not self.files:
89 raise Warning, 'There is no files matching these date in the folder: {}. \n Check startDate and endDate'.format(path)
90 raise Warning, 'There is no files matching these date in the folder: {}. \n Check startDate and endDate'.format(path)
90
91
91 def search_files(self, path, startDate, endDate, startTime, endTime, walk):
92 def search_files(self, path, startDate, endDate, startTime, endTime, walk):
92 '''
93 '''
93 Searching for NCDF files in path
94 Searching for NCDF files in path
94 Creating a list of files to procces included in [startDate,endDate]
95 Creating a list of files to procces included in [startDate,endDate]
95
96
96 Input:
97 Input:
97 path - Path to find files
98 path - Path to find files
98 '''
99 '''
99
100
100 log.log('Searching files {} in {} '.format(self.ext, path), 'NCDFReader')
101 log.log('Searching files {} in {} '.format(self.ext, path), 'NCDFReader')
101 if walk:
102 if walk:
102 paths = [os.path.join(path, p) for p in os.listdir(path) if os.path.isdir(os.path.join(path, p))]
103 paths = [os.path.join(path, p) for p in os.listdir(path) if os.path.isdir(os.path.join(path, p))]
103 paths.sort()
104 paths.sort()
104 else:
105 else:
105 paths = [path]
106 paths = [path]
106
107
107 fileList0 = []
108 fileList0 = []
108
109
109 for subpath in paths:
110 for subpath in paths:
110 fileList0 += [os.path.join(subpath, s) for s in glob.glob1(subpath, '*') if os.path.splitext(s)[-1] in self.ext]
111 fileList0 += [os.path.join(subpath, s) for s in glob.glob1(subpath, '*') if os.path.splitext(s)[-1] in self.ext and 'E{}'.format(self.ele) in s]
111
112
112 fileList0.sort()
113 fileList0.sort()
114 if self.online:
115 fileList0 = fileList0[-1:]
113
116
114 self.files = {}
117 self.files = {}
115
118
116 startDate = startDate - datetime.timedelta(1)
119 startDate = startDate - datetime.timedelta(1)
117 endDate = endDate + datetime.timedelta(1)
120 endDate = endDate + datetime.timedelta(1)
118
121
119 for fullname in fileList0:
122 for fullname in fileList0:
120 thisFile = fullname.split('/')[-1]
123 thisFile = fullname.split('/')[-1]
121 year = thisFile[3:7]
124 year = thisFile[3:7]
122 if not year.isdigit():
125 if not year.isdigit():
123 continue
126 continue
124
127
125 month = thisFile[7:9]
128 month = thisFile[7:9]
126 if not month.isdigit():
129 if not month.isdigit():
127 continue
130 continue
128
131
129 day = thisFile[9:11]
132 day = thisFile[9:11]
130 if not day.isdigit():
133 if not day.isdigit():
131 continue
134 continue
132
135
133 year, month, day = int(year), int(month), int(day)
136 year, month, day = int(year), int(month), int(day)
134 dateFile = datetime.date(year, month, day)
137 dateFile = datetime.date(year, month, day)
135 timeFile = datetime.time(int(thisFile[12:14]), int(thisFile[14:16]), int(thisFile[16:18]))
138 timeFile = datetime.time(int(thisFile[12:14]), int(thisFile[14:16]), int(thisFile[16:18]))
136
139
137 if (startDate > dateFile) or (endDate < dateFile):
140 if (startDate > dateFile) or (endDate < dateFile):
138 continue
141 continue
139
142
140 dt = datetime.datetime.combine(dateFile, timeFile)
143 dt = datetime.datetime.combine(dateFile, timeFile)
141 if dt not in self.files:
144 if dt not in self.files:
142 self.files[dt] = []
145 self.files[dt] = []
143 self.files[dt].append(fullname)
146 self.files[dt].append(fullname)
144
147
145 self.dates = self.files.keys()
148 self.dates = self.files.keys()
146 self.dates.sort()
149 self.dates.sort()
147
150
148 return
151 return
149
152
150 def search_files_online(self):
153 def search_files_online(self):
151 '''
154 '''
152 Searching for NCDF files in online mode path
155 Searching for NCDF files in online mode path
153 Creating a list of files to procces included in [startDate,endDate]
156 Creating a list of files to procces included in [startDate,endDate]
154
157
155 Input:
158 Input:
156 path - Path to find files
159 path - Path to find files
157 '''
160 '''
158
161
159 old_files = self.files[self.dt]
160 self.files = {}
162 self.files = {}
161
163
162 for n in range(self.nTries):
164 for n in range(self.nTries):
163
165
164 if self.walk:
166 if self.walk:
165 paths = [os.path.join(self.path, p) for p in os.listdir(self.path) if os.path.isdir(os.path.join(self.path, p))]
167 paths = [os.path.join(self.path, p) for p in os.listdir(self.path) if os.path.isdir(os.path.join(self.path, p))]
166 paths = paths[-2:]
168 path = paths[-1]
167 else:
169 else:
168 paths = [self.path]
170 paths = self.path
169
171
170 new_files = []
172 new_files = [os.path.join(path, s) for s in glob.glob1(path, '*') if os.path.splitext(s)[-1] in self.ext and 'E{}'.format(self.ele) in s]
171
172 for path in paths:
173 new_files += [os.path.join(path, s) for s in glob.glob1(path, '*') if os.path.splitext(s)[-1] in self.ext and os.path.join(path, s not in old_files)]
174
173
175 new_files.sort()
174 new_files.sort()
176
175
177 if new_files:
176 for fullname in new_files:
177 thisFile = fullname.split('/')[-1]
178 year = thisFile[3:7]
179 if not year.isdigit():
180 continue
181
182 month = thisFile[7:9]
183 if not month.isdigit():
184 continue
185
186 day = thisFile[9:11]
187 if not day.isdigit():
188 continue
189
190 year, month, day = int(year), int(month), int(day)
191 dateFile = datetime.date(year, month, day)
192 timeFile = datetime.time(int(thisFile[12:14]), int(thisFile[14:16]), int(thisFile[16:18]))
193
194 dt = datetime.datetime.combine(dateFile, timeFile)
195
196 if self.dt >= dt:
197 continue
198
199 if dt not in self.files:
200 self.dt = dt
201 self.files[dt] = []
202
203 self.files[dt].append(fullname)
204 break
205
206 if self.files:
178 break
207 break
179 else:
208 else:
180 log.warning('Waiting {} seconds for the next file, try {} ...'.format(self.delay, n + 1), 'NCDFReader')
209 log.warning('Waiting {} seconds for the next file, try {} ...'.format(self.delay, n + 1), 'NCDFReader')
181 time.sleep(self.delay)
210 time.sleep(self.delay)
182
211
183 if not new_files:
212 if not self.files:
184 log.error('No more files found', 'NCDFReader')
185 return 0
213 return 0
186
214
187 startDate = self.dt - datetime.timedelta(seconds=1)
188
189 for fullname in new_files:
190 thisFile = fullname.split('/')[-1]
191 year = thisFile[3:7]
192 if not year.isdigit():
193 continue
194
195 month = thisFile[7:9]
196 if not month.isdigit():
197 continue
198
199 day = thisFile[9:11]
200 if not day.isdigit():
201 continue
202
203 year, month, day = int(year), int(month), int(day)
204 dateFile = datetime.date(year, month, day)
205 timeFile = datetime.time(int(thisFile[12:14]), int(thisFile[14:16]), int(thisFile[16:18]))
206
207 if (startDate > dateFile):
208 continue
209
210 dt = datetime.datetime.combine(dateFile, timeFile)
211 if dt not in self.files:
212 self.files[dt] = []
213
214 self.files[dt].append(fullname)
215
216 self.dates = self.files.keys()
215 self.dates = self.files.keys()
217 self.dates.sort()
216 self.dates.sort()
218 self.cursor = 0
217 self.cursor = 0
219
218
220 return 1
219 return 1
221
220
222 def parseFile(self):
221 def parseFile(self):
223 '''
222 '''
224 '''
223 '''
225
224
226 self.header = {}
225 self.header = {}
227
226
228 for attr in self.fp.ncattrs():
227 for attr in self.fp.ncattrs():
229 self.header[str(attr)] = getattr(self.fp, attr)
228 self.header[str(attr)] = getattr(self.fp, attr)
230
229
231 self.data[self.header['TypeName']] = numpy.array(self.fp.variables[self.header['TypeName']])
230 self.data[self.header['TypeName']] = numpy.array(self.fp.variables[self.header['TypeName']])
232
231
233 if 'Azimuth' not in self.data:
232 if 'Azimuth' not in self.data:
234 self.data['Azimuth'] = numpy.array(self.fp.variables['Azimuth'])
233 self.data['Azimuth'] = numpy.array(self.fp.variables['Azimuth'])
235
234
236
235
237 def setNextFile(self):
236 def setNextFile(self):
238 '''
237 '''
239 Open next files for the current datetime
238 Open next files for the current datetime
240 '''
239 '''
241
240
242 cursor = self.cursor
241 cursor = self.cursor
243
244 if not self.online_mode:
242 if not self.online_mode:
245 self.dt = self.dates[cursor]
246 if cursor == len(self.dates):
243 if cursor == len(self.dates):
247 if self.online:
244 if self.online:
245 cursor = 0
246 self.dt = self.dates[cursor]
248 self.online_mode = True
247 self.online_mode = True
248 if not self.search_files_online():
249 log.success('No more files', 'NCDFReader')
250 return 0
249 else:
251 else:
250 log.success('No more files', 'NCDFReader')
252 log.success('No more files', 'NCDFReader')
251 self.flagNoMoreFiles = 1
253 self.flagNoMoreFiles = 1
252 return 0
254 return 0
253 else:
255 else:
254 if not self.search_files_online():
256 if not self.search_files_online():
255 return 0
257 return 0
258 cursor = self.cursor
256
259
257 log.log(
260 log.log(
258 'Opening: {}\'s files'.format(self.dates[cursor]),
261 'Opening: {}\'s files'.format(self.dates[cursor]),
259 'NCDFReader'
262 'NCDFReader'
260 )
263 )
261
264
262 self.data = {}
265 self.data = {}
263
266
264 for fullname in self.files[self.dates[cursor]]:
267 for fullname in self.files[self.dates[cursor]]:
265
268
266 if os.path.splitext(fullname)[-1] == '.tgz':
269 if os.path.splitext(fullname)[-1] == '.tgz':
267 tar = tarfile.open(fullname, 'r:gz')
270 tar = tarfile.open(fullname, 'r:gz')
268 tar.extractall('/tmp')
271 tar.extractall('/tmp')
269 files = [os.path.join('/tmp', member.name) for member in tar.getmembers()]
272 files = [os.path.join('/tmp', member.name) for member in tar.getmembers()]
270 else:
273 else:
271 files = [fullname]
274 files = [fullname]
272
275
273 for filename in files:
276 for filename in files:
274 if self.filename is not None:
277 if self.filename is not None:
275 self.fp.close()
278 self.fp.close()
276
279
277 self.filename = filename
280 self.filename = filename
278 self.filedate = self.dates[cursor]
281 self.filedate = self.dates[cursor]
279 self.fp = Dataset(self.filename, 'r')
282 self.fp = Dataset(self.filename, 'r')
280 self.parseFile()
283 self.parseFile()
281
284
282 self.counter_records += 1
285 self.counter_records += 1
283 self.cursor += 1
286 self.cursor += 1
284 return 1
287 return 1
285
288
286 def readNextFile(self):
289 def readNextFile(self):
287
290
288 while True:
291 while True:
289 self.flagDiscontinuousBlock = 0
292 self.flagDiscontinuousBlock = 0
290 if not self.setNextFile():
293 if not self.setNextFile():
291 return 0
294 return 0
292
295
293 self.datatime = datetime.datetime.utcfromtimestamp(self.header['Time'])
296 self.datatime = datetime.datetime.utcfromtimestamp(self.header['Time'])
294
297
295 if (self.datatime < datetime.datetime.combine(self.startDate, self.startTime)) or \
298 if (self.datatime < datetime.datetime.combine(self.startDate, self.startTime)) or \
296 (self.datatime > datetime.datetime.combine(self.endDate, self.endTime)):
299 (self.datatime > datetime.datetime.combine(self.endDate, self.endTime)):
297 log.warning(
300 log.warning(
298 'Reading Record No. {}/{} -> {} [Skipping]'.format(
301 'Reading Record No. {}/{} -> {} [Skipping]'.format(
299 self.counter_records,
302 self.counter_records,
300 self.nrecords,
303 self.nrecords,
301 self.datatime.ctime()),
304 self.datatime.ctime()),
302 'NCDFReader')
305 'NCDFReader')
303 continue
306 continue
304 break
307 break
305
308
306 log.log(
309 log.log(
307 'Reading Record No. {}/{} -> {}'.format(
310 'Reading Record No. {}/{} -> {}'.format(
308 self.counter_records,
311 self.counter_records,
309 self.nrecords,
312 self.nrecords,
310 self.datatime.ctime()),
313 self.datatime.ctime()),
311 'NCDFReader')
314 'NCDFReader')
312
315
313 return 1
316 return 1
314
317
315
318
316 def set_output(self):
319 def set_output(self):
317 '''
320 '''
318 Storing data from buffer to dataOut object
321 Storing data from buffer to dataOut object
319 '''
322 '''
320
323
321 self.dataOut.heightList = self.data.pop('Azimuth')
324 self.dataOut.heightList = self.data.pop('Azimuth')
322
325
323 log.log('Parameters found: {}'.format(','.join(self.data.keys())),
326 log.log('Parameters found: {}'.format(','.join(self.data.keys())),
324 'PXReader')
327 'PXReader')
325
328
326 self.dataOut.data_param = numpy.array(self.data.values())
329 self.dataOut.data_param = numpy.array(self.data.values())
327 self.dataOut.data_param[self.dataOut.data_param == -99900.] = numpy.nan
330 self.dataOut.data_param[self.dataOut.data_param == -99900.] = numpy.nan
328 self.dataOut.parameters = self.data.keys()
331 self.dataOut.parameters = self.data.keys()
329 self.dataOut.utctime = self.header['Time']
332 self.dataOut.utctime = self.header['Time']
330 self.dataOut.utctimeInit = self.dataOut.utctime
333 self.dataOut.utctimeInit = self.dataOut.utctime
331 self.dataOut.useLocalTime = False
334 self.dataOut.useLocalTime = False
332 self.dataOut.flagNoData = False
335 self.dataOut.flagNoData = False
333 self.dataOut.flagDiscontinuousBlock = self.flagDiscontinuousBlock
336 self.dataOut.flagDiscontinuousBlock = self.flagDiscontinuousBlock
334
337
335 def getData(self):
338 def getData(self):
336 '''
339 '''
337 Storing data from databuffer to dataOut object
340 Storing data from databuffer to dataOut object
338 '''
341 '''
339 if self.flagNoMoreFiles:
342 if self.flagNoMoreFiles:
340 self.dataOut.flagNoData = True
343 self.dataOut.flagNoData = True
341 log.error('No file left to process', 'NCDFReader')
344 log.error('No file left to process', 'NCDFReader')
342 return 0
345 return 0
343
346
344 if not self.readNextFile():
347 if not self.readNextFile():
345 self.dataOut.flagNoData = True
348 self.dataOut.flagNoData = True
346 return 0
349 return 0
347
350
348 self.set_output()
351 self.set_output()
349
352
350 return 1
353 return 1
351
354
@@ -1,829 +1,829
1 '''
1 '''
2 @author: Juan C. Espinoza
2 @author: Juan C. Espinoza
3 '''
3 '''
4
4
5 import os
5 import os
6 import glob
6 import glob
7 import time
7 import time
8 import json
8 import json
9 import numpy
9 import numpy
10 import paho.mqtt.client as mqtt
10 import paho.mqtt.client as mqtt
11 import zmq
11 import zmq
12 import datetime
12 import datetime
13 import ftplib
13 import ftplib
14 from zmq.utils.monitor import recv_monitor_message
14 from zmq.utils.monitor import recv_monitor_message
15 from functools import wraps
15 from functools import wraps
16 from threading import Thread
16 from threading import Thread
17 from multiprocessing import Process
17 from multiprocessing import Process
18
18
19 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit
19 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit
20 from schainpy.model.data.jrodata import JROData
20 from schainpy.model.data.jrodata import JROData
21 from schainpy.utils import log
21 from schainpy.utils import log
22
22
23 MAXNUMX = 500
23 MAXNUMX = 500
24 MAXNUMY = 500
24 MAXNUMY = 500
25
25
26 PLOT_CODES = {
26 PLOT_CODES = {
27 'rti': 0, #Range time intensity (RTI).
27 'rti': 0, #Range time intensity (RTI).
28 'spc': 1, #Spectra (and Cross-spectra) information.
28 'spc': 1, #Spectra (and Cross-spectra) information.
29 'cspc': 2, #Cross-Correlation information.
29 'cspc': 2, #Cross-Correlation information.
30 'coh': 3, #Coherence map.
30 'coh': 3, #Coherence map.
31 'base': 4, #Base lines graphic.
31 'base': 4, #Base lines graphic.
32 'row': 5, #Row Spectra.
32 'row': 5, #Row Spectra.
33 'total' : 6, #Total Power.
33 'total' : 6, #Total Power.
34 'drift' : 7, #Drifts graphics.
34 'drift' : 7, #Drifts graphics.
35 'height' : 8, #Height profile.
35 'height' : 8, #Height profile.
36 'phase' : 9, #Signal Phase.
36 'phase' : 9, #Signal Phase.
37 'power' : 16,
37 'power' : 16,
38 'noise' : 17,
38 'noise' : 17,
39 'beacon' : 18,
39 'beacon' : 18,
40 #USED IN jroplot_parameters.py
40 #USED IN jroplot_parameters.py
41 'wind' : 22,
41 'wind' : 22,
42 'skymap' : 23,
42 'skymap' : 23,
43 # 'MPHASE_CODE' : 24,
43 # 'MPHASE_CODE' : 24,
44 'moments' : 25,
44 'V' : 25,
45 'param' : 26,
45 'Z' : 26,
46 'spc_fit' : 27,
46 'spc_fit' : 27,
47 'ew_drifts' : 28,
47 'ew_drifts' : 28,
48 'reflectivity': 30
48 'reflectivity': 30
49 }
49 }
50
50
51 class PrettyFloat(float):
51 class PrettyFloat(float):
52 def __repr__(self):
52 def __repr__(self):
53 return '%.2f' % self
53 return '%.2f' % self
54
54
55 def roundFloats(obj):
55 def roundFloats(obj):
56 if isinstance(obj, list):
56 if isinstance(obj, list):
57 return map(roundFloats, obj)
57 return map(roundFloats, obj)
58 elif isinstance(obj, float):
58 elif isinstance(obj, float):
59 return round(obj, 2)
59 return round(obj, 2)
60
60
61 def decimate(z, MAXNUMY):
61 def decimate(z, MAXNUMY):
62 dy = int(len(z[0])/MAXNUMY) + 1
62 dy = int(len(z[0])/MAXNUMY) + 1
63
63
64 return z[::, ::dy]
64 return z[::, ::dy]
65
65
66 class throttle(object):
66 class throttle(object):
67 '''
67 '''
68 Decorator that prevents a function from being called more than once every
68 Decorator that prevents a function from being called more than once every
69 time period.
69 time period.
70 To create a function that cannot be called more than once a minute, but
70 To create a function that cannot be called more than once a minute, but
71 will sleep until it can be called:
71 will sleep until it can be called:
72 @throttle(minutes=1)
72 @throttle(minutes=1)
73 def foo():
73 def foo():
74 pass
74 pass
75
75
76 for i in range(10):
76 for i in range(10):
77 foo()
77 foo()
78 print "This function has run %s times." % i
78 print "This function has run %s times." % i
79 '''
79 '''
80
80
81 def __init__(self, seconds=0, minutes=0, hours=0):
81 def __init__(self, seconds=0, minutes=0, hours=0):
82 self.throttle_period = datetime.timedelta(
82 self.throttle_period = datetime.timedelta(
83 seconds=seconds, minutes=minutes, hours=hours
83 seconds=seconds, minutes=minutes, hours=hours
84 )
84 )
85
85
86 self.time_of_last_call = datetime.datetime.min
86 self.time_of_last_call = datetime.datetime.min
87
87
88 def __call__(self, fn):
88 def __call__(self, fn):
89 @wraps(fn)
89 @wraps(fn)
90 def wrapper(*args, **kwargs):
90 def wrapper(*args, **kwargs):
91 coerce = kwargs.pop('coerce', None)
91 coerce = kwargs.pop('coerce', None)
92 if coerce:
92 if coerce:
93 self.time_of_last_call = datetime.datetime.now()
93 self.time_of_last_call = datetime.datetime.now()
94 return fn(*args, **kwargs)
94 return fn(*args, **kwargs)
95 else:
95 else:
96 now = datetime.datetime.now()
96 now = datetime.datetime.now()
97 time_since_last_call = now - self.time_of_last_call
97 time_since_last_call = now - self.time_of_last_call
98 time_left = self.throttle_period - time_since_last_call
98 time_left = self.throttle_period - time_since_last_call
99
99
100 if time_left > datetime.timedelta(seconds=0):
100 if time_left > datetime.timedelta(seconds=0):
101 return
101 return
102
102
103 self.time_of_last_call = datetime.datetime.now()
103 self.time_of_last_call = datetime.datetime.now()
104 return fn(*args, **kwargs)
104 return fn(*args, **kwargs)
105
105
106 return wrapper
106 return wrapper
107
107
108 class Data(object):
108 class Data(object):
109 '''
109 '''
110 Object to hold data to be plotted
110 Object to hold data to be plotted
111 '''
111 '''
112
112
113 def __init__(self, plottypes, throttle_value, exp_code, buffering=True):
113 def __init__(self, plottypes, throttle_value, exp_code, buffering=True):
114 self.plottypes = plottypes
114 self.plottypes = plottypes
115 self.throttle = throttle_value
115 self.throttle = throttle_value
116 self.exp_code = exp_code
116 self.exp_code = exp_code
117 self.buffering = buffering
117 self.buffering = buffering
118 self.ended = False
118 self.ended = False
119 self.localtime = False
119 self.localtime = False
120 self.__times = []
120 self.__times = []
121 self.__heights = []
121 self.__heights = []
122
122
123 def __str__(self):
123 def __str__(self):
124 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
124 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
125 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
125 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
126
126
127 def __len__(self):
127 def __len__(self):
128 return len(self.__times)
128 return len(self.__times)
129
129
130 def __getitem__(self, key):
130 def __getitem__(self, key):
131 if key not in self.data:
131 if key not in self.data:
132 raise KeyError(log.error('Missing key: {}'.format(key)))
132 raise KeyError(log.error('Missing key: {}'.format(key)))
133
133
134 if 'spc' in key or not self.buffering:
134 if 'spc' in key or not self.buffering:
135 ret = self.data[key]
135 ret = self.data[key]
136 else:
136 else:
137 ret = numpy.array([self.data[key][x] for x in self.times])
137 ret = numpy.array([self.data[key][x] for x in self.times])
138 if ret.ndim > 1:
138 if ret.ndim > 1:
139 ret = numpy.swapaxes(ret, 0, 1)
139 ret = numpy.swapaxes(ret, 0, 1)
140 return ret
140 return ret
141
141
142 def __contains__(self, key):
142 def __contains__(self, key):
143 return key in self.data
143 return key in self.data
144
144
145 def setup(self):
145 def setup(self):
146 '''
146 '''
147 Configure object
147 Configure object
148 '''
148 '''
149
149
150 self.type = ''
150 self.type = ''
151 self.ended = False
151 self.ended = False
152 self.data = {}
152 self.data = {}
153 self.__times = []
153 self.__times = []
154 self.__heights = []
154 self.__heights = []
155 self.__all_heights = set()
155 self.__all_heights = set()
156 for plot in self.plottypes:
156 for plot in self.plottypes:
157 if 'snr' in plot:
157 if 'snr' in plot:
158 plot = 'snr'
158 plot = 'snr'
159 self.data[plot] = {}
159 self.data[plot] = {}
160
160
161 def shape(self, key):
161 def shape(self, key):
162 '''
162 '''
163 Get the shape of the one-element data for the given key
163 Get the shape of the one-element data for the given key
164 '''
164 '''
165
165
166 if len(self.data[key]):
166 if len(self.data[key]):
167 if 'spc' in key or not self.buffering:
167 if 'spc' in key or not self.buffering:
168 return self.data[key].shape
168 return self.data[key].shape
169 return self.data[key][self.__times[0]].shape
169 return self.data[key][self.__times[0]].shape
170 return (0,)
170 return (0,)
171
171
172 def update(self, dataOut, tm):
172 def update(self, dataOut, tm):
173 '''
173 '''
174 Update data object with new dataOut
174 Update data object with new dataOut
175 '''
175 '''
176
176
177 if tm in self.__times:
177 if tm in self.__times:
178 return
178 return
179
179
180 self.type = dataOut.type
180 self.type = dataOut.type
181 self.parameters = getattr(dataOut, 'parameters', [])
181 self.parameters = getattr(dataOut, 'parameters', [])
182 if hasattr(dataOut, 'pairsList'):
182 if hasattr(dataOut, 'pairsList'):
183 self.pairs = dataOut.pairsList
183 self.pairs = dataOut.pairsList
184 self.channels = dataOut.channelList
184 self.channels = dataOut.channelList
185 self.interval = dataOut.getTimeInterval()
185 self.interval = dataOut.getTimeInterval()
186 self.localtime = dataOut.useLocalTime
186 self.localtime = dataOut.useLocalTime
187 if 'spc' in self.plottypes or 'cspc' in self.plottypes:
187 if 'spc' in self.plottypes or 'cspc' in self.plottypes:
188 self.xrange = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
188 self.xrange = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
189 self.__heights.append(dataOut.heightList)
189 self.__heights.append(dataOut.heightList)
190 self.__all_heights.update(dataOut.heightList)
190 self.__all_heights.update(dataOut.heightList)
191 self.__times.append(tm)
191 self.__times.append(tm)
192
192
193 for plot in self.plottypes:
193 for plot in self.plottypes:
194 if plot == 'spc':
194 if plot == 'spc':
195 z = dataOut.data_spc/dataOut.normFactor
195 z = dataOut.data_spc/dataOut.normFactor
196 self.data[plot] = 10*numpy.log10(z)
196 self.data[plot] = 10*numpy.log10(z)
197 if plot == 'cspc':
197 if plot == 'cspc':
198 self.data[plot] = dataOut.data_cspc
198 self.data[plot] = dataOut.data_cspc
199 if plot == 'noise':
199 if plot == 'noise':
200 buffer = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
200 buffer = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
201 if plot == 'rti':
201 if plot == 'rti':
202 buffer = dataOut.getPower()
202 buffer = dataOut.getPower()
203 if plot == 'snr_db':
203 if plot == 'snr_db':
204 self.data['snr'][tm] = dataOut.data_SNR
204 self.data['snr'][tm] = dataOut.data_SNR
205 if plot == 'snr':
205 if plot == 'snr':
206 buffer = 10*numpy.log10(dataOut.data_SNR)
206 buffer = 10*numpy.log10(dataOut.data_SNR)
207 if plot == 'dop':
207 if plot == 'dop':
208 buffer = 10*numpy.log10(dataOut.data_DOP)
208 buffer = 10*numpy.log10(dataOut.data_DOP)
209 if plot == 'mean':
209 if plot == 'mean':
210 buffer = dataOut.data_MEAN
210 buffer = dataOut.data_MEAN
211 if plot == 'std':
211 if plot == 'std':
212 buffer = dataOut.data_STD
212 buffer = dataOut.data_STD
213 if plot == 'coh':
213 if plot == 'coh':
214 buffer = dataOut.getCoherence()
214 buffer = dataOut.getCoherence()
215 if plot == 'phase':
215 if plot == 'phase':
216 buffer = dataOut.getCoherence(phase=True)
216 buffer = dataOut.getCoherence(phase=True)
217 if plot == 'output':
217 if plot == 'output':
218 buffer = dataOut.data_output
218 buffer = dataOut.data_output
219 if plot == 'param':
219 if plot == 'param':
220 buffer = dataOut.data_param
220 buffer = dataOut.data_param
221
221
222 if self.buffering:
222 if self.buffering:
223 self.data[plot][tm] = buffer
223 self.data[plot][tm] = buffer
224 else:
224 else:
225 self.data[plot] = buffer
225 self.data[plot] = buffer
226
226
227 def normalize_heights(self):
227 def normalize_heights(self):
228 '''
228 '''
229 Ensure same-dimension of the data for different heighList
229 Ensure same-dimension of the data for different heighList
230 '''
230 '''
231
231
232 H = numpy.array(list(self.__all_heights))
232 H = numpy.array(list(self.__all_heights))
233 H.sort()
233 H.sort()
234 for key in self.data:
234 for key in self.data:
235 shape = self.shape(key)[:-1] + H.shape
235 shape = self.shape(key)[:-1] + H.shape
236 for tm, obj in self.data[key].items():
236 for tm, obj in self.data[key].items():
237 h = self.__heights[self.__times.index(tm)]
237 h = self.__heights[self.__times.index(tm)]
238 if H.size == h.size:
238 if H.size == h.size:
239 continue
239 continue
240 index = numpy.where(numpy.in1d(H, h))[0]
240 index = numpy.where(numpy.in1d(H, h))[0]
241 dummy = numpy.zeros(shape) + numpy.nan
241 dummy = numpy.zeros(shape) + numpy.nan
242 if len(shape) == 2:
242 if len(shape) == 2:
243 dummy[:, index] = obj
243 dummy[:, index] = obj
244 else:
244 else:
245 dummy[index] = obj
245 dummy[index] = obj
246 self.data[key][tm] = dummy
246 self.data[key][tm] = dummy
247
247
248 self.__heights = [H for tm in self.__times]
248 self.__heights = [H for tm in self.__times]
249
249
250 def jsonify(self, decimate=False):
250 def jsonify(self, decimate=False):
251 '''
251 '''
252 Convert data to json
252 Convert data to json
253 '''
253 '''
254
254
255 data = {}
255 data = {}
256 tm = self.times[-1]
256 tm = self.times[-1]
257
257
258 for key in self.data:
258 for key in self.data:
259 if key in ('spc', 'cspc') or not self.buffering:
259 if key in ('spc', 'cspc') or not self.buffering:
260 dx = int(self.data[key].shape[1]/MAXNUMX) + 1
260 dx = int(self.data[key].shape[1]/MAXNUMX) + 1
261 dy = int(self.data[key].shape[2]/MAXNUMY) + 1
261 dy = int(self.data[key].shape[2]/MAXNUMY) + 1
262 data[key] = roundFloats(self.data[key][::, ::dx, ::dy].tolist())
262 data[key] = roundFloats(self.data[key][::, ::dx, ::dy].tolist())
263 else:
263 else:
264 data[key] = roundFloats(self.data[key][tm].tolist())
264 data[key] = roundFloats(self.data[key][tm].tolist())
265
265
266 ret = {'data': data}
266 ret = {'data': data}
267 ret['exp_code'] = self.exp_code
267 ret['exp_code'] = self.exp_code
268 ret['time'] = tm
268 ret['time'] = tm
269 ret['interval'] = self.interval
269 ret['interval'] = self.interval
270 ret['localtime'] = self.localtime
270 ret['localtime'] = self.localtime
271 ret['yrange'] = roundFloats(self.heights.tolist())
271 ret['yrange'] = roundFloats(self.heights.tolist())
272 if key in ('spc', 'cspc'):
272 if key in ('spc', 'cspc'):
273 ret['xrange'] = roundFloats(self.xrange[2][::dx].tolist())
273 ret['xrange'] = roundFloats(self.xrange[2][::dx].tolist())
274 else:
274 else:
275 ret['xrange'] = []
275 ret['xrange'] = []
276 if hasattr(self, 'pairs'):
276 if hasattr(self, 'pairs'):
277 ret['pairs'] = self.pairs
277 ret['pairs'] = self.pairs
278 return json.dumps(ret)
278 return json.dumps(ret)
279
279
280 @property
280 @property
281 def times(self):
281 def times(self):
282 '''
282 '''
283 Return the list of times of the current data
283 Return the list of times of the current data
284 '''
284 '''
285
285
286 ret = numpy.array(self.__times)
286 ret = numpy.array(self.__times)
287 ret.sort()
287 ret.sort()
288 return ret
288 return ret
289
289
290 @property
290 @property
291 def heights(self):
291 def heights(self):
292 '''
292 '''
293 Return the list of heights of the current data
293 Return the list of heights of the current data
294 '''
294 '''
295
295
296 return numpy.array(self.__heights[-1])
296 return numpy.array(self.__heights[-1])
297
297
298 class PublishData(Operation):
298 class PublishData(Operation):
299 '''
299 '''
300 Operation to send data over zmq.
300 Operation to send data over zmq.
301 '''
301 '''
302
302
303 __attrs__ = ['host', 'port', 'delay', 'zeromq', 'mqtt', 'verbose']
303 __attrs__ = ['host', 'port', 'delay', 'zeromq', 'mqtt', 'verbose']
304
304
305 def __init__(self, **kwargs):
305 def __init__(self, **kwargs):
306 """Inicio."""
306 """Inicio."""
307 Operation.__init__(self, **kwargs)
307 Operation.__init__(self, **kwargs)
308 self.isConfig = False
308 self.isConfig = False
309 self.client = None
309 self.client = None
310 self.zeromq = None
310 self.zeromq = None
311 self.mqtt = None
311 self.mqtt = None
312
312
313 def on_disconnect(self, client, userdata, rc):
313 def on_disconnect(self, client, userdata, rc):
314 if rc != 0:
314 if rc != 0:
315 log.warning('Unexpected disconnection.')
315 log.warning('Unexpected disconnection.')
316 self.connect()
316 self.connect()
317
317
318 def connect(self):
318 def connect(self):
319 log.warning('trying to connect')
319 log.warning('trying to connect')
320 try:
320 try:
321 self.client.connect(
321 self.client.connect(
322 host=self.host,
322 host=self.host,
323 port=self.port,
323 port=self.port,
324 keepalive=60*10,
324 keepalive=60*10,
325 bind_address='')
325 bind_address='')
326 self.client.loop_start()
326 self.client.loop_start()
327 # self.client.publish(
327 # self.client.publish(
328 # self.topic + 'SETUP',
328 # self.topic + 'SETUP',
329 # json.dumps(setup),
329 # json.dumps(setup),
330 # retain=True
330 # retain=True
331 # )
331 # )
332 except:
332 except:
333 log.error('MQTT Conection error.')
333 log.error('MQTT Conection error.')
334 self.client = False
334 self.client = False
335
335
336 def setup(self, port=1883, username=None, password=None, clientId="user", zeromq=1, verbose=True, **kwargs):
336 def setup(self, port=1883, username=None, password=None, clientId="user", zeromq=1, verbose=True, **kwargs):
337 self.counter = 0
337 self.counter = 0
338 self.topic = kwargs.get('topic', 'schain')
338 self.topic = kwargs.get('topic', 'schain')
339 self.delay = kwargs.get('delay', 0)
339 self.delay = kwargs.get('delay', 0)
340 self.plottype = kwargs.get('plottype', 'spectra')
340 self.plottype = kwargs.get('plottype', 'spectra')
341 self.host = kwargs.get('host', "10.10.10.82")
341 self.host = kwargs.get('host', "10.10.10.82")
342 self.port = kwargs.get('port', 3000)
342 self.port = kwargs.get('port', 3000)
343 self.clientId = clientId
343 self.clientId = clientId
344 self.cnt = 0
344 self.cnt = 0
345 self.zeromq = zeromq
345 self.zeromq = zeromq
346 self.mqtt = kwargs.get('plottype', 0)
346 self.mqtt = kwargs.get('plottype', 0)
347 self.client = None
347 self.client = None
348 self.verbose = verbose
348 self.verbose = verbose
349 setup = []
349 setup = []
350 if mqtt is 1:
350 if mqtt is 1:
351 self.client = mqtt.Client(
351 self.client = mqtt.Client(
352 client_id=self.clientId + self.topic + 'SCHAIN',
352 client_id=self.clientId + self.topic + 'SCHAIN',
353 clean_session=True)
353 clean_session=True)
354 self.client.on_disconnect = self.on_disconnect
354 self.client.on_disconnect = self.on_disconnect
355 self.connect()
355 self.connect()
356 for plot in self.plottype:
356 for plot in self.plottype:
357 setup.append({
357 setup.append({
358 'plot': plot,
358 'plot': plot,
359 'topic': self.topic + plot,
359 'topic': self.topic + plot,
360 'title': getattr(self, plot + '_' + 'title', False),
360 'title': getattr(self, plot + '_' + 'title', False),
361 'xlabel': getattr(self, plot + '_' + 'xlabel', False),
361 'xlabel': getattr(self, plot + '_' + 'xlabel', False),
362 'ylabel': getattr(self, plot + '_' + 'ylabel', False),
362 'ylabel': getattr(self, plot + '_' + 'ylabel', False),
363 'xrange': getattr(self, plot + '_' + 'xrange', False),
363 'xrange': getattr(self, plot + '_' + 'xrange', False),
364 'yrange': getattr(self, plot + '_' + 'yrange', False),
364 'yrange': getattr(self, plot + '_' + 'yrange', False),
365 'zrange': getattr(self, plot + '_' + 'zrange', False),
365 'zrange': getattr(self, plot + '_' + 'zrange', False),
366 })
366 })
367 if zeromq is 1:
367 if zeromq is 1:
368 context = zmq.Context()
368 context = zmq.Context()
369 self.zmq_socket = context.socket(zmq.PUSH)
369 self.zmq_socket = context.socket(zmq.PUSH)
370 server = kwargs.get('server', 'zmq.pipe')
370 server = kwargs.get('server', 'zmq.pipe')
371
371
372 if 'tcp://' in server:
372 if 'tcp://' in server:
373 address = server
373 address = server
374 else:
374 else:
375 address = 'ipc:///tmp/%s' % server
375 address = 'ipc:///tmp/%s' % server
376
376
377 self.zmq_socket.connect(address)
377 self.zmq_socket.connect(address)
378 time.sleep(1)
378 time.sleep(1)
379
379
380
380
381 def publish_data(self):
381 def publish_data(self):
382 self.dataOut.finished = False
382 self.dataOut.finished = False
383 if self.mqtt is 1:
383 if self.mqtt is 1:
384 yData = self.dataOut.heightList[:2].tolist()
384 yData = self.dataOut.heightList[:2].tolist()
385 if self.plottype == 'spectra':
385 if self.plottype == 'spectra':
386 data = getattr(self.dataOut, 'data_spc')
386 data = getattr(self.dataOut, 'data_spc')
387 z = data/self.dataOut.normFactor
387 z = data/self.dataOut.normFactor
388 zdB = 10*numpy.log10(z)
388 zdB = 10*numpy.log10(z)
389 xlen, ylen = zdB[0].shape
389 xlen, ylen = zdB[0].shape
390 dx = int(xlen/MAXNUMX) + 1
390 dx = int(xlen/MAXNUMX) + 1
391 dy = int(ylen/MAXNUMY) + 1
391 dy = int(ylen/MAXNUMY) + 1
392 Z = [0 for i in self.dataOut.channelList]
392 Z = [0 for i in self.dataOut.channelList]
393 for i in self.dataOut.channelList:
393 for i in self.dataOut.channelList:
394 Z[i] = zdB[i][::dx, ::dy].tolist()
394 Z[i] = zdB[i][::dx, ::dy].tolist()
395 payload = {
395 payload = {
396 'timestamp': self.dataOut.utctime,
396 'timestamp': self.dataOut.utctime,
397 'data': roundFloats(Z),
397 'data': roundFloats(Z),
398 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
398 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
399 'interval': self.dataOut.getTimeInterval(),
399 'interval': self.dataOut.getTimeInterval(),
400 'type': self.plottype,
400 'type': self.plottype,
401 'yData': yData
401 'yData': yData
402 }
402 }
403
403
404 elif self.plottype in ('rti', 'power'):
404 elif self.plottype in ('rti', 'power'):
405 data = getattr(self.dataOut, 'data_spc')
405 data = getattr(self.dataOut, 'data_spc')
406 z = data/self.dataOut.normFactor
406 z = data/self.dataOut.normFactor
407 avg = numpy.average(z, axis=1)
407 avg = numpy.average(z, axis=1)
408 avgdB = 10*numpy.log10(avg)
408 avgdB = 10*numpy.log10(avg)
409 xlen, ylen = z[0].shape
409 xlen, ylen = z[0].shape
410 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
410 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
411 AVG = [0 for i in self.dataOut.channelList]
411 AVG = [0 for i in self.dataOut.channelList]
412 for i in self.dataOut.channelList:
412 for i in self.dataOut.channelList:
413 AVG[i] = avgdB[i][::dy].tolist()
413 AVG[i] = avgdB[i][::dy].tolist()
414 payload = {
414 payload = {
415 'timestamp': self.dataOut.utctime,
415 'timestamp': self.dataOut.utctime,
416 'data': roundFloats(AVG),
416 'data': roundFloats(AVG),
417 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
417 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
418 'interval': self.dataOut.getTimeInterval(),
418 'interval': self.dataOut.getTimeInterval(),
419 'type': self.plottype,
419 'type': self.plottype,
420 'yData': yData
420 'yData': yData
421 }
421 }
422 elif self.plottype == 'noise':
422 elif self.plottype == 'noise':
423 noise = self.dataOut.getNoise()/self.dataOut.normFactor
423 noise = self.dataOut.getNoise()/self.dataOut.normFactor
424 noisedB = 10*numpy.log10(noise)
424 noisedB = 10*numpy.log10(noise)
425 payload = {
425 payload = {
426 'timestamp': self.dataOut.utctime,
426 'timestamp': self.dataOut.utctime,
427 'data': roundFloats(noisedB.reshape(-1, 1).tolist()),
427 'data': roundFloats(noisedB.reshape(-1, 1).tolist()),
428 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
428 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
429 'interval': self.dataOut.getTimeInterval(),
429 'interval': self.dataOut.getTimeInterval(),
430 'type': self.plottype,
430 'type': self.plottype,
431 'yData': yData
431 'yData': yData
432 }
432 }
433 elif self.plottype == 'snr':
433 elif self.plottype == 'snr':
434 data = getattr(self.dataOut, 'data_SNR')
434 data = getattr(self.dataOut, 'data_SNR')
435 avgdB = 10*numpy.log10(data)
435 avgdB = 10*numpy.log10(data)
436
436
437 ylen = data[0].size
437 ylen = data[0].size
438 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
438 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
439 AVG = [0 for i in self.dataOut.channelList]
439 AVG = [0 for i in self.dataOut.channelList]
440 for i in self.dataOut.channelList:
440 for i in self.dataOut.channelList:
441 AVG[i] = avgdB[i][::dy].tolist()
441 AVG[i] = avgdB[i][::dy].tolist()
442 payload = {
442 payload = {
443 'timestamp': self.dataOut.utctime,
443 'timestamp': self.dataOut.utctime,
444 'data': roundFloats(AVG),
444 'data': roundFloats(AVG),
445 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
445 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
446 'type': self.plottype,
446 'type': self.plottype,
447 'yData': yData
447 'yData': yData
448 }
448 }
449 else:
449 else:
450 print "Tipo de grafico invalido"
450 print "Tipo de grafico invalido"
451 payload = {
451 payload = {
452 'data': 'None',
452 'data': 'None',
453 'timestamp': 'None',
453 'timestamp': 'None',
454 'type': None
454 'type': None
455 }
455 }
456
456
457 self.client.publish(self.topic + self.plottype, json.dumps(payload), qos=0)
457 self.client.publish(self.topic + self.plottype, json.dumps(payload), qos=0)
458
458
459 if self.zeromq is 1:
459 if self.zeromq is 1:
460 if self.verbose:
460 if self.verbose:
461 log.log(
461 log.log(
462 'Sending {} - {}'.format(self.dataOut.type, self.dataOut.datatime),
462 'Sending {} - {}'.format(self.dataOut.type, self.dataOut.datatime),
463 self.name
463 self.name
464 )
464 )
465 self.zmq_socket.send_pyobj(self.dataOut)
465 self.zmq_socket.send_pyobj(self.dataOut)
466
466
467 def run(self, dataOut, **kwargs):
467 def run(self, dataOut, **kwargs):
468 self.dataOut = dataOut
468 self.dataOut = dataOut
469 if not self.isConfig:
469 if not self.isConfig:
470 self.setup(**kwargs)
470 self.setup(**kwargs)
471 self.isConfig = True
471 self.isConfig = True
472
472
473 self.publish_data()
473 self.publish_data()
474 time.sleep(self.delay)
474 time.sleep(self.delay)
475
475
476 def close(self):
476 def close(self):
477 if self.zeromq is 1:
477 if self.zeromq is 1:
478 self.dataOut.finished = True
478 self.dataOut.finished = True
479 self.zmq_socket.send_pyobj(self.dataOut)
479 self.zmq_socket.send_pyobj(self.dataOut)
480 time.sleep(0.1)
480 time.sleep(0.1)
481 self.zmq_socket.close()
481 self.zmq_socket.close()
482 if self.client:
482 if self.client:
483 self.client.loop_stop()
483 self.client.loop_stop()
484 self.client.disconnect()
484 self.client.disconnect()
485
485
486
486
487 class ReceiverData(ProcessingUnit):
487 class ReceiverData(ProcessingUnit):
488
488
489 __attrs__ = ['server']
489 __attrs__ = ['server']
490
490
491 def __init__(self, **kwargs):
491 def __init__(self, **kwargs):
492
492
493 ProcessingUnit.__init__(self, **kwargs)
493 ProcessingUnit.__init__(self, **kwargs)
494
494
495 self.isConfig = False
495 self.isConfig = False
496 server = kwargs.get('server', 'zmq.pipe')
496 server = kwargs.get('server', 'zmq.pipe')
497 if 'tcp://' in server:
497 if 'tcp://' in server:
498 address = server
498 address = server
499 else:
499 else:
500 address = 'ipc:///tmp/%s' % server
500 address = 'ipc:///tmp/%s' % server
501
501
502 self.address = address
502 self.address = address
503 self.dataOut = JROData()
503 self.dataOut = JROData()
504
504
505 def setup(self):
505 def setup(self):
506
506
507 self.context = zmq.Context()
507 self.context = zmq.Context()
508 self.receiver = self.context.socket(zmq.PULL)
508 self.receiver = self.context.socket(zmq.PULL)
509 self.receiver.bind(self.address)
509 self.receiver.bind(self.address)
510 time.sleep(0.5)
510 time.sleep(0.5)
511 log.success('ReceiverData from {}'.format(self.address))
511 log.success('ReceiverData from {}'.format(self.address))
512
512
513
513
514 def run(self):
514 def run(self):
515
515
516 if not self.isConfig:
516 if not self.isConfig:
517 self.setup()
517 self.setup()
518 self.isConfig = True
518 self.isConfig = True
519
519
520 self.dataOut = self.receiver.recv_pyobj()
520 self.dataOut = self.receiver.recv_pyobj()
521 log.log('{} - {}'.format(self.dataOut.type,
521 log.log('{} - {}'.format(self.dataOut.type,
522 self.dataOut.datatime.ctime(),),
522 self.dataOut.datatime.ctime(),),
523 'Receiving')
523 'Receiving')
524
524
525
525
526 class PlotterReceiver(ProcessingUnit, Process):
526 class PlotterReceiver(ProcessingUnit, Process):
527
527
528 throttle_value = 5
528 throttle_value = 5
529 __attrs__ = ['server', 'plottypes', 'realtime', 'localtime', 'throttle',
529 __attrs__ = ['server', 'plottypes', 'realtime', 'localtime', 'throttle',
530 'exp_code', 'web_server', 'buffering']
530 'exp_code', 'web_server', 'buffering']
531
531
532 def __init__(self, **kwargs):
532 def __init__(self, **kwargs):
533
533
534 ProcessingUnit.__init__(self, **kwargs)
534 ProcessingUnit.__init__(self, **kwargs)
535 Process.__init__(self)
535 Process.__init__(self)
536 self.mp = False
536 self.mp = False
537 self.isConfig = False
537 self.isConfig = False
538 self.isWebConfig = False
538 self.isWebConfig = False
539 self.connections = 0
539 self.connections = 0
540 server = kwargs.get('server', 'zmq.pipe')
540 server = kwargs.get('server', 'zmq.pipe')
541 web_server = kwargs.get('web_server', None)
541 web_server = kwargs.get('web_server', None)
542 if 'tcp://' in server:
542 if 'tcp://' in server:
543 address = server
543 address = server
544 else:
544 else:
545 address = 'ipc:///tmp/%s' % server
545 address = 'ipc:///tmp/%s' % server
546 self.address = address
546 self.address = address
547 self.web_address = web_server
547 self.web_address = web_server
548 self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')]
548 self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')]
549 self.realtime = kwargs.get('realtime', False)
549 self.realtime = kwargs.get('realtime', False)
550 self.localtime = kwargs.get('localtime', True)
550 self.localtime = kwargs.get('localtime', True)
551 self.buffering = kwargs.get('buffering', True)
551 self.buffering = kwargs.get('buffering', True)
552 self.throttle_value = kwargs.get('throttle', 5)
552 self.throttle_value = kwargs.get('throttle', 5)
553 self.exp_code = kwargs.get('exp_code', None)
553 self.exp_code = kwargs.get('exp_code', None)
554 self.sendData = self.initThrottle(self.throttle_value)
554 self.sendData = self.initThrottle(self.throttle_value)
555 self.dates = []
555 self.dates = []
556 self.setup()
556 self.setup()
557
557
558 def setup(self):
558 def setup(self):
559
559
560 self.data = Data(self.plottypes, self.throttle_value, self.exp_code, self.buffering)
560 self.data = Data(self.plottypes, self.throttle_value, self.exp_code, self.buffering)
561 self.isConfig = True
561 self.isConfig = True
562
562
563 def event_monitor(self, monitor):
563 def event_monitor(self, monitor):
564
564
565 events = {}
565 events = {}
566
566
567 for name in dir(zmq):
567 for name in dir(zmq):
568 if name.startswith('EVENT_'):
568 if name.startswith('EVENT_'):
569 value = getattr(zmq, name)
569 value = getattr(zmq, name)
570 events[value] = name
570 events[value] = name
571
571
572 while monitor.poll():
572 while monitor.poll():
573 evt = recv_monitor_message(monitor)
573 evt = recv_monitor_message(monitor)
574 if evt['event'] == 32:
574 if evt['event'] == 32:
575 self.connections += 1
575 self.connections += 1
576 if evt['event'] == 512:
576 if evt['event'] == 512:
577 pass
577 pass
578
578
579 evt.update({'description': events[evt['event']]})
579 evt.update({'description': events[evt['event']]})
580
580
581 if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
581 if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
582 break
582 break
583 monitor.close()
583 monitor.close()
584 print('event monitor thread done!')
584 print('event monitor thread done!')
585
585
586 def initThrottle(self, throttle_value):
586 def initThrottle(self, throttle_value):
587
587
588 @throttle(seconds=throttle_value)
588 @throttle(seconds=throttle_value)
589 def sendDataThrottled(fn_sender, data):
589 def sendDataThrottled(fn_sender, data):
590 fn_sender(data)
590 fn_sender(data)
591
591
592 return sendDataThrottled
592 return sendDataThrottled
593
593
594 def send(self, data):
594 def send(self, data):
595 log.log('Sending {}'.format(data), self.name)
595 log.log('Sending {}'.format(data), self.name)
596 self.sender.send_pyobj(data)
596 self.sender.send_pyobj(data)
597
597
598 def run(self):
598 def run(self):
599
599
600 log.log(
600 log.log(
601 'Starting from {}'.format(self.address),
601 'Starting from {}'.format(self.address),
602 self.name
602 self.name
603 )
603 )
604
604
605 self.context = zmq.Context()
605 self.context = zmq.Context()
606 self.receiver = self.context.socket(zmq.PULL)
606 self.receiver = self.context.socket(zmq.PULL)
607 self.receiver.bind(self.address)
607 self.receiver.bind(self.address)
608 monitor = self.receiver.get_monitor_socket()
608 monitor = self.receiver.get_monitor_socket()
609 self.sender = self.context.socket(zmq.PUB)
609 self.sender = self.context.socket(zmq.PUB)
610 if self.web_address:
610 if self.web_address:
611 log.success(
611 log.success(
612 'Sending to web: {}'.format(self.web_address),
612 'Sending to web: {}'.format(self.web_address),
613 self.name
613 self.name
614 )
614 )
615 self.sender_web = self.context.socket(zmq.PUSH)
615 self.sender_web = self.context.socket(zmq.PUSH)
616 self.sender_web.connect(self.web_address)
616 self.sender_web.connect(self.web_address)
617 time.sleep(1)
617 time.sleep(1)
618
618
619 if 'server' in self.kwargs:
619 if 'server' in self.kwargs:
620 self.sender.bind("ipc:///tmp/{}.plots".format(self.kwargs['server']))
620 self.sender.bind("ipc:///tmp/{}.plots".format(self.kwargs['server']))
621 else:
621 else:
622 self.sender.bind("ipc:///tmp/zmq.plots")
622 self.sender.bind("ipc:///tmp/zmq.plots")
623
623
624 time.sleep(2)
624 time.sleep(2)
625
625
626 t = Thread(target=self.event_monitor, args=(monitor,))
626 t = Thread(target=self.event_monitor, args=(monitor,))
627 t.start()
627 t.start()
628
628
629 while True:
629 while True:
630 dataOut = self.receiver.recv_pyobj()
630 dataOut = self.receiver.recv_pyobj()
631 if not dataOut.flagNoData:
631 if not dataOut.flagNoData:
632 if dataOut.type == 'Parameters':
632 if dataOut.type == 'Parameters':
633 tm = dataOut.utctimeInit
633 tm = dataOut.utctimeInit
634 else:
634 else:
635 tm = dataOut.utctime
635 tm = dataOut.utctime
636 if dataOut.useLocalTime:
636 if dataOut.useLocalTime:
637 if not self.localtime:
637 if not self.localtime:
638 tm += time.timezone
638 tm += time.timezone
639 dt = datetime.datetime.fromtimestamp(tm).date()
639 dt = datetime.datetime.fromtimestamp(tm).date()
640 else:
640 else:
641 if self.localtime:
641 if self.localtime:
642 tm -= time.timezone
642 tm -= time.timezone
643 dt = datetime.datetime.utcfromtimestamp(tm).date()
643 dt = datetime.datetime.utcfromtimestamp(tm).date()
644 coerce = False
644 coerce = False
645 if dt not in self.dates:
645 if dt not in self.dates:
646 if self.data:
646 if self.data:
647 self.data.ended = True
647 self.data.ended = True
648 self.send(self.data)
648 self.send(self.data)
649 coerce = True
649 coerce = True
650 self.data.setup()
650 self.data.setup()
651 self.dates.append(dt)
651 self.dates.append(dt)
652
652
653 self.data.update(dataOut, tm)
653 self.data.update(dataOut, tm)
654
654
655 if dataOut.finished is True:
655 if dataOut.finished is True:
656 self.connections -= 1
656 self.connections -= 1
657 if self.connections == 0 and dt in self.dates:
657 if self.connections == 0 and dt in self.dates:
658 self.data.ended = True
658 self.data.ended = True
659 self.send(self.data)
659 self.send(self.data)
660 self.data.setup()
660 self.data.setup()
661 else:
661 else:
662 if self.realtime:
662 if self.realtime:
663 self.send(self.data)
663 self.send(self.data)
664 if self.web_address:
664 if self.web_address:
665 payload = self.data.jsonify()
665 payload = self.data.jsonify()
666 log.log('Sending to web... type:{}, size:{}'.format(dataOut.type, len(payload)), self.name)
666 log.log('Sending to web... type:{}, size:{}'.format(dataOut.type, len(payload)), self.name)
667 self.sender_web.send(payload)
667 self.sender_web.send(payload)
668 else:
668 else:
669 self.sendData(self.send, self.data, coerce=coerce)
669 self.sendData(self.send, self.data, coerce=coerce)
670 coerce = False
670 coerce = False
671
671
672 return
672 return
673
673
674
674
675 class SendToFTP(Operation, Process):
675 class SendToFTP(Operation, Process):
676
676
677 '''
677 '''
678 Operation to send data over FTP.
678 Operation to send data over FTP.
679 '''
679 '''
680
680
681 __attrs__ = ['server', 'username', 'password', 'patterns', 'timeout']
681 __attrs__ = ['server', 'username', 'password', 'patterns', 'timeout']
682
682
683 def __init__(self, **kwargs):
683 def __init__(self, **kwargs):
684 '''
684 '''
685 patterns = [(local1, remote1, ext, delay, exp_code, sub_exp_code), ...]
685 patterns = [(local1, remote1, ext, delay, exp_code, sub_exp_code), ...]
686 '''
686 '''
687 Operation.__init__(self, **kwargs)
687 Operation.__init__(self, **kwargs)
688 Process.__init__(self)
688 Process.__init__(self)
689 self.server = kwargs.get('server')
689 self.server = kwargs.get('server')
690 self.username = kwargs.get('username')
690 self.username = kwargs.get('username')
691 self.password = kwargs.get('password')
691 self.password = kwargs.get('password')
692 self.patterns = kwargs.get('patterns')
692 self.patterns = kwargs.get('patterns')
693 self.timeout = kwargs.get('timeout', 10)
693 self.timeout = kwargs.get('timeout', 10)
694 self.times = [time.time() for p in self.patterns]
694 self.times = [time.time() for p in self.patterns]
695 self.latest = ['' for p in self.patterns]
695 self.latest = ['' for p in self.patterns]
696 self.mp = False
696 self.mp = False
697 self.ftp = None
697 self.ftp = None
698
698
699 def setup(self):
699 def setup(self):
700
700
701 log.log('Connecting to ftp://{}'.format(self.server), self.name)
701 log.log('Connecting to ftp://{}'.format(self.server), self.name)
702 try:
702 try:
703 self.ftp = ftplib.FTP(self.server, timeout=self.timeout)
703 self.ftp = ftplib.FTP(self.server, timeout=self.timeout)
704 except ftplib.all_errors:
704 except ftplib.all_errors:
705 log.error('Server connection fail: {}'.format(self.server), self.name)
705 log.error('Server connection fail: {}'.format(self.server), self.name)
706 if self.ftp is not None:
706 if self.ftp is not None:
707 self.ftp.close()
707 self.ftp.close()
708 self.ftp = None
708 self.ftp = None
709 self.isConfig = False
709 self.isConfig = False
710 return
710 return
711
711
712 try:
712 try:
713 self.ftp.login(self.username, self.password)
713 self.ftp.login(self.username, self.password)
714 except ftplib.all_errors:
714 except ftplib.all_errors:
715 log.error('The given username y/o password are incorrect', self.name)
715 log.error('The given username y/o password are incorrect', self.name)
716 if self.ftp is not None:
716 if self.ftp is not None:
717 self.ftp.close()
717 self.ftp.close()
718 self.ftp = None
718 self.ftp = None
719 self.isConfig = False
719 self.isConfig = False
720 return
720 return
721
721
722 log.success('Connection success', self.name)
722 log.success('Connection success', self.name)
723 self.isConfig = True
723 self.isConfig = True
724 return
724 return
725
725
726 def check(self):
726 def check(self):
727
727
728 try:
728 try:
729 self.ftp.voidcmd("NOOP")
729 self.ftp.voidcmd("NOOP")
730 except:
730 except:
731 log.warning('Connection lost... trying to reconnect', self.name)
731 log.warning('Connection lost... trying to reconnect', self.name)
732 if self.ftp is not None:
732 if self.ftp is not None:
733 self.ftp.close()
733 self.ftp.close()
734 self.ftp = None
734 self.ftp = None
735 self.setup()
735 self.setup()
736
736
737 def find_files(self, path, ext):
737 def find_files(self, path, ext):
738
738
739 files = glob.glob1(path, '*{}'.format(ext))
739 files = glob.glob1(path, '*{}'.format(ext))
740 files.sort()
740 files.sort()
741 if files:
741 if files:
742 return files[-1]
742 return files[-1]
743 return None
743 return None
744
744
745 def getftpname(self, filename, exp_code, sub_exp_code):
745 def getftpname(self, filename, exp_code, sub_exp_code):
746
746
747 thisDatetime = datetime.datetime.strptime(filename.split('_')[1], '%Y%m%d')
747 thisDatetime = datetime.datetime.strptime(filename.split('_')[1], '%Y%m%d')
748 YEAR_STR = '%4.4d'%thisDatetime.timetuple().tm_year
748 YEAR_STR = '%4.4d'%thisDatetime.timetuple().tm_year
749 DOY_STR = '%3.3d'%thisDatetime.timetuple().tm_yday
749 DOY_STR = '%3.3d'%thisDatetime.timetuple().tm_yday
750 exp_code = '%3.3d'%exp_code
750 exp_code = '%3.3d'%exp_code
751 sub_exp_code = '%2.2d'%sub_exp_code
751 sub_exp_code = '%2.2d'%sub_exp_code
752 plot_code = '%2.2d'% PLOT_CODES[filename.split('_')[0].split('-')[0]]
752 plot_code = '%2.2d'% PLOT_CODES[filename.split('_')[0].split('-')[1]]
753 name = YEAR_STR + DOY_STR + '00' + exp_code + sub_exp_code + plot_code + '00.png'
753 name = YEAR_STR + DOY_STR + '00' + exp_code + sub_exp_code + plot_code + '00.png'
754 return name
754 return name
755
755
756 def upload(self, src, dst):
756 def upload(self, src, dst):
757
757
758 log.log('Uploading {} '.format(src), self.name, nl=False)
758 log.log('Uploading {} '.format(src), self.name, nl=False)
759
759
760 fp = open(src, 'rb')
760 fp = open(src, 'rb')
761 command = 'STOR {}'.format(dst)
761 command = 'STOR {}'.format(dst)
762
762
763 try:
763 try:
764 self.ftp.storbinary(command, fp, blocksize=1024)
764 self.ftp.storbinary(command, fp, blocksize=1024)
765 except ftplib.all_errors, e:
765 except ftplib.all_errors, e:
766 log.error('{}'.format(e), self.name)
766 log.error('{}'.format(e), self.name)
767 if self.ftp is not None:
767 if self.ftp is not None:
768 self.ftp.close()
768 self.ftp.close()
769 self.ftp = None
769 self.ftp = None
770 return
770 return
771
771
772 try:
772 try:
773 self.ftp.sendcmd('SITE CHMOD 755 {}'.format(dst))
773 self.ftp.sendcmd('SITE CHMOD 755 {}'.format(dst))
774 except ftplib.all_errors, e:
774 except ftplib.all_errors, e:
775 log.error('{}'.format(e), self.name)
775 log.error('{}'.format(e), self.name)
776 if self.ftp is not None:
776 if self.ftp is not None:
777 self.ftp.close()
777 self.ftp.close()
778 self.ftp = None
778 self.ftp = None
779
779
780 fp.close()
780 fp.close()
781
781
782 log.success('OK', tag='')
782 log.success('OK', tag='')
783
783
784 def send_files(self):
784 def send_files(self):
785
785
786 for x, pattern in enumerate(self.patterns):
786 for x, pattern in enumerate(self.patterns):
787 local, remote, ext, delay, exp_code, sub_exp_code = pattern
787 local, remote, ext, delay, exp_code, sub_exp_code = pattern
788 if time.time()-self.times[x] >= delay:
788 if time.time()-self.times[x] >= delay:
789 srcname = self.find_files(local, ext)
789 srcname = self.find_files(local, ext)
790
790
791 if srcname is None or srcname == self.latest[x]:
791 if srcname is None or srcname == self.latest[x]:
792 continue
792 continue
793
793
794 if 'png' in ext:
794 if 'png' in ext:
795 dstname = self.getftpname(srcname, exp_code, sub_exp_code)
795 dstname = self.getftpname(srcname, exp_code, sub_exp_code)
796 else:
796 else:
797 dstname = srcname
797 dstname = srcname
798
798
799 src = os.path.join(local, srcname)
799 src = os.path.join(local, srcname)
800
800
801 if os.path.getmtime(src) < time.time() - 30*60:
801 if os.path.getmtime(src) < time.time() - 30*60:
802 continue
802 continue
803
803
804 dst = os.path.join(remote, dstname)
804 dst = os.path.join(remote, dstname)
805
805
806 if self.ftp is None:
806 if self.ftp is None:
807 continue
807 continue
808
808
809 self.upload(src, dst)
809 self.upload(src, dst)
810
810
811 self.times[x] = time.time()
811 self.times[x] = time.time()
812 self.latest[x] = srcname
812 self.latest[x] = srcname
813
813
814 def run(self):
814 def run(self):
815
815
816 while True:
816 while True:
817 if not self.isConfig:
817 if not self.isConfig:
818 self.setup()
818 self.setup()
819 if self.ftp is not None:
819 if self.ftp is not None:
820 self.check()
820 self.check()
821 self.send_files()
821 self.send_files()
822 time.sleep(2)
822 time.sleep(2)
823
823
824 def close():
824 def close():
825
825
826 if self.ftp is not None:
826 if self.ftp is not None:
827 if self.ftp is not None:
827 if self.ftp is not None:
828 self.ftp.close()
828 self.ftp.close()
829 self.terminate()
829 self.terminate()
General Comments 0
You need to be logged in to leave comments. Login now