##// END OF EJS Templates
Add new events to PlotData, fix utc times
Juan C. Espinoza -
r1087:27828ce411ee
parent child
Show More
@@ -1,819 +1,895
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("seismic_r", 20)(numpy.arange(20))[10:15]
19 blu_values = matplotlib.pyplot.get_cmap("seismic_r", 20)(numpy.arange(20))[10:15]
20 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list("jro", numpy.vstack((blu_values, jet_values)))
20 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list("jro", numpy.vstack((blu_values, jet_values)))
21 matplotlib.pyplot.register_cmap(cmap=ncmap)
21 matplotlib.pyplot.register_cmap(cmap=ncmap)
22
22
23 func = lambda x, pos: '{}'.format(datetime.datetime.fromtimestamp(x).strftime('%H:%M'))
23 func = lambda x, pos: '{}'.format(datetime.datetime.utcfromtimestamp(x).strftime('%H:%M'))
24
25 UT1970 = datetime.datetime(1970, 1, 1) - datetime.timedelta(seconds=time.timezone)
26
24
27 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'RdBu_r', 'seismic')]
25 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'RdBu_r', 'seismic')]
28
26
29 class PlotData(Operation, Process):
27 class PlotData(Operation, Process):
30 '''
28 '''
31 Base class for Schain plotting operations
29 Base class for Schain plotting operations
32 '''
30 '''
33
31
34 CODE = 'Figure'
32 CODE = 'Figure'
35 colormap = 'jro'
33 colormap = 'jro'
36 bgcolor = 'white'
34 bgcolor = 'white'
37 CONFLATE = False
35 CONFLATE = False
38 __MAXNUMX = 80
36 __MAXNUMX = 80
39 __missing = 1E30
37 __missing = 1E30
40
38
41 def __init__(self, **kwargs):
39 def __init__(self, **kwargs):
42
40
43 Operation.__init__(self, plot=True, **kwargs)
41 Operation.__init__(self, plot=True, **kwargs)
44 Process.__init__(self)
42 Process.__init__(self)
45 self.kwargs['code'] = self.CODE
43 self.kwargs['code'] = self.CODE
46 self.mp = False
44 self.mp = False
47 self.data = None
45 self.data = None
48 self.isConfig = False
46 self.isConfig = False
49 self.figures = []
47 self.figures = []
50 self.axes = []
48 self.axes = []
51 self.cb_axes = []
49 self.cb_axes = []
52 self.localtime = kwargs.pop('localtime', True)
50 self.localtime = kwargs.pop('localtime', True)
53 self.show = kwargs.get('show', True)
51 self.show = kwargs.get('show', True)
54 self.save = kwargs.get('save', False)
52 self.save = kwargs.get('save', False)
55 self.colormap = kwargs.get('colormap', self.colormap)
53 self.colormap = kwargs.get('colormap', self.colormap)
56 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
54 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
57 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
55 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
58 self.colormaps = kwargs.get('colormaps', None)
56 self.colormaps = kwargs.get('colormaps', None)
59 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
57 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
60 self.showprofile = kwargs.get('showprofile', False)
58 self.showprofile = kwargs.get('showprofile', False)
61 self.title = kwargs.get('wintitle', self.CODE.upper())
59 self.title = kwargs.get('wintitle', self.CODE.upper())
62 self.cb_label = kwargs.get('cb_label', None)
60 self.cb_label = kwargs.get('cb_label', None)
63 self.cb_labels = kwargs.get('cb_labels', None)
61 self.cb_labels = kwargs.get('cb_labels', None)
64 self.xaxis = kwargs.get('xaxis', 'frequency')
62 self.xaxis = kwargs.get('xaxis', 'frequency')
65 self.zmin = kwargs.get('zmin', None)
63 self.zmin = kwargs.get('zmin', None)
66 self.zmax = kwargs.get('zmax', None)
64 self.zmax = kwargs.get('zmax', None)
67 self.zlimits = kwargs.get('zlimits', None)
65 self.zlimits = kwargs.get('zlimits', None)
68 self.xmin = kwargs.get('xmin', None)
66 self.xmin = kwargs.get('xmin', None)
69 self.xmax = kwargs.get('xmax', None)
67 self.xmax = kwargs.get('xmax', None)
70 self.xrange = kwargs.get('xrange', 24)
68 self.xrange = kwargs.get('xrange', 24)
71 self.ymin = kwargs.get('ymin', None)
69 self.ymin = kwargs.get('ymin', None)
72 self.ymax = kwargs.get('ymax', None)
70 self.ymax = kwargs.get('ymax', None)
73 self.xlabel = kwargs.get('xlabel', None)
71 self.xlabel = kwargs.get('xlabel', None)
74 self.__MAXNUMY = kwargs.get('decimation', 100)
72 self.__MAXNUMY = kwargs.get('decimation', 100)
75 self.showSNR = kwargs.get('showSNR', False)
73 self.showSNR = kwargs.get('showSNR', False)
76 self.oneFigure = kwargs.get('oneFigure', True)
74 self.oneFigure = kwargs.get('oneFigure', True)
77 self.width = kwargs.get('width', None)
75 self.width = kwargs.get('width', None)
78 self.height = kwargs.get('height', None)
76 self.height = kwargs.get('height', None)
79 self.colorbar = kwargs.get('colorbar', True)
77 self.colorbar = kwargs.get('colorbar', True)
80 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
78 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
81 self.titles = ['' for __ in range(16)]
79 self.titles = ['' for __ in range(16)]
82
80
83 def __setup(self):
81 def __setup(self):
84 '''
82 '''
85 Common setup for all figures, here figures and axes are created
83 Common setup for all figures, here figures and axes are created
86 '''
84 '''
87
85
88 self.setup()
86 self.setup()
89
87
90 self.time_label = 'LT' if self.localtime else 'UTC'
88 self.time_label = 'LT' if self.localtime else 'UTC'
91
89
92 if self.width is None:
90 if self.width is None:
93 self.width = 8
91 self.width = 8
94
92
95 self.figures = []
93 self.figures = []
96 self.axes = []
94 self.axes = []
97 self.cb_axes = []
95 self.cb_axes = []
98 self.pf_axes = []
96 self.pf_axes = []
99 self.cmaps = []
97 self.cmaps = []
100
98
101 size = '15%' if self.ncols==1 else '30%'
99 size = '15%' if self.ncols==1 else '30%'
102 pad = '4%' if self.ncols==1 else '8%'
100 pad = '4%' if self.ncols==1 else '8%'
103
101
104 if self.oneFigure:
102 if self.oneFigure:
105 if self.height is None:
103 if self.height is None:
106 self.height = 1.4*self.nrows + 1
104 self.height = 1.4*self.nrows + 1
107 fig = plt.figure(figsize=(self.width, self.height),
105 fig = plt.figure(figsize=(self.width, self.height),
108 edgecolor='k',
106 edgecolor='k',
109 facecolor='w')
107 facecolor='w')
110 self.figures.append(fig)
108 self.figures.append(fig)
111 for n in range(self.nplots):
109 for n in range(self.nplots):
112 ax = fig.add_subplot(self.nrows, self.ncols, n+1)
110 ax = fig.add_subplot(self.nrows, self.ncols, n+1)
113 ax.tick_params(labelsize=8)
111 ax.tick_params(labelsize=8)
114 ax.firsttime = True
112 ax.firsttime = True
115 ax.index = 0
113 ax.index = 0
114 ax.press = None
116 self.axes.append(ax)
115 self.axes.append(ax)
117 if self.showprofile:
116 if self.showprofile:
118 cax = self.__add_axes(ax, size=size, pad=pad)
117 cax = self.__add_axes(ax, size=size, pad=pad)
119 cax.tick_params(labelsize=8)
118 cax.tick_params(labelsize=8)
120 self.pf_axes.append(cax)
119 self.pf_axes.append(cax)
121 else:
120 else:
122 if self.height is None:
121 if self.height is None:
123 self.height = 3
122 self.height = 3
124 for n in range(self.nplots):
123 for n in range(self.nplots):
125 fig = plt.figure(figsize=(self.width, self.height),
124 fig = plt.figure(figsize=(self.width, self.height),
126 edgecolor='k',
125 edgecolor='k',
127 facecolor='w')
126 facecolor='w')
128 ax = fig.add_subplot(1, 1, 1)
127 ax = fig.add_subplot(1, 1, 1)
129 ax.tick_params(labelsize=8)
128 ax.tick_params(labelsize=8)
130 ax.firsttime = True
129 ax.firsttime = True
131 ax.index = 0
130 ax.index = 0
131 ax.press = None
132 self.figures.append(fig)
132 self.figures.append(fig)
133 self.axes.append(ax)
133 self.axes.append(ax)
134 if self.showprofile:
134 if self.showprofile:
135 cax = self.__add_axes(ax, size=size, pad=pad)
135 cax = self.__add_axes(ax, size=size, pad=pad)
136 cax.tick_params(labelsize=8)
136 cax.tick_params(labelsize=8)
137 self.pf_axes.append(cax)
137 self.pf_axes.append(cax)
138
138
139 for n in range(self.nrows):
139 for n in range(self.nrows):
140 if self.colormaps is not None:
140 if self.colormaps is not None:
141 cmap = plt.get_cmap(self.colormaps[n])
141 cmap = plt.get_cmap(self.colormaps[n])
142 else:
142 else:
143 cmap = plt.get_cmap(self.colormap)
143 cmap = plt.get_cmap(self.colormap)
144 cmap.set_bad(self.bgcolor, 1.)
144 cmap.set_bad(self.bgcolor, 1.)
145 self.cmaps.append(cmap)
145 self.cmaps.append(cmap)
146
146
147 for fig in self.figures:
147 for fig in self.figures:
148 fig.canvas.mpl_connect('key_press_event', self.event_key_press)
148 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
149 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
150 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
151 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
152 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
149
153
150 def event_key_press(self, event):
154 def OnKeyPress(self, event):
151 '''
155 '''
156 Event for pressing keys (up, down) change colormap
152 '''
157 '''
153
158 ax = event.inaxes
154 for ax in self.axes:
159 if ax in self.axes:
155 if ax == event.inaxes:
156 if event.key == 'down':
160 if event.key == 'down':
157 ax.index += 1
161 ax.index += 1
158 elif event.key == 'up':
162 elif event.key == 'up':
159 ax.index -= 1
163 ax.index -= 1
160 if ax.index < 0:
164 if ax.index < 0:
161 ax.index = len(CMAPS) - 1
165 ax.index = len(CMAPS) - 1
162 elif ax.index == len(CMAPS):
166 elif ax.index == len(CMAPS):
163 ax.index = 0
167 ax.index = 0
164 cmap = CMAPS[ax.index]
168 cmap = CMAPS[ax.index]
165 ax.cbar.set_cmap(cmap)
169 ax.cbar.set_cmap(cmap)
166 ax.cbar.draw_all()
170 ax.cbar.draw_all()
167 ax.plt.set_cmap(cmap)
171 ax.plt.set_cmap(cmap)
168 ax.cbar.patch.figure.canvas.draw()
172 ax.cbar.patch.figure.canvas.draw()
169
173
174 def OnBtnScroll(self, event):
175 '''
176 Event for scrolling, scale figure
177 '''
178 cb_ax = event.inaxes
179 if cb_ax in [ax.cbar.ax for ax in self.axes]:
180 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
181 pt = ax.cbar.ax.bbox.get_points()[:,1]
182 nrm = ax.cbar.norm
183 vmin, vmax, p0, p1, pS = (nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
184 scale = 2 if event.step == 1 else 0.5
185 point = vmin + (vmax - vmin) / (p1 - p0)*(pS - p0)
186 ax.cbar.norm.vmin = point - scale*(point - vmin)
187 ax.cbar.norm.vmax = point - scale*(point - vmax)
188 ax.plt.set_norm(ax.cbar.norm)
189 ax.cbar.draw_all()
190 ax.cbar.patch.figure.canvas.draw()
191
192 def onBtnPress(self, event):
193 '''
194 Event for mouse button press
195 '''
196 cb_ax = event.inaxes
197 if cb_ax is None:
198 return
199
200 if cb_ax in [ax.cbar.ax for ax in self.axes]:
201 cb_ax.press = event.x, event.y
202 else:
203 cb_ax.press = None
204
205 def onMotion(self, event):
206 '''
207 Event for move inside colorbar
208 '''
209 cb_ax = event.inaxes
210 if cb_ax is None:
211 return
212 if cb_ax not in [ax.cbar.ax for ax in self.axes]:
213 return
214 if cb_ax.press is None:
215 return
216
217 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
218 xprev, yprev = cb_ax.press
219 dx = event.x - xprev
220 dy = event.y - yprev
221 cb_ax.press = event.x, event.y
222 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
223 perc = 0.03
224
225 if event.button == 1:
226 ax.cbar.norm.vmin -= (perc*scale)*numpy.sign(dy)
227 ax.cbar.norm.vmax -= (perc*scale)*numpy.sign(dy)
228 elif event.button == 3:
229 ax.cbar.norm.vmin -= (perc*scale)*numpy.sign(dy)
230 ax.cbar.norm.vmax += (perc*scale)*numpy.sign(dy)
231
232 ax.cbar.draw_all()
233 ax.plt.set_norm(ax.cbar.norm)
234 ax.cbar.patch.figure.canvas.draw()
235
236 def onBtnRelease(self, event):
237 '''
238 Event for mouse button release
239 '''
240 cb_ax = event.inaxes
241 if cb_ax is not None:
242 cb_ax.press = None
243
170 def __add_axes(self, ax, size='30%', pad='8%'):
244 def __add_axes(self, ax, size='30%', pad='8%'):
171 '''
245 '''
172 Add new axes to the given figure
246 Add new axes to the given figure
173 '''
247 '''
174 divider = make_axes_locatable(ax)
248 divider = make_axes_locatable(ax)
175 nax = divider.new_horizontal(size=size, pad=pad)
249 nax = divider.new_horizontal(size=size, pad=pad)
176 ax.figure.add_axes(nax)
250 ax.figure.add_axes(nax)
177 return nax
251 return nax
178
252
179 self.setup()
253 self.setup()
180
254
181 def setup(self):
255 def setup(self):
182 '''
256 '''
183 This method should be implemented in the child class, the following
257 This method should be implemented in the child class, the following
184 attributes should be set:
258 attributes should be set:
185
259
186 self.nrows: number of rows
260 self.nrows: number of rows
187 self.ncols: number of cols
261 self.ncols: number of cols
188 self.nplots: number of plots (channels or pairs)
262 self.nplots: number of plots (channels or pairs)
189 self.ylabel: label for Y axes
263 self.ylabel: label for Y axes
190 self.titles: list of axes title
264 self.titles: list of axes title
191
265
192 '''
266 '''
193 raise(NotImplementedError, 'Implement this method in child class')
267 raise(NotImplementedError, 'Implement this method in child class')
194
268
195 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
269 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
196 '''
270 '''
197 Create a masked array for missing data
271 Create a masked array for missing data
198 '''
272 '''
199 if x_buffer.shape[0] < 2:
273 if x_buffer.shape[0] < 2:
200 return x_buffer, y_buffer, z_buffer
274 return x_buffer, y_buffer, z_buffer
201
275
202 deltas = x_buffer[1:] - x_buffer[0:-1]
276 deltas = x_buffer[1:] - x_buffer[0:-1]
203 x_median = numpy.median(deltas)
277 x_median = numpy.median(deltas)
204
278
205 index = numpy.where(deltas > 5*x_median)
279 index = numpy.where(deltas > 5*x_median)
206
280
207 if len(index[0]) != 0:
281 if len(index[0]) != 0:
208 z_buffer[::, index[0], ::] = self.__missing
282 z_buffer[::, index[0], ::] = self.__missing
209 z_buffer = numpy.ma.masked_inside(z_buffer,
283 z_buffer = numpy.ma.masked_inside(z_buffer,
210 0.99*self.__missing,
284 0.99*self.__missing,
211 1.01*self.__missing)
285 1.01*self.__missing)
212
286
213 return x_buffer, y_buffer, z_buffer
287 return x_buffer, y_buffer, z_buffer
214
288
215 def decimate(self):
289 def decimate(self):
216
290
217 # dx = int(len(self.x)/self.__MAXNUMX) + 1
291 # dx = int(len(self.x)/self.__MAXNUMX) + 1
218 dy = int(len(self.y)/self.__MAXNUMY) + 1
292 dy = int(len(self.y)/self.__MAXNUMY) + 1
219
293
220 # x = self.x[::dx]
294 # x = self.x[::dx]
221 x = self.x
295 x = self.x
222 y = self.y[::dy]
296 y = self.y[::dy]
223 z = self.z[::, ::, ::dy]
297 z = self.z[::, ::, ::dy]
224
298
225 return x, y, z
299 return x, y, z
226
300
227 def format(self):
301 def format(self):
228 '''
302 '''
229 Set min and max values, labels, ticks and titles
303 Set min and max values, labels, ticks and titles
230 '''
304 '''
231
305
232 if self.xmin is None:
306 if self.xmin is None:
233 xmin = self.min_time
307 xmin = self.min_time
234 else:
308 else:
235 if self.xaxis is 'time':
309 if self.xaxis is 'time':
236 dt = datetime.datetime.fromtimestamp(self.min_time)
310 dt = datetime.datetime.utcfromtimestamp(self.min_time)
237 xmin = (datetime.datetime.combine(dt.date(),
311 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) - datetime.datetime(1970, 1, 1)).total_seconds()
238 datetime.time(int(self.xmin), 0, 0))-UT1970).total_seconds()
239 else:
312 else:
240 xmin = self.xmin
313 xmin = self.xmin
241
314
242 if self.xmax is None:
315 if self.xmax is None:
243 xmax = xmin+self.xrange*60*60
316 xmax = xmin+self.xrange*60*60
244 else:
317 else:
245 if self.xaxis is 'time':
318 if self.xaxis is 'time':
246 dt = datetime.datetime.fromtimestamp(self.min_time)
319 dt = datetime.datetime.utcfromtimestamp(self.min_time)
247 xmax = (datetime.datetime.combine(dt.date(),
320 xmax = (dt.replace(hour=int(self.xmax), minute=0, second=0) - datetime.datetime(1970, 1, 1)).total_seconds()
248 datetime.time(int(self.xmax), 0, 0))-UT1970).total_seconds()
249 else:
321 else:
250 xmax = self.xmax
322 xmax = self.xmax
251
323
252 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
324 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
253 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
325 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
254
326
255 ystep = 200 if ymax>= 800 else 100 if ymax>=400 else 50 if ymax>=200 else 20
327 Y = numpy.array([10, 20, 50, 100, 200, 500, 1000, 2000])
328 i = 1 if numpy.where(ymax < Y)[0][0] < 0 else numpy.where(ymax < Y)[0][0]
329 ystep = Y[i-1]/5
256
330
257 for n, ax in enumerate(self.axes):
331 for n, ax in enumerate(self.axes):
258 if ax.firsttime:
332 if ax.firsttime:
259 ax.set_facecolor(self.bgcolor)
333 ax.set_facecolor(self.bgcolor)
260 ax.yaxis.set_major_locator(MultipleLocator(ystep))
334 ax.yaxis.set_major_locator(MultipleLocator(ystep))
261 if self.xaxis is 'time':
335 if self.xaxis is 'time':
262 ax.xaxis.set_major_formatter(FuncFormatter(func))
336 ax.xaxis.set_major_formatter(FuncFormatter(func))
263 ax.xaxis.set_major_locator(LinearLocator(9))
337 ax.xaxis.set_major_locator(LinearLocator(9))
264 if self.xlabel is not None:
338 if self.xlabel is not None:
265 ax.set_xlabel(self.xlabel)
339 ax.set_xlabel(self.xlabel)
266 ax.set_ylabel(self.ylabel)
340 ax.set_ylabel(self.ylabel)
267 ax.firsttime = False
341 ax.firsttime = False
268 if self.showprofile:
342 if self.showprofile:
269 self.pf_axes[n].set_ylim(ymin, ymax)
343 self.pf_axes[n].set_ylim(ymin, ymax)
270 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
344 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
271 self.pf_axes[n].set_xlabel('dB')
345 self.pf_axes[n].set_xlabel('dB')
272 self.pf_axes[n].grid(b=True, axis='x')
346 self.pf_axes[n].grid(b=True, axis='x')
273 [tick.set_visible(False) for tick in self.pf_axes[n].get_yticklabels()]
347 [tick.set_visible(False) for tick in self.pf_axes[n].get_yticklabels()]
274 if self.colorbar:
348 if self.colorbar:
275 ax.cbar = plt.colorbar(ax.plt, ax=ax, pad=0.02, aspect=10)
349 ax.cbar = plt.colorbar(ax.plt, ax=ax, pad=0.02, aspect=10)
276 ax.cbar.ax.tick_params(labelsize=8)
350 ax.cbar.ax.tick_params(labelsize=8)
351 ax.cbar.ax.press = None
277 if self.cb_label:
352 if self.cb_label:
278 ax.cbar.set_label(self.cb_label, size=8)
353 ax.cbar.set_label(self.cb_label, size=8)
279 elif self.cb_labels:
354 elif self.cb_labels:
280 ax.cbar.set_label(self.cb_labels[n], size=8)
355 ax.cbar.set_label(self.cb_labels[n], size=8)
281
356
282 ax.set_title('{} - {} {}'.format(
357 ax.set_title('{} - {} {}'.format(
283 self.titles[n],
358 self.titles[n],
284 datetime.datetime.fromtimestamp(self.max_time).strftime('%H:%M:%S'),
359 datetime.datetime.utcfromtimestamp(self.max_time).strftime('%H:%M:%S'),
285 self.time_label),
360 self.time_label),
286 size=8)
361 size=8)
287 ax.set_xlim(xmin, xmax)
362 ax.set_xlim(xmin, xmax)
288 ax.set_ylim(ymin, ymax)
363 ax.set_ylim(ymin, ymax)
289
364
290 def __plot(self):
365 def __plot(self):
291 '''
366 '''
292 '''
367 '''
293 log.success('Plotting', self.name)
368 log.success('Plotting', self.name)
294
369
295 self.plot()
370 self.plot()
296 self.format()
371 self.format()
297
372
298 for n, fig in enumerate(self.figures):
373 for n, fig in enumerate(self.figures):
299 if self.nrows == 0 or self.nplots == 0:
374 if self.nrows == 0 or self.nplots == 0:
300 log.warning('No data', self.name)
375 log.warning('No data', self.name)
301 continue
376 continue
302 if self.show:
377 if self.show:
303 fig.show()
378 fig.show()
304
379
305 fig.tight_layout()
380 fig.tight_layout()
306 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
381 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
307 datetime.datetime.fromtimestamp(self.max_time).strftime('%Y/%m/%d')))
382 datetime.datetime.utcfromtimestamp(self.max_time).strftime('%Y/%m/%d')))
308 # fig.canvas.draw()
383 # fig.canvas.draw()
309
384
310 if self.save and self.data.ended:
385 if self.save and self.data.ended:
311 channels = range(self.nrows)
386 channels = range(self.nrows)
312 if self.oneFigure:
387 if self.oneFigure:
313 label = ''
388 label = ''
314 else:
389 else:
315 label = '_{}'.format(channels[n])
390 label = '_{}'.format(channels[n])
316 figname = os.path.join(
391 figname = os.path.join(
317 self.save,
392 self.save,
318 '{}{}_{}.png'.format(
393 '{}{}_{}.png'.format(
319 self.CODE,
394 self.CODE,
320 label,
395 label,
321 datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')
396 datetime.datetime.utcfromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')
322 )
397 )
323 )
398 )
324 print 'Saving figure: {}'.format(figname)
399 print 'Saving figure: {}'.format(figname)
325 fig.savefig(figname)
400 fig.savefig(figname)
326
401
327 def plot(self):
402 def plot(self):
328 '''
403 '''
329 '''
404 '''
330 raise(NotImplementedError, 'Implement this method in child class')
405 raise(NotImplementedError, 'Implement this method in child class')
331
406
332 def run(self):
407 def run(self):
333
408
334 log.success('Starting', self.name)
409 log.success('Starting', self.name)
335
410
336 context = zmq.Context()
411 context = zmq.Context()
337 receiver = context.socket(zmq.SUB)
412 receiver = context.socket(zmq.SUB)
338 receiver.setsockopt(zmq.SUBSCRIBE, '')
413 receiver.setsockopt(zmq.SUBSCRIBE, '')
339 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
414 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
340
415
341 if 'server' in self.kwargs['parent']:
416 if 'server' in self.kwargs['parent']:
342 receiver.connect('ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
417 receiver.connect('ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
343 else:
418 else:
344 receiver.connect("ipc:///tmp/zmq.plots")
419 receiver.connect("ipc:///tmp/zmq.plots")
345
420
346 while True:
421 while True:
347 try:
422 try:
348 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
423 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)
349
424
350 if self.localtime:
425 if self.localtime:
351 self.times = self.data.times - time.timezone
426 self.times = self.data.times - time.timezone
352 else:
427 else:
353 self.times = self.data.times
428 self.times = self.data.times
354
429
355 self.min_time = self.times[0]
430 self.min_time = self.times[0]
356 self.max_time = self.times[-1]
431 self.max_time = self.times[-1]
357
432
358 if self.isConfig is False:
433 if self.isConfig is False:
359 self.__setup()
434 self.__setup()
360 self.isConfig = True
435 self.isConfig = True
361
436
362 self.__plot()
437 self.__plot()
363
438
364 except zmq.Again as e:
439 except zmq.Again as e:
365 log.log('Waiting for data...')
440 log.log('Waiting for data...')
366 if self.data:
441 if self.data:
367 plt.pause(self.data.throttle)
442 plt.pause(self.data.throttle)
368 else:
443 else:
369 time.sleep(2)
444 time.sleep(2)
370
445
371 def close(self):
446 def close(self):
372 if self.data:
447 if self.data:
373 self.__plot()
448 self.__plot()
374
449
375 class PlotSpectraData(PlotData):
450 class PlotSpectraData(PlotData):
376 '''
451 '''
377 Plot for Spectra data
452 Plot for Spectra data
378 '''
453 '''
379
454
380 CODE = 'spc'
455 CODE = 'spc'
381 colormap = 'jro'
456 colormap = 'jro'
382
457
383 def setup(self):
458 def setup(self):
384 self.nplots = len(self.data.channels)
459 self.nplots = len(self.data.channels)
385 self.ncols = int(numpy.sqrt(self.nplots)+ 0.9)
460 self.ncols = int(numpy.sqrt(self.nplots)+ 0.9)
386 self.nrows = int((1.0*self.nplots/self.ncols) + 0.9)
461 self.nrows = int((1.0*self.nplots/self.ncols) + 0.9)
387 self.width = 3.4*self.ncols
462 self.width = 3.4*self.ncols
388 self.height = 3*self.nrows
463 self.height = 3*self.nrows
389 self.cb_label = 'dB'
464 self.cb_label = 'dB'
390 if self.showprofile:
465 if self.showprofile:
391 self.width += 0.8*self.ncols
466 self.width += 0.8*self.ncols
392
467
393 self.ylabel = 'Range [Km]'
468 self.ylabel = 'Range [Km]'
394
469
395 def plot(self):
470 def plot(self):
396 if self.xaxis == "frequency":
471 if self.xaxis == "frequency":
397 x = self.data.xrange[0]
472 x = self.data.xrange[0]
398 self.xlabel = "Frequency (kHz)"
473 self.xlabel = "Frequency (kHz)"
399 elif self.xaxis == "time":
474 elif self.xaxis == "time":
400 x = self.data.xrange[1]
475 x = self.data.xrange[1]
401 self.xlabel = "Time (ms)"
476 self.xlabel = "Time (ms)"
402 else:
477 else:
403 x = self.data.xrange[2]
478 x = self.data.xrange[2]
404 self.xlabel = "Velocity (m/s)"
479 self.xlabel = "Velocity (m/s)"
405
480
406 if self.CODE == 'spc_mean':
481 if self.CODE == 'spc_mean':
407 x = self.data.xrange[2]
482 x = self.data.xrange[2]
408 self.xlabel = "Velocity (m/s)"
483 self.xlabel = "Velocity (m/s)"
409
484
410 self.titles = []
485 self.titles = []
411
486
412 y = self.data.heights
487 y = self.data.heights
413 self.y = y
488 self.y = y
414 z = self.data['spc']
489 z = self.data['spc']
415
490
416 for n, ax in enumerate(self.axes):
491 for n, ax in enumerate(self.axes):
417 noise = self.data['noise'][n][-1]
492 noise = self.data['noise'][n][-1]
418 if self.CODE == 'spc_mean':
493 if self.CODE == 'spc_mean':
419 mean = self.data['mean'][n][-1]
494 mean = self.data['mean'][n][-1]
420 if ax.firsttime:
495 if ax.firsttime:
421 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
496 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
422 self.xmin = self.xmin if self.xmin else -self.xmax
497 self.xmin = self.xmin if self.xmin else -self.xmax
423 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
498 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
424 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
499 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
425 ax.plt = ax.pcolormesh(x, y, z[n].T,
500 ax.plt = ax.pcolormesh(x, y, z[n].T,
426 vmin=self.zmin,
501 vmin=self.zmin,
427 vmax=self.zmax,
502 vmax=self.zmax,
428 cmap=plt.get_cmap(self.colormap)
503 cmap=plt.get_cmap(self.colormap)
429 )
504 )
430
505
431 if self.showprofile:
506 if self.showprofile:
432 ax.plt_profile= self.pf_axes[n].plot(self.data['rti'][n][-1], y)[0]
507 ax.plt_profile= self.pf_axes[n].plot(self.data['rti'][n][-1], y)[0]
433 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
508 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
434 color="k", linestyle="dashed", lw=1)[0]
509 color="k", linestyle="dashed", lw=1)[0]
435 if self.CODE == 'spc_mean':
510 if self.CODE == 'spc_mean':
436 ax.plt_mean = ax.plot(mean, y, color='k')[0]
511 ax.plt_mean = ax.plot(mean, y, color='k')[0]
437 else:
512 else:
438 ax.plt.set_array(z[n].T.ravel())
513 ax.plt.set_array(z[n].T.ravel())
439 if self.showprofile:
514 if self.showprofile:
440 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
515 ax.plt_profile.set_data(self.data['rti'][n][-1], y)
441 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
516 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
442 if self.CODE == 'spc_mean':
517 if self.CODE == 'spc_mean':
443 ax.plt_mean.set_data(mean, y)
518 ax.plt_mean.set_data(mean, y)
444
519
445 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
520 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
446 self.saveTime = self.max_time
521 self.saveTime = self.max_time
447
522
448
523
449 class PlotCrossSpectraData(PlotData):
524 class PlotCrossSpectraData(PlotData):
450
525
451 CODE = 'cspc'
526 CODE = 'cspc'
452 zmin_coh = None
527 zmin_coh = None
453 zmax_coh = None
528 zmax_coh = None
454 zmin_phase = None
529 zmin_phase = None
455 zmax_phase = None
530 zmax_phase = None
456
531
457 def setup(self):
532 def setup(self):
458
533
459 self.ncols = 4
534 self.ncols = 4
460 self.nrows = len(self.data.pairs)
535 self.nrows = len(self.data.pairs)
461 self.nplots = self.nrows*4
536 self.nplots = self.nrows*4
462 self.width = 3.4*self.ncols
537 self.width = 3.4*self.ncols
463 self.height = 3*self.nrows
538 self.height = 3*self.nrows
464 self.ylabel = 'Range [Km]'
539 self.ylabel = 'Range [Km]'
465 self.showprofile = False
540 self.showprofile = False
466
541
467 def plot(self):
542 def plot(self):
468
543
469 if self.xaxis == "frequency":
544 if self.xaxis == "frequency":
470 x = self.data.xrange[0]
545 x = self.data.xrange[0]
471 self.xlabel = "Frequency (kHz)"
546 self.xlabel = "Frequency (kHz)"
472 elif self.xaxis == "time":
547 elif self.xaxis == "time":
473 x = self.data.xrange[1]
548 x = self.data.xrange[1]
474 self.xlabel = "Time (ms)"
549 self.xlabel = "Time (ms)"
475 else:
550 else:
476 x = self.data.xrange[2]
551 x = self.data.xrange[2]
477 self.xlabel = "Velocity (m/s)"
552 self.xlabel = "Velocity (m/s)"
478
553
479 self.titles = []
554 self.titles = []
480
555
481 y = self.data.heights
556 y = self.data.heights
482 self.y = y
557 self.y = y
483 spc = self.data['spc']
558 spc = self.data['spc']
484 cspc = self.data['cspc']
559 cspc = self.data['cspc']
485
560
486 for n in range(self.nrows):
561 for n in range(self.nrows):
487 noise = self.data['noise'][n][-1]
562 noise = self.data['noise'][n][-1]
488 pair = self.data.pairs[n]
563 pair = self.data.pairs[n]
489 ax = self.axes[4*n]
564 ax = self.axes[4*n]
490 ax3 = self.axes[4*n+3]
565 ax3 = self.axes[4*n+3]
491 if ax.firsttime:
566 if ax.firsttime:
492 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
567 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
493 self.xmin = self.xmin if self.xmin else -self.xmax
568 self.xmin = self.xmin if self.xmin else -self.xmax
494 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
569 self.zmin = self.zmin if self.zmin else numpy.nanmin(spc)
495 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
570 self.zmax = self.zmax if self.zmax else numpy.nanmax(spc)
496 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
571 ax.plt = ax.pcolormesh(x, y, spc[pair[0]].T,
497 vmin=self.zmin,
572 vmin=self.zmin,
498 vmax=self.zmax,
573 vmax=self.zmax,
499 cmap=plt.get_cmap(self.colormap)
574 cmap=plt.get_cmap(self.colormap)
500 )
575 )
501 else:
576 else:
502 ax.plt.set_array(spc[pair[0]].T.ravel())
577 ax.plt.set_array(spc[pair[0]].T.ravel())
503 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
578 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
504
579
505 ax = self.axes[4*n+1]
580 ax = self.axes[4*n+1]
506 if ax.firsttime:
581 if ax.firsttime:
507 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
582 ax.plt = ax.pcolormesh(x, y, spc[pair[1]].T,
508 vmin=self.zmin,
583 vmin=self.zmin,
509 vmax=self.zmax,
584 vmax=self.zmax,
510 cmap=plt.get_cmap(self.colormap)
585 cmap=plt.get_cmap(self.colormap)
511 )
586 )
512 else:
587 else:
513 ax.plt.set_array(spc[pair[1]].T.ravel())
588 ax.plt.set_array(spc[pair[1]].T.ravel())
514 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
589 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
515
590
516 out = cspc[n]/numpy.sqrt(spc[pair[0]]*spc[pair[1]])
591 out = cspc[n]/numpy.sqrt(spc[pair[0]]*spc[pair[1]])
517 coh = numpy.abs(out)
592 coh = numpy.abs(out)
518 phase = numpy.arctan2(out.imag, out.real)*180/numpy.pi
593 phase = numpy.arctan2(out.imag, out.real)*180/numpy.pi
519
594
520 ax = self.axes[4*n+2]
595 ax = self.axes[4*n+2]
521 if ax.firsttime:
596 if ax.firsttime:
522 ax.plt = ax.pcolormesh(x, y, coh.T,
597 ax.plt = ax.pcolormesh(x, y, coh.T,
523 vmin=0,
598 vmin=0,
524 vmax=1,
599 vmax=1,
525 cmap=plt.get_cmap(self.colormap_coh)
600 cmap=plt.get_cmap(self.colormap_coh)
526 )
601 )
527 else:
602 else:
528 ax.plt.set_array(coh.T.ravel())
603 ax.plt.set_array(coh.T.ravel())
529 self.titles.append('Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
604 self.titles.append('Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
530
605
531 ax = self.axes[4*n+3]
606 ax = self.axes[4*n+3]
532 if ax.firsttime:
607 if ax.firsttime:
533 ax.plt = ax.pcolormesh(x, y, phase.T,
608 ax.plt = ax.pcolormesh(x, y, phase.T,
534 vmin=-180,
609 vmin=-180,
535 vmax=180,
610 vmax=180,
536 cmap=plt.get_cmap(self.colormap_phase)
611 cmap=plt.get_cmap(self.colormap_phase)
537 )
612 )
538 else:
613 else:
539 ax.plt.set_array(phase.T.ravel())
614 ax.plt.set_array(phase.T.ravel())
540 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
615 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
541
616
542 self.saveTime = self.max_time
617 self.saveTime = self.max_time
543
618
544
619
545 class PlotSpectraMeanData(PlotSpectraData):
620 class PlotSpectraMeanData(PlotSpectraData):
546 '''
621 '''
547 Plot for Spectra and Mean
622 Plot for Spectra and Mean
548 '''
623 '''
549 CODE = 'spc_mean'
624 CODE = 'spc_mean'
550 colormap = 'jro'
625 colormap = 'jro'
551
626
552
627
553 class PlotRTIData(PlotData):
628 class PlotRTIData(PlotData):
554 '''
629 '''
555 Plot for RTI data
630 Plot for RTI data
556 '''
631 '''
557
632
558 CODE = 'rti'
633 CODE = 'rti'
559 colormap = 'jro'
634 colormap = 'jro'
560
635
561 def setup(self):
636 def setup(self):
562 self.xaxis = 'time'
637 self.xaxis = 'time'
563 self.ncols = 1
638 self.ncols = 1
564 self.nrows = len(self.data.channels)
639 self.nrows = len(self.data.channels)
565 self.nplots = len(self.data.channels)
640 self.nplots = len(self.data.channels)
566 self.ylabel = 'Range [Km]'
641 self.ylabel = 'Range [Km]'
567 self.cb_label = 'dB'
642 self.cb_label = 'dB'
568 self.titles = ['{} Channel {}'.format(self.CODE.upper(), x) for x in range(self.nrows)]
643 self.titles = ['{} Channel {}'.format(self.CODE.upper(), x) for x in range(self.nrows)]
569
644
570 def plot(self):
645 def plot(self):
571 self.x = self.times
646 self.x = self.times
572 self.y = self.data.heights
647 self.y = self.data.heights
573 self.z = self.data[self.CODE]
648 self.z = self.data[self.CODE]
574 self.z = numpy.ma.masked_invalid(self.z)
649 self.z = numpy.ma.masked_invalid(self.z)
575
650
576 for n, ax in enumerate(self.axes):
651 for n, ax in enumerate(self.axes):
577 x, y, z = self.fill_gaps(*self.decimate())
652 x, y, z = self.fill_gaps(*self.decimate())
578 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
653 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
579 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
654 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
580 if ax.firsttime:
655 if ax.firsttime:
581 ax.plt = ax.pcolormesh(x, y, z[n].T,
656 ax.plt = ax.pcolormesh(x, y, z[n].T,
582 vmin=self.zmin,
657 vmin=self.zmin,
583 vmax=self.zmax,
658 vmax=self.zmax,
584 cmap=plt.get_cmap(self.colormap)
659 cmap=plt.get_cmap(self.colormap)
585 )
660 )
586 if self.showprofile:
661 if self.showprofile:
587 ax.plot_profile= self.pf_axes[n].plot(self.data['rti'][n][-1], self.y)[0]
662 ax.plot_profile= self.pf_axes[n].plot(self.data['rti'][n][-1], self.y)[0]
588 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
663 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y,
589 color="k", linestyle="dashed", lw=1)[0]
664 color="k", linestyle="dashed", lw=1)[0]
590 else:
665 else:
591 ax.collections.remove(ax.collections[0])
666 ax.collections.remove(ax.collections[0])
592 ax.plt = ax.pcolormesh(x, y, z[n].T,
667 ax.plt = ax.pcolormesh(x, y, z[n].T,
593 vmin=self.zmin,
668 vmin=self.zmin,
594 vmax=self.zmax,
669 vmax=self.zmax,
595 cmap=plt.get_cmap(self.colormap)
670 cmap=plt.get_cmap(self.colormap)
596 )
671 )
597 if self.showprofile:
672 if self.showprofile:
598 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
673 ax.plot_profile.set_data(self.data['rti'][n][-1], self.y)
599 ax.plot_noise.set_data(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y)
674 ax.plot_noise.set_data(numpy.repeat(self.data['noise'][n][-1], len(self.y)), self.y)
600
675
601 self.saveTime = self.min_time
676 self.saveTime = self.min_time
602
677
603
678
604 class PlotCOHData(PlotRTIData):
679 class PlotCOHData(PlotRTIData):
605 '''
680 '''
606 Plot for Coherence data
681 Plot for Coherence data
607 '''
682 '''
608
683
609 CODE = 'coh'
684 CODE = 'coh'
610
685
611 def setup(self):
686 def setup(self):
612 self.xaxis = 'time'
687 self.xaxis = 'time'
613 self.ncols = 1
688 self.ncols = 1
614 self.nrows = len(self.data.pairs)
689 self.nrows = len(self.data.pairs)
615 self.nplots = len(self.data.pairs)
690 self.nplots = len(self.data.pairs)
616 self.ylabel = 'Range [Km]'
691 self.ylabel = 'Range [Km]'
617 if self.CODE == 'coh':
692 if self.CODE == 'coh':
618 self.cb_label = ''
693 self.cb_label = ''
619 self.titles = ['Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
694 self.titles = ['Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
620 else:
695 else:
621 self.cb_label = 'Degrees'
696 self.cb_label = 'Degrees'
622 self.titles = ['Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
697 self.titles = ['Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
623
698
624
699
625 class PlotPHASEData(PlotCOHData):
700 class PlotPHASEData(PlotCOHData):
626 '''
701 '''
627 Plot for Phase map data
702 Plot for Phase map data
628 '''
703 '''
629
704
630 CODE = 'phase'
705 CODE = 'phase'
631 colormap = 'seismic'
706 colormap = 'seismic'
632
707
633
708
634 class PlotNoiseData(PlotData):
709 class PlotNoiseData(PlotData):
635 '''
710 '''
636 Plot for noise
711 Plot for noise
637 '''
712 '''
638
713
639 CODE = 'noise'
714 CODE = 'noise'
640
715
641 def setup(self):
716 def setup(self):
642 self.xaxis = 'time'
717 self.xaxis = 'time'
643 self.ncols = 1
718 self.ncols = 1
644 self.nrows = 1
719 self.nrows = 1
645 self.nplots = 1
720 self.nplots = 1
646 self.ylabel = 'Intensity [dB]'
721 self.ylabel = 'Intensity [dB]'
647 self.titles = ['Noise']
722 self.titles = ['Noise']
648 self.colorbar = False
723 self.colorbar = False
649
724
650 def plot(self):
725 def plot(self):
651
726
652 x = self.times
727 x = self.times
653 xmin = self.min_time
728 xmin = self.min_time
654 xmax = xmin+self.xrange*60*60
729 xmax = xmin+self.xrange*60*60
655 Y = self.data[self.CODE]
730 Y = self.data[self.CODE]
656
731
657 if self.axes[0].firsttime:
732 if self.axes[0].firsttime:
658 for ch in self.data.channels:
733 for ch in self.data.channels:
659 y = Y[ch]
734 y = Y[ch]
660 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
735 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
661 plt.legend()
736 plt.legend()
662 else:
737 else:
663 for ch in self.data.channels:
738 for ch in self.data.channels:
664 y = Y[ch]
739 y = Y[ch]
665 self.axes[0].lines[ch].set_data(x, y)
740 self.axes[0].lines[ch].set_data(x, y)
666
741
667 self.ymin = numpy.nanmin(Y) - 5
742 self.ymin = numpy.nanmin(Y) - 5
668 self.ymax = numpy.nanmax(Y) + 5
743 self.ymax = numpy.nanmax(Y) + 5
669 self.saveTime = self.min_time
744 self.saveTime = self.min_time
670
745
671
746
672 class PlotSNRData(PlotRTIData):
747 class PlotSNRData(PlotRTIData):
673 '''
748 '''
674 Plot for SNR Data
749 Plot for SNR Data
675 '''
750 '''
676
751
677 CODE = 'snr'
752 CODE = 'snr'
678 colormap = 'jet'
753 colormap = 'jet'
679
754
680
755
681 class PlotDOPData(PlotRTIData):
756 class PlotDOPData(PlotRTIData):
682 '''
757 '''
683 Plot for DOPPLER Data
758 Plot for DOPPLER Data
684 '''
759 '''
685
760
686 CODE = 'dop'
761 CODE = 'dop'
687 colormap = 'jet'
762 colormap = 'jet'
688
763
689
764
690 class PlotSkyMapData(PlotData):
765 class PlotSkyMapData(PlotData):
691 '''
766 '''
692 Plot for meteors detection data
767 Plot for meteors detection data
693 '''
768 '''
694
769
695 CODE = 'met'
770 CODE = 'met'
696
771
697 def setup(self):
772 def setup(self):
698
773
699 self.ncols = 1
774 self.ncols = 1
700 self.nrows = 1
775 self.nrows = 1
701 self.width = 7.2
776 self.width = 7.2
702 self.height = 7.2
777 self.height = 7.2
703
778
704 self.xlabel = 'Zonal Zenith Angle (deg)'
779 self.xlabel = 'Zonal Zenith Angle (deg)'
705 self.ylabel = 'Meridional Zenith Angle (deg)'
780 self.ylabel = 'Meridional Zenith Angle (deg)'
706
781
707 if self.figure is None:
782 if self.figure is None:
708 self.figure = plt.figure(figsize=(self.width, self.height),
783 self.figure = plt.figure(figsize=(self.width, self.height),
709 edgecolor='k',
784 edgecolor='k',
710 facecolor='w')
785 facecolor='w')
711 else:
786 else:
712 self.figure.clf()
787 self.figure.clf()
713
788
714 self.ax = plt.subplot2grid((self.nrows, self.ncols), (0, 0), 1, 1, polar=True)
789 self.ax = plt.subplot2grid((self.nrows, self.ncols), (0, 0), 1, 1, polar=True)
715 self.ax.firsttime = True
790 self.ax.firsttime = True
716
791
717
792
718 def plot(self):
793 def plot(self):
719
794
720 arrayParameters = numpy.concatenate([self.data['param'][t] for t in self.times])
795 arrayParameters = numpy.concatenate([self.data['param'][t] for t in self.times])
721 error = arrayParameters[:,-1]
796 error = arrayParameters[:,-1]
722 indValid = numpy.where(error == 0)[0]
797 indValid = numpy.where(error == 0)[0]
723 finalMeteor = arrayParameters[indValid,:]
798 finalMeteor = arrayParameters[indValid,:]
724 finalAzimuth = finalMeteor[:,3]
799 finalAzimuth = finalMeteor[:,3]
725 finalZenith = finalMeteor[:,4]
800 finalZenith = finalMeteor[:,4]
726
801
727 x = finalAzimuth*numpy.pi/180
802 x = finalAzimuth*numpy.pi/180
728 y = finalZenith
803 y = finalZenith
729
804
730 if self.ax.firsttime:
805 if self.ax.firsttime:
731 self.ax.plot = self.ax.plot(x, y, 'bo', markersize=5)[0]
806 self.ax.plot = self.ax.plot(x, y, 'bo', markersize=5)[0]
732 self.ax.set_ylim(0,90)
807 self.ax.set_ylim(0,90)
733 self.ax.set_yticks(numpy.arange(0,90,20))
808 self.ax.set_yticks(numpy.arange(0,90,20))
734 self.ax.set_xlabel(self.xlabel)
809 self.ax.set_xlabel(self.xlabel)
735 self.ax.set_ylabel(self.ylabel)
810 self.ax.set_ylabel(self.ylabel)
736 self.ax.yaxis.labelpad = 40
811 self.ax.yaxis.labelpad = 40
737 self.ax.firsttime = False
812 self.ax.firsttime = False
738 else:
813 else:
739 self.ax.plot.set_data(x, y)
814 self.ax.plot.set_data(x, y)
740
815
741
816
742 dt1 = datetime.datetime.fromtimestamp(self.min_time).strftime('%y/%m/%d %H:%M:%S')
817 dt1 = datetime.datetime.utcfromtimestamp(self.min_time).strftime('%y/%m/%d %H:%M:%S')
743 dt2 = datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')
818 dt2 = datetime.datetime.utcfromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')
744 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
819 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
745 dt2,
820 dt2,
746 len(x))
821 len(x))
747 self.ax.set_title(title, size=8)
822 self.ax.set_title(title, size=8)
748
823
749 self.saveTime = self.max_time
824 self.saveTime = self.max_time
750
825
751 class PlotParamData(PlotRTIData):
826 class PlotParamData(PlotRTIData):
752 '''
827 '''
753 Plot for data_param object
828 Plot for data_param object
754 '''
829 '''
755
830
756 CODE = 'param'
831 CODE = 'param'
757 colormap = 'seismic'
832 colormap = 'seismic'
758
833
759 def setup(self):
834 def setup(self):
760 self.xaxis = 'time'
835 self.xaxis = 'time'
761 self.ncols = 1
836 self.ncols = 1
762 self.nrows = self.data.shape(self.CODE)[0]
837 self.nrows = self.data.shape(self.CODE)[0]
763 self.nplots = self.nrows
838 self.nplots = self.nrows
764 if self.showSNR:
839 if self.showSNR:
765 self.nrows += 1
840 self.nrows += 1
766 self.nplots += 1
841 self.nplots += 1
767
842
768 self.ylabel = 'Height [Km]'
843 self.ylabel = 'Height [Km]'
769 self.titles = self.data.parameters \
844 self.titles = self.data.parameters \
770 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
845 if self.data.parameters else ['Param {}'.format(x) for x in xrange(self.nrows)]
771 if self.showSNR:
846 if self.showSNR:
772 self.titles.append('SNR')
847 self.titles.append('SNR')
773
848
774 def plot(self):
849 def plot(self):
775 self.data.normalize_heights()
850 self.data.normalize_heights()
776 self.x = self.times
851 self.x = self.times
777 self.y = self.data.heights
852 self.y = self.data.heights
778 if self.showSNR:
853 if self.showSNR:
779 self.z = numpy.concatenate(
854 self.z = numpy.concatenate(
780 (self.data[self.CODE], self.data['snr'])
855 (self.data[self.CODE], self.data['snr'])
781 )
856 )
782 else:
857 else:
783 self.z = self.data[self.CODE]
858 self.z = self.data[self.CODE]
784
859
785 self.z = numpy.ma.masked_invalid(self.z)
860 self.z = numpy.ma.masked_invalid(self.z)
786
861
787 for n, ax in enumerate(self.axes):
862 for n, ax in enumerate(self.axes):
788
863
789 x, y, z = self.fill_gaps(*self.decimate())
864 x, y, z = self.fill_gaps(*self.decimate())
865 self.zmax = self.zmax if self.zmax is not None else numpy.max(self.z[n])
866 self.zmin = self.zmin if self.zmin is not None else numpy.min(self.z[n])
790
867
791 if ax.firsttime:
868 if ax.firsttime:
792 if self.zlimits is not None:
869 if self.zlimits is not None:
793 self.zmin, self.zmax = self.zlimits[n]
870 self.zmin, self.zmax = self.zlimits[n]
794 self.zmax = self.zmax if self.zmax is not None else numpy.nanmax(abs(self.z[:-1, :]))
871
795 self.zmin = self.zmin if self.zmin is not None else -self.zmax
872 ax.plt = ax.pcolormesh(x, y, z[n].T*self.factors[n],
796 ax.plt = ax.pcolormesh(x, y, z[n, :, :].T*self.factors[n],
797 vmin=self.zmin,
873 vmin=self.zmin,
798 vmax=self.zmax,
874 vmax=self.zmax,
799 cmap=self.cmaps[n]
875 cmap=self.cmaps[n]
800 )
876 )
801 else:
877 else:
802 if self.zlimits is not None:
878 if self.zlimits is not None:
803 self.zmin, self.zmax = self.zlimits[n]
879 self.zmin, self.zmax = self.zlimits[n]
804 ax.collections.remove(ax.collections[0])
880 ax.collections.remove(ax.collections[0])
805 ax.plt = ax.pcolormesh(x, y, z[n, :, :].T*self.factors[n],
881 ax.plt = ax.pcolormesh(x, y, z[n].T*self.factors[n],
806 vmin=self.zmin,
882 vmin=self.zmin,
807 vmax=self.zmax,
883 vmax=self.zmax,
808 cmap=self.cmaps[n]
884 cmap=self.cmaps[n]
809 )
885 )
810
886
811 self.saveTime = self.min_time
887 self.saveTime = self.min_time
812
888
813 class PlotOuputData(PlotParamData):
889 class PlotOutputData(PlotParamData):
814 '''
890 '''
815 Plot data_output object
891 Plot data_output object
816 '''
892 '''
817
893
818 CODE = 'output'
894 CODE = 'output'
819 colormap = 'seismic'
895 colormap = 'seismic'
@@ -1,607 +1,607
1 '''
1 '''
2 @author: Juan C. Espinoza
2 @author: Juan C. Espinoza
3 '''
3 '''
4
4
5 import time
5 import time
6 import json
6 import json
7 import numpy
7 import numpy
8 import paho.mqtt.client as mqtt
8 import paho.mqtt.client as mqtt
9 import zmq
9 import zmq
10 import datetime
10 import datetime
11 from zmq.utils.monitor import recv_monitor_message
11 from zmq.utils.monitor import recv_monitor_message
12 from functools import wraps
12 from functools import wraps
13 from threading import Thread
13 from threading import Thread
14 from multiprocessing import Process
14 from multiprocessing import Process
15
15
16 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit
16 from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit
17 from schainpy.model.data.jrodata import JROData
17 from schainpy.model.data.jrodata import JROData
18 from schainpy.utils import log
18 from schainpy.utils import log
19
19
20 MAXNUMX = 100
20 MAXNUMX = 100
21 MAXNUMY = 100
21 MAXNUMY = 100
22
22
23 class PrettyFloat(float):
23 class PrettyFloat(float):
24 def __repr__(self):
24 def __repr__(self):
25 return '%.2f' % self
25 return '%.2f' % self
26
26
27 def roundFloats(obj):
27 def roundFloats(obj):
28 if isinstance(obj, list):
28 if isinstance(obj, list):
29 return map(roundFloats, obj)
29 return map(roundFloats, obj)
30 elif isinstance(obj, float):
30 elif isinstance(obj, float):
31 return round(obj, 2)
31 return round(obj, 2)
32
32
33 def decimate(z, MAXNUMY):
33 def decimate(z, MAXNUMY):
34 dy = int(len(z[0])/MAXNUMY) + 1
34 dy = int(len(z[0])/MAXNUMY) + 1
35
35
36 return z[::, ::dy]
36 return z[::, ::dy]
37
37
38 class throttle(object):
38 class throttle(object):
39 '''
39 '''
40 Decorator that prevents a function from being called more than once every
40 Decorator that prevents a function from being called more than once every
41 time period.
41 time period.
42 To create a function that cannot be called more than once a minute, but
42 To create a function that cannot be called more than once a minute, but
43 will sleep until it can be called:
43 will sleep until it can be called:
44 @throttle(minutes=1)
44 @throttle(minutes=1)
45 def foo():
45 def foo():
46 pass
46 pass
47
47
48 for i in range(10):
48 for i in range(10):
49 foo()
49 foo()
50 print "This function has run %s times." % i
50 print "This function has run %s times." % i
51 '''
51 '''
52
52
53 def __init__(self, seconds=0, minutes=0, hours=0):
53 def __init__(self, seconds=0, minutes=0, hours=0):
54 self.throttle_period = datetime.timedelta(
54 self.throttle_period = datetime.timedelta(
55 seconds=seconds, minutes=minutes, hours=hours
55 seconds=seconds, minutes=minutes, hours=hours
56 )
56 )
57
57
58 self.time_of_last_call = datetime.datetime.min
58 self.time_of_last_call = datetime.datetime.min
59
59
60 def __call__(self, fn):
60 def __call__(self, fn):
61 @wraps(fn)
61 @wraps(fn)
62 def wrapper(*args, **kwargs):
62 def wrapper(*args, **kwargs):
63 now = datetime.datetime.now()
63 now = datetime.datetime.now()
64 time_since_last_call = now - self.time_of_last_call
64 time_since_last_call = now - self.time_of_last_call
65 time_left = self.throttle_period - time_since_last_call
65 time_left = self.throttle_period - time_since_last_call
66
66
67 if time_left > datetime.timedelta(seconds=0):
67 if time_left > datetime.timedelta(seconds=0):
68 return
68 return
69
69
70 self.time_of_last_call = datetime.datetime.now()
70 self.time_of_last_call = datetime.datetime.now()
71 return fn(*args, **kwargs)
71 return fn(*args, **kwargs)
72
72
73 return wrapper
73 return wrapper
74
74
75 class Data(object):
75 class Data(object):
76 '''
76 '''
77 Object to hold data to be plotted
77 Object to hold data to be plotted
78 '''
78 '''
79
79
80 def __init__(self, plottypes, throttle_value):
80 def __init__(self, plottypes, throttle_value):
81 self.plottypes = plottypes
81 self.plottypes = plottypes
82 self.throttle = throttle_value
82 self.throttle = throttle_value
83 self.ended = False
83 self.ended = False
84 self.__times = []
84 self.__times = []
85
85
86 def __str__(self):
86 def __str__(self):
87 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
87 dum = ['{}{}'.format(key, self.shape(key)) for key in self.data]
88 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
88 return 'Data[{}][{}]'.format(';'.join(dum), len(self.__times))
89
89
90 def __len__(self):
90 def __len__(self):
91 return len(self.__times)
91 return len(self.__times)
92
92
93 def __getitem__(self, key):
93 def __getitem__(self, key):
94 if key not in self.data:
94 if key not in self.data:
95 raise KeyError(log.error('Missing key: {}'.format(key)))
95 raise KeyError(log.error('Missing key: {}'.format(key)))
96
96
97 if 'spc' in key:
97 if 'spc' in key:
98 ret = self.data[key]
98 ret = self.data[key]
99 else:
99 else:
100 ret = numpy.array([self.data[key][x] for x in self.times])
100 ret = numpy.array([self.data[key][x] for x in self.times])
101 if ret.ndim > 1:
101 if ret.ndim > 1:
102 ret = numpy.swapaxes(ret, 0, 1)
102 ret = numpy.swapaxes(ret, 0, 1)
103 return ret
103 return ret
104
104
105 def setup(self):
105 def setup(self):
106 '''
106 '''
107 Configure object
107 Configure object
108 '''
108 '''
109
109
110 self.ended = False
110 self.ended = False
111 self.data = {}
111 self.data = {}
112 self.__times = []
112 self.__times = []
113 self.__heights = []
113 self.__heights = []
114 self.__all_heights = set()
114 self.__all_heights = set()
115 for plot in self.plottypes:
115 for plot in self.plottypes:
116 if 'snr' in plot:
116 if 'snr' in plot:
117 plot = 'snr'
117 plot = 'snr'
118 self.data[plot] = {}
118 self.data[plot] = {}
119
119
120 def shape(self, key):
120 def shape(self, key):
121 '''
121 '''
122 Get the shape of the one-element data for the given key
122 Get the shape of the one-element data for the given key
123 '''
123 '''
124
124
125 if len(self.data[key]):
125 if len(self.data[key]):
126 if 'spc' in key:
126 if 'spc' in key:
127 return self.data[key].shape
127 return self.data[key].shape
128 return self.data[key][self.__times[0]].shape
128 return self.data[key][self.__times[0]].shape
129 return (0,)
129 return (0,)
130
130
131 def update(self, dataOut):
131 def update(self, dataOut):
132 '''
132 '''
133 Update data object with new dataOut
133 Update data object with new dataOut
134 '''
134 '''
135
135
136 tm = dataOut.utctime
136 tm = dataOut.utctime
137 if tm in self.__times:
137 if tm in self.__times:
138 return
138 return
139
139
140 self.parameters = getattr(dataOut, 'parameters', [])
140 self.parameters = getattr(dataOut, 'parameters', [])
141 self.pairs = dataOut.pairsList
141 self.pairs = dataOut.pairsList
142 self.channels = dataOut.channelList
142 self.channels = dataOut.channelList
143 self.interval = dataOut.getTimeInterval()
143 self.interval = dataOut.getTimeInterval()
144 if 'spc' in self.plottypes or 'cspc' in self.plottypes:
144 if 'spc' in self.plottypes or 'cspc' in self.plottypes:
145 self.xrange = (dataOut.getFreqRange(1)/1000. , dataOut.getAcfRange(1) , dataOut.getVelRange(1))
145 self.xrange = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
146 self.__heights.append(dataOut.heightList)
146 self.__heights.append(dataOut.heightList)
147 self.__all_heights.update(dataOut.heightList)
147 self.__all_heights.update(dataOut.heightList)
148 self.__times.append(tm)
148 self.__times.append(tm)
149
149
150 for plot in self.plottypes:
150 for plot in self.plottypes:
151 if plot == 'spc':
151 if plot == 'spc':
152 z = dataOut.data_spc/dataOut.normFactor
152 z = dataOut.data_spc/dataOut.normFactor
153 self.data[plot] = 10*numpy.log10(z)
153 self.data[plot] = 10*numpy.log10(z)
154 if plot == 'cspc':
154 if plot == 'cspc':
155 self.data[plot] = dataOut.data_cspc
155 self.data[plot] = dataOut.data_cspc
156 if plot == 'noise':
156 if plot == 'noise':
157 self.data[plot][tm] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
157 self.data[plot][tm] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
158 if plot == 'rti':
158 if plot == 'rti':
159 self.data[plot][tm] = dataOut.getPower()
159 self.data[plot][tm] = dataOut.getPower()
160 if plot == 'snr_db':
160 if plot == 'snr_db':
161 self.data['snr'][tm] = dataOut.data_SNR
161 self.data['snr'][tm] = dataOut.data_SNR
162 if plot == 'snr':
162 if plot == 'snr':
163 self.data[plot][tm] = 10*numpy.log10(dataOut.data_SNR)
163 self.data[plot][tm] = 10*numpy.log10(dataOut.data_SNR)
164 if plot == 'dop':
164 if plot == 'dop':
165 self.data[plot][tm] = 10*numpy.log10(dataOut.data_DOP)
165 self.data[plot][tm] = 10*numpy.log10(dataOut.data_DOP)
166 if plot == 'mean':
166 if plot == 'mean':
167 self.data[plot][tm] = dataOut.data_MEAN
167 self.data[plot][tm] = dataOut.data_MEAN
168 if plot == 'std':
168 if plot == 'std':
169 self.data[plot][tm] = dataOut.data_STD
169 self.data[plot][tm] = dataOut.data_STD
170 if plot == 'coh':
170 if plot == 'coh':
171 self.data[plot][tm] = dataOut.getCoherence()
171 self.data[plot][tm] = dataOut.getCoherence()
172 if plot == 'phase':
172 if plot == 'phase':
173 self.data[plot][tm] = dataOut.getCoherence(phase=True)
173 self.data[plot][tm] = dataOut.getCoherence(phase=True)
174 if plot == 'output':
174 if plot == 'output':
175 self.data[plot][tm] = dataOut.data_output
175 self.data[plot][tm] = dataOut.data_output
176 if plot == 'param':
176 if plot == 'param':
177 self.data[plot][tm] = dataOut.data_param
177 self.data[plot][tm] = dataOut.data_param
178
178
179 def normalize_heights(self):
179 def normalize_heights(self):
180 '''
180 '''
181 Ensure same-dimension of the data for different heighList
181 Ensure same-dimension of the data for different heighList
182 '''
182 '''
183
183
184 H = numpy.array(list(self.__all_heights))
184 H = numpy.array(list(self.__all_heights))
185 H.sort()
185 H.sort()
186 for key in self.data:
186 for key in self.data:
187 shape = self.shape(key)[:-1] + H.shape
187 shape = self.shape(key)[:-1] + H.shape
188 for tm, obj in self.data[key].items():
188 for tm, obj in self.data[key].items():
189 h = self.__heights[self.__times.index(tm)]
189 h = self.__heights[self.__times.index(tm)]
190 if H.size == h.size:
190 if H.size == h.size:
191 continue
191 continue
192 index = numpy.where(numpy.in1d(H, h))[0]
192 index = numpy.where(numpy.in1d(H, h))[0]
193 dummy = numpy.zeros(shape) + numpy.nan
193 dummy = numpy.zeros(shape) + numpy.nan
194 if len(shape) == 2:
194 if len(shape) == 2:
195 dummy[:, index] = obj
195 dummy[:, index] = obj
196 else:
196 else:
197 dummy[index] = obj
197 dummy[index] = obj
198 self.data[key][tm] = dummy
198 self.data[key][tm] = dummy
199
199
200 self.__heights = [H for tm in self.__times]
200 self.__heights = [H for tm in self.__times]
201
201
202 def jsonify(self, decimate=False):
202 def jsonify(self, decimate=False):
203 '''
203 '''
204 Convert data to json
204 Convert data to json
205 '''
205 '''
206
206
207 ret = {}
207 ret = {}
208 tm = self.times[-1]
208 tm = self.times[-1]
209
209
210 for key, value in self.data:
210 for key, value in self.data:
211 if key in ('spc', 'cspc'):
211 if key in ('spc', 'cspc'):
212 ret[key] = roundFloats(self.data[key].to_list())
212 ret[key] = roundFloats(self.data[key].to_list())
213 else:
213 else:
214 ret[key] = roundFloats(self.data[key][tm].to_list())
214 ret[key] = roundFloats(self.data[key][tm].to_list())
215
215
216 ret['timestamp'] = tm
216 ret['timestamp'] = tm
217 ret['interval'] = self.interval
217 ret['interval'] = self.interval
218
218
219 @property
219 @property
220 def times(self):
220 def times(self):
221 '''
221 '''
222 Return the list of times of the current data
222 Return the list of times of the current data
223 '''
223 '''
224
224
225 ret = numpy.array(self.__times)
225 ret = numpy.array(self.__times)
226 ret.sort()
226 ret.sort()
227 return ret
227 return ret
228
228
229 @property
229 @property
230 def heights(self):
230 def heights(self):
231 '''
231 '''
232 Return the list of heights of the current data
232 Return the list of heights of the current data
233 '''
233 '''
234
234
235 return numpy.array(self.__heights[-1])
235 return numpy.array(self.__heights[-1])
236
236
237 class PublishData(Operation):
237 class PublishData(Operation):
238 '''
238 '''
239 Operation to send data over zmq.
239 Operation to send data over zmq.
240 '''
240 '''
241
241
242 def __init__(self, **kwargs):
242 def __init__(self, **kwargs):
243 """Inicio."""
243 """Inicio."""
244 Operation.__init__(self, **kwargs)
244 Operation.__init__(self, **kwargs)
245 self.isConfig = False
245 self.isConfig = False
246 self.client = None
246 self.client = None
247 self.zeromq = None
247 self.zeromq = None
248 self.mqtt = None
248 self.mqtt = None
249
249
250 def on_disconnect(self, client, userdata, rc):
250 def on_disconnect(self, client, userdata, rc):
251 if rc != 0:
251 if rc != 0:
252 log.warning('Unexpected disconnection.')
252 log.warning('Unexpected disconnection.')
253 self.connect()
253 self.connect()
254
254
255 def connect(self):
255 def connect(self):
256 log.warning('trying to connect')
256 log.warning('trying to connect')
257 try:
257 try:
258 self.client.connect(
258 self.client.connect(
259 host=self.host,
259 host=self.host,
260 port=self.port,
260 port=self.port,
261 keepalive=60*10,
261 keepalive=60*10,
262 bind_address='')
262 bind_address='')
263 self.client.loop_start()
263 self.client.loop_start()
264 # self.client.publish(
264 # self.client.publish(
265 # self.topic + 'SETUP',
265 # self.topic + 'SETUP',
266 # json.dumps(setup),
266 # json.dumps(setup),
267 # retain=True
267 # retain=True
268 # )
268 # )
269 except:
269 except:
270 log.error('MQTT Conection error.')
270 log.error('MQTT Conection error.')
271 self.client = False
271 self.client = False
272
272
273 def setup(self, port=1883, username=None, password=None, clientId="user", zeromq=1, verbose=True, **kwargs):
273 def setup(self, port=1883, username=None, password=None, clientId="user", zeromq=1, verbose=True, **kwargs):
274 self.counter = 0
274 self.counter = 0
275 self.topic = kwargs.get('topic', 'schain')
275 self.topic = kwargs.get('topic', 'schain')
276 self.delay = kwargs.get('delay', 0)
276 self.delay = kwargs.get('delay', 0)
277 self.plottype = kwargs.get('plottype', 'spectra')
277 self.plottype = kwargs.get('plottype', 'spectra')
278 self.host = kwargs.get('host', "10.10.10.82")
278 self.host = kwargs.get('host', "10.10.10.82")
279 self.port = kwargs.get('port', 3000)
279 self.port = kwargs.get('port', 3000)
280 self.clientId = clientId
280 self.clientId = clientId
281 self.cnt = 0
281 self.cnt = 0
282 self.zeromq = zeromq
282 self.zeromq = zeromq
283 self.mqtt = kwargs.get('plottype', 0)
283 self.mqtt = kwargs.get('plottype', 0)
284 self.client = None
284 self.client = None
285 self.verbose = verbose
285 self.verbose = verbose
286 setup = []
286 setup = []
287 if mqtt is 1:
287 if mqtt is 1:
288 self.client = mqtt.Client(
288 self.client = mqtt.Client(
289 client_id=self.clientId + self.topic + 'SCHAIN',
289 client_id=self.clientId + self.topic + 'SCHAIN',
290 clean_session=True)
290 clean_session=True)
291 self.client.on_disconnect = self.on_disconnect
291 self.client.on_disconnect = self.on_disconnect
292 self.connect()
292 self.connect()
293 for plot in self.plottype:
293 for plot in self.plottype:
294 setup.append({
294 setup.append({
295 'plot': plot,
295 'plot': plot,
296 'topic': self.topic + plot,
296 'topic': self.topic + plot,
297 'title': getattr(self, plot + '_' + 'title', False),
297 'title': getattr(self, plot + '_' + 'title', False),
298 'xlabel': getattr(self, plot + '_' + 'xlabel', False),
298 'xlabel': getattr(self, plot + '_' + 'xlabel', False),
299 'ylabel': getattr(self, plot + '_' + 'ylabel', False),
299 'ylabel': getattr(self, plot + '_' + 'ylabel', False),
300 'xrange': getattr(self, plot + '_' + 'xrange', False),
300 'xrange': getattr(self, plot + '_' + 'xrange', False),
301 'yrange': getattr(self, plot + '_' + 'yrange', False),
301 'yrange': getattr(self, plot + '_' + 'yrange', False),
302 'zrange': getattr(self, plot + '_' + 'zrange', False),
302 'zrange': getattr(self, plot + '_' + 'zrange', False),
303 })
303 })
304 if zeromq is 1:
304 if zeromq is 1:
305 context = zmq.Context()
305 context = zmq.Context()
306 self.zmq_socket = context.socket(zmq.PUSH)
306 self.zmq_socket = context.socket(zmq.PUSH)
307 server = kwargs.get('server', 'zmq.pipe')
307 server = kwargs.get('server', 'zmq.pipe')
308
308
309 if 'tcp://' in server:
309 if 'tcp://' in server:
310 address = server
310 address = server
311 else:
311 else:
312 address = 'ipc:///tmp/%s' % server
312 address = 'ipc:///tmp/%s' % server
313
313
314 self.zmq_socket.connect(address)
314 self.zmq_socket.connect(address)
315 time.sleep(1)
315 time.sleep(1)
316
316
317
317
318 def publish_data(self):
318 def publish_data(self):
319 self.dataOut.finished = False
319 self.dataOut.finished = False
320 if self.mqtt is 1:
320 if self.mqtt is 1:
321 yData = self.dataOut.heightList[:2].tolist()
321 yData = self.dataOut.heightList[:2].tolist()
322 if self.plottype == 'spectra':
322 if self.plottype == 'spectra':
323 data = getattr(self.dataOut, 'data_spc')
323 data = getattr(self.dataOut, 'data_spc')
324 z = data/self.dataOut.normFactor
324 z = data/self.dataOut.normFactor
325 zdB = 10*numpy.log10(z)
325 zdB = 10*numpy.log10(z)
326 xlen, ylen = zdB[0].shape
326 xlen, ylen = zdB[0].shape
327 dx = int(xlen/MAXNUMX) + 1
327 dx = int(xlen/MAXNUMX) + 1
328 dy = int(ylen/MAXNUMY) + 1
328 dy = int(ylen/MAXNUMY) + 1
329 Z = [0 for i in self.dataOut.channelList]
329 Z = [0 for i in self.dataOut.channelList]
330 for i in self.dataOut.channelList:
330 for i in self.dataOut.channelList:
331 Z[i] = zdB[i][::dx, ::dy].tolist()
331 Z[i] = zdB[i][::dx, ::dy].tolist()
332 payload = {
332 payload = {
333 'timestamp': self.dataOut.utctime,
333 'timestamp': self.dataOut.utctime,
334 'data': roundFloats(Z),
334 'data': roundFloats(Z),
335 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
335 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
336 'interval': self.dataOut.getTimeInterval(),
336 'interval': self.dataOut.getTimeInterval(),
337 'type': self.plottype,
337 'type': self.plottype,
338 'yData': yData
338 'yData': yData
339 }
339 }
340
340
341 elif self.plottype in ('rti', 'power'):
341 elif self.plottype in ('rti', 'power'):
342 data = getattr(self.dataOut, 'data_spc')
342 data = getattr(self.dataOut, 'data_spc')
343 z = data/self.dataOut.normFactor
343 z = data/self.dataOut.normFactor
344 avg = numpy.average(z, axis=1)
344 avg = numpy.average(z, axis=1)
345 avgdB = 10*numpy.log10(avg)
345 avgdB = 10*numpy.log10(avg)
346 xlen, ylen = z[0].shape
346 xlen, ylen = z[0].shape
347 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
347 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
348 AVG = [0 for i in self.dataOut.channelList]
348 AVG = [0 for i in self.dataOut.channelList]
349 for i in self.dataOut.channelList:
349 for i in self.dataOut.channelList:
350 AVG[i] = avgdB[i][::dy].tolist()
350 AVG[i] = avgdB[i][::dy].tolist()
351 payload = {
351 payload = {
352 'timestamp': self.dataOut.utctime,
352 'timestamp': self.dataOut.utctime,
353 'data': roundFloats(AVG),
353 'data': roundFloats(AVG),
354 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
354 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
355 'interval': self.dataOut.getTimeInterval(),
355 'interval': self.dataOut.getTimeInterval(),
356 'type': self.plottype,
356 'type': self.plottype,
357 'yData': yData
357 'yData': yData
358 }
358 }
359 elif self.plottype == 'noise':
359 elif self.plottype == 'noise':
360 noise = self.dataOut.getNoise()/self.dataOut.normFactor
360 noise = self.dataOut.getNoise()/self.dataOut.normFactor
361 noisedB = 10*numpy.log10(noise)
361 noisedB = 10*numpy.log10(noise)
362 payload = {
362 payload = {
363 'timestamp': self.dataOut.utctime,
363 'timestamp': self.dataOut.utctime,
364 'data': roundFloats(noisedB.reshape(-1, 1).tolist()),
364 'data': roundFloats(noisedB.reshape(-1, 1).tolist()),
365 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
365 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
366 'interval': self.dataOut.getTimeInterval(),
366 'interval': self.dataOut.getTimeInterval(),
367 'type': self.plottype,
367 'type': self.plottype,
368 'yData': yData
368 'yData': yData
369 }
369 }
370 elif self.plottype == 'snr':
370 elif self.plottype == 'snr':
371 data = getattr(self.dataOut, 'data_SNR')
371 data = getattr(self.dataOut, 'data_SNR')
372 avgdB = 10*numpy.log10(data)
372 avgdB = 10*numpy.log10(data)
373
373
374 ylen = data[0].size
374 ylen = data[0].size
375 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
375 dy = numpy.floor(ylen/self.__MAXNUMY) + 1
376 AVG = [0 for i in self.dataOut.channelList]
376 AVG = [0 for i in self.dataOut.channelList]
377 for i in self.dataOut.channelList:
377 for i in self.dataOut.channelList:
378 AVG[i] = avgdB[i][::dy].tolist()
378 AVG[i] = avgdB[i][::dy].tolist()
379 payload = {
379 payload = {
380 'timestamp': self.dataOut.utctime,
380 'timestamp': self.dataOut.utctime,
381 'data': roundFloats(AVG),
381 'data': roundFloats(AVG),
382 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
382 'channels': ['Ch %s' % ch for ch in self.dataOut.channelList],
383 'type': self.plottype,
383 'type': self.plottype,
384 'yData': yData
384 'yData': yData
385 }
385 }
386 else:
386 else:
387 print "Tipo de grafico invalido"
387 print "Tipo de grafico invalido"
388 payload = {
388 payload = {
389 'data': 'None',
389 'data': 'None',
390 'timestamp': 'None',
390 'timestamp': 'None',
391 'type': None
391 'type': None
392 }
392 }
393
393
394 self.client.publish(self.topic + self.plottype, json.dumps(payload), qos=0)
394 self.client.publish(self.topic + self.plottype, json.dumps(payload), qos=0)
395
395
396 if self.zeromq is 1:
396 if self.zeromq is 1:
397 if self.verbose:
397 if self.verbose:
398 log.log(
398 log.log(
399 '{} - {}'.format(self.dataOut.type, self.dataOut.datatime),
399 '{} - {}'.format(self.dataOut.type, self.dataOut.datatime),
400 'Sending'
400 'Sending'
401 )
401 )
402 self.zmq_socket.send_pyobj(self.dataOut)
402 self.zmq_socket.send_pyobj(self.dataOut)
403
403
404 def run(self, dataOut, **kwargs):
404 def run(self, dataOut, **kwargs):
405 self.dataOut = dataOut
405 self.dataOut = dataOut
406 if not self.isConfig:
406 if not self.isConfig:
407 self.setup(**kwargs)
407 self.setup(**kwargs)
408 self.isConfig = True
408 self.isConfig = True
409
409
410 self.publish_data()
410 self.publish_data()
411 time.sleep(self.delay)
411 time.sleep(self.delay)
412
412
413 def close(self):
413 def close(self):
414 if self.zeromq is 1:
414 if self.zeromq is 1:
415 self.dataOut.finished = True
415 self.dataOut.finished = True
416 self.zmq_socket.send_pyobj(self.dataOut)
416 self.zmq_socket.send_pyobj(self.dataOut)
417 time.sleep(0.1)
417 time.sleep(0.1)
418 self.zmq_socket.close()
418 self.zmq_socket.close()
419 if self.client:
419 if self.client:
420 self.client.loop_stop()
420 self.client.loop_stop()
421 self.client.disconnect()
421 self.client.disconnect()
422
422
423
423
424 class ReceiverData(ProcessingUnit):
424 class ReceiverData(ProcessingUnit):
425
425
426 def __init__(self, **kwargs):
426 def __init__(self, **kwargs):
427
427
428 ProcessingUnit.__init__(self, **kwargs)
428 ProcessingUnit.__init__(self, **kwargs)
429
429
430 self.isConfig = False
430 self.isConfig = False
431 server = kwargs.get('server', 'zmq.pipe')
431 server = kwargs.get('server', 'zmq.pipe')
432 if 'tcp://' in server:
432 if 'tcp://' in server:
433 address = server
433 address = server
434 else:
434 else:
435 address = 'ipc:///tmp/%s' % server
435 address = 'ipc:///tmp/%s' % server
436
436
437 self.address = address
437 self.address = address
438 self.dataOut = JROData()
438 self.dataOut = JROData()
439
439
440 def setup(self):
440 def setup(self):
441
441
442 self.context = zmq.Context()
442 self.context = zmq.Context()
443 self.receiver = self.context.socket(zmq.PULL)
443 self.receiver = self.context.socket(zmq.PULL)
444 self.receiver.bind(self.address)
444 self.receiver.bind(self.address)
445 time.sleep(0.5)
445 time.sleep(0.5)
446 log.success('ReceiverData from {}'.format(self.address))
446 log.success('ReceiverData from {}'.format(self.address))
447
447
448
448
449 def run(self):
449 def run(self):
450
450
451 if not self.isConfig:
451 if not self.isConfig:
452 self.setup()
452 self.setup()
453 self.isConfig = True
453 self.isConfig = True
454
454
455 self.dataOut = self.receiver.recv_pyobj()
455 self.dataOut = self.receiver.recv_pyobj()
456 log.log('{} - {}'.format(self.dataOut.type,
456 log.log('{} - {}'.format(self.dataOut.type,
457 self.dataOut.datatime.ctime(),),
457 self.dataOut.datatime.ctime(),),
458 'Receiving')
458 'Receiving')
459
459
460
460
461 class PlotterReceiver(ProcessingUnit, Process):
461 class PlotterReceiver(ProcessingUnit, Process):
462
462
463 throttle_value = 5
463 throttle_value = 5
464
464
465 def __init__(self, **kwargs):
465 def __init__(self, **kwargs):
466
466
467 ProcessingUnit.__init__(self, **kwargs)
467 ProcessingUnit.__init__(self, **kwargs)
468 Process.__init__(self)
468 Process.__init__(self)
469 self.mp = False
469 self.mp = False
470 self.isConfig = False
470 self.isConfig = False
471 self.isWebConfig = False
471 self.isWebConfig = False
472 self.connections = 0
472 self.connections = 0
473 server = kwargs.get('server', 'zmq.pipe')
473 server = kwargs.get('server', 'zmq.pipe')
474 plot_server = kwargs.get('plot_server', 'zmq.web')
474 plot_server = kwargs.get('plot_server', 'zmq.web')
475 if 'tcp://' in server:
475 if 'tcp://' in server:
476 address = server
476 address = server
477 else:
477 else:
478 address = 'ipc:///tmp/%s' % server
478 address = 'ipc:///tmp/%s' % server
479
479
480 if 'tcp://' in plot_server:
480 if 'tcp://' in plot_server:
481 plot_address = plot_server
481 plot_address = plot_server
482 else:
482 else:
483 plot_address = 'ipc:///tmp/%s' % plot_server
483 plot_address = 'ipc:///tmp/%s' % plot_server
484
484
485 self.address = address
485 self.address = address
486 self.plot_address = plot_address
486 self.plot_address = plot_address
487 self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')]
487 self.plottypes = [s.strip() for s in kwargs.get('plottypes', 'rti').split(',')]
488 self.realtime = kwargs.get('realtime', False)
488 self.realtime = kwargs.get('realtime', False)
489 self.throttle_value = kwargs.get('throttle', 5)
489 self.throttle_value = kwargs.get('throttle', 5)
490 self.sendData = self.initThrottle(self.throttle_value)
490 self.sendData = self.initThrottle(self.throttle_value)
491 self.dates = []
491 self.dates = []
492 self.setup()
492 self.setup()
493
493
494 def setup(self):
494 def setup(self):
495
495
496 self.data = Data(self.plottypes, self.throttle_value)
496 self.data = Data(self.plottypes, self.throttle_value)
497 self.isConfig = True
497 self.isConfig = True
498
498
499 def event_monitor(self, monitor):
499 def event_monitor(self, monitor):
500
500
501 events = {}
501 events = {}
502
502
503 for name in dir(zmq):
503 for name in dir(zmq):
504 if name.startswith('EVENT_'):
504 if name.startswith('EVENT_'):
505 value = getattr(zmq, name)
505 value = getattr(zmq, name)
506 events[value] = name
506 events[value] = name
507
507
508 while monitor.poll():
508 while monitor.poll():
509 evt = recv_monitor_message(monitor)
509 evt = recv_monitor_message(monitor)
510 if evt['event'] == 32:
510 if evt['event'] == 32:
511 self.connections += 1
511 self.connections += 1
512 if evt['event'] == 512:
512 if evt['event'] == 512:
513 pass
513 pass
514
514
515 evt.update({'description': events[evt['event']]})
515 evt.update({'description': events[evt['event']]})
516
516
517 if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
517 if evt['event'] == zmq.EVENT_MONITOR_STOPPED:
518 break
518 break
519 monitor.close()
519 monitor.close()
520 print('event monitor thread done!')
520 print('event monitor thread done!')
521
521
522 def initThrottle(self, throttle_value):
522 def initThrottle(self, throttle_value):
523
523
524 @throttle(seconds=throttle_value)
524 @throttle(seconds=throttle_value)
525 def sendDataThrottled(fn_sender, data):
525 def sendDataThrottled(fn_sender, data):
526 fn_sender(data)
526 fn_sender(data)
527
527
528 return sendDataThrottled
528 return sendDataThrottled
529
529
530 def send(self, data):
530 def send(self, data):
531 log.success('Sending {}'.format(data), self.name)
531 log.success('Sending {}'.format(data), self.name)
532 self.sender.send_pyobj(data)
532 self.sender.send_pyobj(data)
533
533
534 def run(self):
534 def run(self):
535
535
536 log.success(
536 log.success(
537 'Starting from {}'.format(self.address),
537 'Starting from {}'.format(self.address),
538 self.name
538 self.name
539 )
539 )
540
540
541 self.context = zmq.Context()
541 self.context = zmq.Context()
542 self.receiver = self.context.socket(zmq.PULL)
542 self.receiver = self.context.socket(zmq.PULL)
543 self.receiver.bind(self.address)
543 self.receiver.bind(self.address)
544 monitor = self.receiver.get_monitor_socket()
544 monitor = self.receiver.get_monitor_socket()
545 self.sender = self.context.socket(zmq.PUB)
545 self.sender = self.context.socket(zmq.PUB)
546 if self.realtime:
546 if self.realtime:
547 self.sender_web = self.context.socket(zmq.PUB)
547 self.sender_web = self.context.socket(zmq.PUB)
548 self.sender_web.connect(self.plot_address)
548 self.sender_web.connect(self.plot_address)
549 time.sleep(1)
549 time.sleep(1)
550
550
551 if 'server' in self.kwargs:
551 if 'server' in self.kwargs:
552 self.sender.bind("ipc:///tmp/{}.plots".format(self.kwargs['server']))
552 self.sender.bind("ipc:///tmp/{}.plots".format(self.kwargs['server']))
553 else:
553 else:
554 self.sender.bind("ipc:///tmp/zmq.plots")
554 self.sender.bind("ipc:///tmp/zmq.plots")
555
555
556 time.sleep(2)
556 time.sleep(2)
557
557
558 t = Thread(target=self.event_monitor, args=(monitor,))
558 t = Thread(target=self.event_monitor, args=(monitor,))
559 t.start()
559 t.start()
560
560
561 while True:
561 while True:
562 dataOut = self.receiver.recv_pyobj()
562 dataOut = self.receiver.recv_pyobj()
563 dt = datetime.datetime.fromtimestamp(dataOut.utctime).date()
563 dt = datetime.datetime.utcfromtimestamp(dataOut.utctime).date()
564 sended = False
564 sended = False
565 if dt not in self.dates:
565 if dt not in self.dates:
566 if self.data:
566 if self.data:
567 self.data.ended = True
567 self.data.ended = True
568 self.send(self.data)
568 self.send(self.data)
569 sended = True
569 sended = True
570 self.data.setup()
570 self.data.setup()
571 self.dates.append(dt)
571 self.dates.append(dt)
572
572
573 self.data.update(dataOut)
573 self.data.update(dataOut)
574
574
575 if dataOut.finished is True:
575 if dataOut.finished is True:
576 self.connections -= 1
576 self.connections -= 1
577 if self.connections == 0 and dt in self.dates:
577 if self.connections == 0 and dt in self.dates:
578 self.data.ended = True
578 self.data.ended = True
579 self.send(self.data)
579 self.send(self.data)
580 self.data.setup()
580 self.data.setup()
581 else:
581 else:
582 if self.realtime:
582 if self.realtime:
583 self.send(self.data)
583 self.send(self.data)
584 # self.sender_web.send_string(self.data.jsonify())
584 # self.sender_web.send_string(self.data.jsonify())
585 else:
585 else:
586 if not sended:
586 if not sended:
587 self.sendData(self.send, self.data)
587 self.sendData(self.send, self.data)
588
588
589 return
589 return
590
590
591 def sendToWeb(self):
591 def sendToWeb(self):
592
592
593 if not self.isWebConfig:
593 if not self.isWebConfig:
594 context = zmq.Context()
594 context = zmq.Context()
595 sender_web_config = context.socket(zmq.PUB)
595 sender_web_config = context.socket(zmq.PUB)
596 if 'tcp://' in self.plot_address:
596 if 'tcp://' in self.plot_address:
597 dum, address, port = self.plot_address.split(':')
597 dum, address, port = self.plot_address.split(':')
598 conf_address = '{}:{}:{}'.format(dum, address, int(port)+1)
598 conf_address = '{}:{}:{}'.format(dum, address, int(port)+1)
599 else:
599 else:
600 conf_address = self.plot_address + '.config'
600 conf_address = self.plot_address + '.config'
601 sender_web_config.bind(conf_address)
601 sender_web_config.bind(conf_address)
602 time.sleep(1)
602 time.sleep(1)
603 for kwargs in self.operationKwargs.values():
603 for kwargs in self.operationKwargs.values():
604 if 'plot' in kwargs:
604 if 'plot' in kwargs:
605 log.success('[Sending] Config data to web for {}'.format(kwargs['code'].upper()))
605 log.success('[Sending] Config data to web for {}'.format(kwargs['code'].upper()))
606 sender_web_config.send_string(json.dumps(kwargs))
606 sender_web_config.send_string(json.dumps(kwargs))
607 self.isWebConfig = True No newline at end of file
607 self.isWebConfig = True
General Comments 0
You need to be logged in to leave comments. Login now