##// END OF EJS Templates
Issues Arreglados
J Gomez -
r971:e09ceb63bec5
parent child
Show More
@@ -1,907 +1,934
1
1
2 import os
2 import os
3 import zmq
3 import zmq
4 import time
4 import time
5 import numpy
5 import numpy
6 import datetime
6 import datetime
7 import numpy as np
7 import numpy as np
8 import matplotlib
8 import matplotlib
9 import glob
9 matplotlib.use('TkAgg')
10 matplotlib.use('TkAgg')
10 import matplotlib.pyplot as plt
11 import matplotlib.pyplot as plt
11 from mpl_toolkits.axes_grid1 import make_axes_locatable
12 from mpl_toolkits.axes_grid1 import make_axes_locatable
12 from matplotlib.ticker import FuncFormatter, LinearLocator
13 from matplotlib.ticker import FuncFormatter, LinearLocator
13 from multiprocessing import Process
14 from multiprocessing import Process
14
15
15 from schainpy.model.proc.jroproc_base import Operation
16 from schainpy.model.proc.jroproc_base import Operation
16
17
17 plt.ion()
18 plt.ion()
18
19
19 func = lambda x, pos: ('%s') %(datetime.datetime.fromtimestamp(x).strftime('%H:%M'))
20 func = lambda x, pos: ('%s') %(datetime.datetime.fromtimestamp(x).strftime('%H:%M'))
20
21
21 d1970 = datetime.datetime(1970,1,1)
22 d1970 = datetime.datetime(1970,1,1)
22
23
23 class PlotData(Operation, Process):
24 class PlotData(Operation, Process):
24
25
25 CODE = 'Figure'
26 CODE = 'Figure'
26 colormap = 'jro'
27 colormap = 'jro'
27 CONFLATE = False
28 CONFLATE = False
28 __MAXNUMX = 80
29 __MAXNUMX = 80
29 __missing = 1E30
30 __missing = 1E30
30
31
31 def __init__(self, **kwargs):
32 def __init__(self, **kwargs):
32
33
33 Operation.__init__(self, plot=True, **kwargs)
34 Operation.__init__(self, plot=True, **kwargs)
34 Process.__init__(self)
35 Process.__init__(self)
35 self.kwargs['code'] = self.CODE
36 self.kwargs['code'] = self.CODE
36 self.mp = False
37 self.mp = False
37 self.dataOut = None
38 self.dataOut = None
38 self.isConfig = False
39 self.isConfig = False
39 self.figure = None
40 self.figure = None
40 self.axes = []
41 self.axes = []
41 self.localtime = kwargs.pop('localtime', True)
42 self.localtime = kwargs.pop('localtime', True)
42 self.show = kwargs.get('show', True)
43 self.show = kwargs.get('show', True)
43 self.save = kwargs.get('save', False)
44 self.save = kwargs.get('save', False)
44 self.colormap = kwargs.get('colormap', self.colormap)
45 self.colormap = kwargs.get('colormap', self.colormap)
45 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
46 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
46 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
47 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
47 self.showprofile = kwargs.get('showprofile', True)
48 self.showprofile = kwargs.get('showprofile', True)
48 self.title = kwargs.get('wintitle', '')
49 self.title = kwargs.get('wintitle', '')
49 self.xaxis = kwargs.get('xaxis', 'frequency')
50 self.xaxis = kwargs.get('xaxis', 'frequency')
50 self.zmin = kwargs.get('zmin', None)
51 self.zmin = kwargs.get('zmin', None)
51 self.zmax = kwargs.get('zmax', None)
52 self.zmax = kwargs.get('zmax', None)
52 self.xmin = kwargs.get('xmin', None)
53 self.xmin = kwargs.get('xmin', None)
53 self.xmax = kwargs.get('xmax', None)
54 self.xmax = kwargs.get('xmax', None)
54 self.xrange = kwargs.get('xrange', 24)
55 self.xrange = kwargs.get('xrange', 24)
55 self.ymin = kwargs.get('ymin', None)
56 self.ymin = kwargs.get('ymin', None)
56 self.ymax = kwargs.get('ymax', None)
57 self.ymax = kwargs.get('ymax', None)
57 self.__MAXNUMY = kwargs.get('decimation', 80)
58 self.__MAXNUMY = kwargs.get('decimation', 80)
58 self.throttle_value = 5
59 self.throttle_value = 5
59 self.times = []
60 self.times = []
60 #self.interactive = self.kwargs['parent']
61 #self.interactive = self.kwargs['parent']
61
62
62 '''
63 '''
63 this new parameter is created to plot data from varius channels at different figures
64 this new parameter is created to plot data from varius channels at different figures
64 1. crear una lista de figuras donde se puedan plotear las figuras,
65 1. crear una lista de figuras donde se puedan plotear las figuras,
65 2. dar las opciones de configuracion a cada figura, estas opciones son iguales para ambas figuras
66 2. dar las opciones de configuracion a cada figura, estas opciones son iguales para ambas figuras
66 3. probar?
67 3. probar?
67 '''
68 '''
68 self.ind_plt_ch = kwargs.get('ind_plt_ch', False)
69 self.ind_plt_ch = kwargs.get('ind_plt_ch', False)
69 self.figurelist = None
70 self.figurelist = None
70
71
71
72
72 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
73 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
73
74
74 if x_buffer.shape[0] < 2:
75 if x_buffer.shape[0] < 2:
75 return x_buffer, y_buffer, z_buffer
76 return x_buffer, y_buffer, z_buffer
76
77
77 deltas = x_buffer[1:] - x_buffer[0:-1]
78 deltas = x_buffer[1:] - x_buffer[0:-1]
78 x_median = np.median(deltas)
79 x_median = np.median(deltas)
79
80
80 index = np.where(deltas > 5*x_median)
81 index = np.where(deltas > 5*x_median)
81
82
82 if len(index[0]) != 0:
83 if len(index[0]) != 0:
83 z_buffer[::, index[0], ::] = self.__missing
84 z_buffer[::, index[0], ::] = self.__missing
84 z_buffer = np.ma.masked_inside(z_buffer,
85 z_buffer = np.ma.masked_inside(z_buffer,
85 0.99*self.__missing,
86 0.99*self.__missing,
86 1.01*self.__missing)
87 1.01*self.__missing)
87
88
88 return x_buffer, y_buffer, z_buffer
89 return x_buffer, y_buffer, z_buffer
89
90
90 def decimate(self):
91 def decimate(self):
91
92
92 # dx = int(len(self.x)/self.__MAXNUMX) + 1
93 # dx = int(len(self.x)/self.__MAXNUMX) + 1
93 dy = int(len(self.y)/self.__MAXNUMY) + 1
94 dy = int(len(self.y)/self.__MAXNUMY) + 1
94
95
95 # x = self.x[::dx]
96 # x = self.x[::dx]
96 x = self.x
97 x = self.x
97 y = self.y[::dy]
98 y = self.y[::dy]
98 z = self.z[::, ::, ::dy]
99 z = self.z[::, ::, ::dy]
99
100
100 return x, y, z
101 return x, y, z
101
102
103 '''
104 JM:
105 elimana las otras imagenes generadas debido a que lso workers no llegan en orden y le pueden
106 poner otro tiempo a la figura q no necesariamente es el ultimo.
107 Solo se realiza cuando termina la imagen.
108 Problemas:
109 -Aun no encuentro.
110 '''
111 def deleteanotherfiles(self):
112 figurenames=[]
113 for n, eachfigure in enumerate(self.figurelist):
114 #add specific name for each channel in channelList
115 ghostfigname = os.path.join(self.save, '{}_{}_{}'.format(self.titles[n].replace(' ',''),self.CODE,
116 datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d')))
117 figname = os.path.join(self.save, '{}_{}_{}.png'.format(self.titles[n].replace(' ',''),self.CODE,
118 datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
119
120 for ghostfigure in glob.glob(ghostfigname+'*'): #ghostfigure will adopt all posible names of figures
121 if ghostfigure != figname:
122 os.remove(ghostfigure)
123 print 'Removing GhostFigures:' , figname
124
102 def __plot(self):
125 def __plot(self):
103
126
104 print 'plotting...{}'.format(self.CODE)
127 print 'plotting...{}'.format(self.CODE)
105 if self.ind_plt_ch is False : #standard
128 if self.ind_plt_ch is False : #standard
106 if self.show:
129 if self.show:
107 self.figure.show()
130 self.figure.show()
108 self.plot()
131 self.plot()
109 plt.tight_layout()
132 plt.tight_layout()
110 self.figure.canvas.manager.set_window_title('{} {} - {}'.format(self.title, self.CODE.upper(),
133 self.figure.canvas.manager.set_window_title('{} {} - {}'.format(self.title, self.CODE.upper(),
111 datetime.datetime.fromtimestamp(self.max_time).strftime('%Y/%m/%d')))
134 datetime.datetime.fromtimestamp(self.max_time).strftime('%Y/%m/%d')))
112 else :
135 else :
113 for n, eachfigure in enumerate(self.figurelist):
136 for n, eachfigure in enumerate(self.figurelist):
114 if self.show:
137 if self.show:
115 eachfigure.show()
138 eachfigure.show()
139
116 self.plot() # ok? como elijo que figura?
140 self.plot() # ok? como elijo que figura?
117 plt.tight_layout()
141 #eachfigure.subplots_adjust(left=0.2)
142 #eachfigure.subplots_adjuccst(right=0.2)
143 eachfigure.tight_layout() # ajuste de cada subplot
118 eachfigure.canvas.manager.set_window_title('{} {} - {}'.format(self.title[n], self.CODE.upper(),
144 eachfigure.canvas.manager.set_window_title('{} {} - {}'.format(self.title[n], self.CODE.upper(),
119 datetime.datetime.fromtimestamp(self.max_time).strftime('%Y/%m/%d')))
145 datetime.datetime.fromtimestamp(self.max_time).strftime('%Y/%m/%d')))
120
146
121 # if self.save:
147 # if self.save:
122 # if self.ind_plt_ch is False : #standard
148 # if self.ind_plt_ch is False : #standard
123 # figname = os.path.join(self.save, '{}_{}.png'.format(self.CODE,
149 # figname = os.path.join(self.save, '{}_{}.png'.format(self.CODE,
124 # datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
150 # datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
125 # print 'Saving figure: {}'.format(figname)
151 # print 'Saving figure: {}'.format(figname)
126 # self.figure.savefig(figname)
152 # self.figure.savefig(figname)
127 # else :
153 # else :
128 # for n, eachfigure in enumerate(self.figurelist):
154 # for n, eachfigure in enumerate(self.figurelist):
129 # #add specific name for each channel in channelList
155 # #add specific name for each channel in channelList
130 # figname = os.path.join(self.save, '{}_{}_{}.png'.format(self.titles[n],self.CODE,
156 # figname = os.path.join(self.save, '{}_{}_{}.png'.format(self.titles[n],self.CODE,
131 # datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
157 # datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
132 #
158 #
133 # print 'Saving figure: {}'.format(figname)
159 # print 'Saving figure: {}'.format(figname)
134 # eachfigure.savefig(figname)
160 # eachfigure.savefig(figname)
135
161
136 if self.ind_plt_ch is False :
162 if self.ind_plt_ch is False :
137 self.figure.canvas.draw()
163 self.figure.canvas.draw()
138 else :
164 else :
139 for eachfigure in self.figurelist:
165 for eachfigure in self.figurelist:
140 eachfigure.canvas.draw()
166 eachfigure.canvas.draw()
141
167
142 if self.save:
168 if self.save:
143 if self.ind_plt_ch is False : #standard
169 if self.ind_plt_ch is False : #standard
144 figname = os.path.join(self.save, '{}_{}.png'.format(self.CODE,
170 figname = os.path.join(self.save, '{}_{}.png'.format(self.CODE,
145 datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
171 datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
146 print 'Saving figure: {}'.format(figname)
172 print 'Saving figure: {}'.format(figname)
147 self.figure.savefig(figname)
173 self.figure.savefig(figname)
148 else :
174 else :
149 for n, eachfigure in enumerate(self.figurelist):
175 for n, eachfigure in enumerate(self.figurelist):
150 #add specific name for each channel in channelList
176 #add specific name for each channel in channelList
151 figname = os.path.join(self.save, '{}_{}_{}.png'.format(self.titles[n],self.CODE,
177 figname = os.path.join(self.save, '{}_{}_{}.png'.format(self.titles[n].replace(' ',''),self.CODE,
152 datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
178 datetime.datetime.fromtimestamp(self.saveTime).strftime('%y%m%d_%H%M%S')))
153
179
154 print 'Saving figure: {}'.format(figname)
180 print 'Saving figure: {}'.format(figname)
155 eachfigure.savefig(figname)
181 eachfigure.savefig(figname)
156
182
157
183
158 def plot(self):
184 def plot(self):
159
185
160 print 'plotting...{}'.format(self.CODE.upper())
186 print 'plotting...{}'.format(self.CODE.upper())
161 return
187 return
162
188
163 def run(self):
189 def run(self):
164
190
165 print '[Starting] {}'.format(self.name)
191 print '[Starting] {}'.format(self.name)
166
192
167 context = zmq.Context()
193 context = zmq.Context()
168 receiver = context.socket(zmq.SUB)
194 receiver = context.socket(zmq.SUB)
169 receiver.setsockopt(zmq.SUBSCRIBE, '')
195 receiver.setsockopt(zmq.SUBSCRIBE, '')
170 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
196 receiver.setsockopt(zmq.CONFLATE, self.CONFLATE)
171
197
172 if 'server' in self.kwargs['parent']:
198 if 'server' in self.kwargs['parent']:
173 receiver.connect('ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
199 receiver.connect('ipc:///tmp/{}.plots'.format(self.kwargs['parent']['server']))
174 else:
200 else:
175 receiver.connect("ipc:///tmp/zmq.plots")
201 receiver.connect("ipc:///tmp/zmq.plots")
176
202
177 seconds_passed = 0
203 seconds_passed = 0
178
204
179 while True:
205 while True:
180 try:
206 try:
181 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)#flags=zmq.NOBLOCK
207 self.data = receiver.recv_pyobj(flags=zmq.NOBLOCK)#flags=zmq.NOBLOCK
182 self.started = self.data['STARTED']
208 self.started = self.data['STARTED']
183 self.dataOut = self.data['dataOut']
209 self.dataOut = self.data['dataOut']
184
210
185 if (len(self.times) < len(self.data['times']) and not self.started and self.data['ENDED']):
211 if (len(self.times) < len(self.data['times']) and not self.started and self.data['ENDED']):
186 continue
212 continue
187
213
188 self.times = self.data['times']
214 self.times = self.data['times']
189 self.times.sort()
215 self.times.sort()
190 self.throttle_value = self.data['throttle']
216 self.throttle_value = self.data['throttle']
191 self.min_time = self.times[0]
217 self.min_time = self.times[0]
192 self.max_time = self.times[-1]
218 self.max_time = self.times[-1]
193
219
194 if self.isConfig is False:
220 if self.isConfig is False:
195 print 'setting up'
221 print 'setting up'
196 self.setup()
222 self.setup()
197 self.isConfig = True
223 self.isConfig = True
198 self.__plot()
224 self.__plot()
199
225
200 if self.data['ENDED'] is True:
226 if self.data['ENDED'] is True:
201 print '********GRAPHIC ENDED********'
227 print '********GRAPHIC ENDED********'
202 self.ended = True
228 self.ended = True
203 self.isConfig = False
229 self.isConfig = False
204 self.__plot()
230 self.__plot()
231 self.deleteanotherfiles() #CLPDG
205 elif seconds_passed >= self.data['throttle']:
232 elif seconds_passed >= self.data['throttle']:
206 print 'passed', seconds_passed
233 print 'passed', seconds_passed
207 self.__plot()
234 self.__plot()
208 seconds_passed = 0
235 seconds_passed = 0
209
236
210 except zmq.Again as e:
237 except zmq.Again as e:
211 print 'Waiting for data...'
238 print 'Waiting for data...'
212 plt.pause(2)
239 plt.pause(2)
213 seconds_passed += 2
240 seconds_passed += 2
214
241
215 def close(self):
242 def close(self):
216 if self.dataOut:
243 if self.dataOut:
217 self.__plot()
244 self.__plot()
218
245
219
246
220 class PlotSpectraData(PlotData):
247 class PlotSpectraData(PlotData):
221
248
222 CODE = 'spc'
249 CODE = 'spc'
223 colormap = 'jro'
250 colormap = 'jro'
224 CONFLATE = False
251 CONFLATE = False
225
252
226 def setup(self):
253 def setup(self):
227
254
228 ncolspan = 1
255 ncolspan = 1
229 colspan = 1
256 colspan = 1
230 self.ncols = int(numpy.sqrt(self.dataOut.nChannels)+0.9)
257 self.ncols = int(numpy.sqrt(self.dataOut.nChannels)+0.9)
231 self.nrows = int(self.dataOut.nChannels*1./self.ncols + 0.9)
258 self.nrows = int(self.dataOut.nChannels*1./self.ncols + 0.9)
232 self.width = 3.6*self.ncols
259 self.width = 3.6*self.ncols
233 self.height = 3.2*self.nrows
260 self.height = 3.2*self.nrows
234 if self.showprofile:
261 if self.showprofile:
235 ncolspan = 3
262 ncolspan = 3
236 colspan = 2
263 colspan = 2
237 self.width += 1.2*self.ncols
264 self.width += 1.2*self.ncols
238
265
239 self.ylabel = 'Range [Km]'
266 self.ylabel = 'Range [Km]'
240 self.titles = ['Channel {}'.format(x) for x in self.dataOut.channelList]
267 self.titles = ['Channel {}'.format(x) for x in self.dataOut.channelList]
241
268
242 if self.figure is None:
269 if self.figure is None:
243 self.figure = plt.figure(figsize=(self.width, self.height),
270 self.figure = plt.figure(figsize=(self.width, self.height),
244 edgecolor='k',
271 edgecolor='k',
245 facecolor='w')
272 facecolor='w')
246 else:
273 else:
247 self.figure.clf()
274 self.figure.clf()
248
275
249 n = 0
276 n = 0
250 for y in range(self.nrows):
277 for y in range(self.nrows):
251 for x in range(self.ncols):
278 for x in range(self.ncols):
252 if n >= self.dataOut.nChannels:
279 if n >= self.dataOut.nChannels:
253 break
280 break
254 ax = plt.subplot2grid((self.nrows, self.ncols*ncolspan), (y, x*ncolspan), 1, colspan)
281 ax = plt.subplot2grid((self.nrows, self.ncols*ncolspan), (y, x*ncolspan), 1, colspan)
255 if self.showprofile:
282 if self.showprofile:
256 ax.ax_profile = plt.subplot2grid((self.nrows, self.ncols*ncolspan), (y, x*ncolspan+colspan), 1, 1)
283 ax.ax_profile = plt.subplot2grid((self.nrows, self.ncols*ncolspan), (y, x*ncolspan+colspan), 1, 1)
257
284
258 ax.firsttime = True
285 ax.firsttime = True
259 self.axes.append(ax)
286 self.axes.append(ax)
260 n += 1
287 n += 1
261
288
262 def plot(self):
289 def plot(self):
263
290
264 if self.xaxis == "frequency":
291 if self.xaxis == "frequency":
265 x = self.dataOut.getFreqRange(1)/1000.
292 x = self.dataOut.getFreqRange(1)/1000.
266 xlabel = "Frequency (kHz)"
293 xlabel = "Frequency (kHz)"
267 elif self.xaxis == "time":
294 elif self.xaxis == "time":
268 x = self.dataOut.getAcfRange(1)
295 x = self.dataOut.getAcfRange(1)
269 xlabel = "Time (ms)"
296 xlabel = "Time (ms)"
270 else:
297 else:
271 x = self.dataOut.getVelRange(1)
298 x = self.dataOut.getVelRange(1)
272 xlabel = "Velocity (m/s)"
299 xlabel = "Velocity (m/s)"
273
300
274 y = self.dataOut.getHeiRange()
301 y = self.dataOut.getHeiRange()
275 z = self.data[self.CODE]
302 z = self.data[self.CODE]
276
303
277 for n, ax in enumerate(self.axes):
304 for n, ax in enumerate(self.axes):
278 if ax.firsttime:
305 if ax.firsttime:
279 self.xmax = self.xmax if self.xmax else np.nanmax(x)
306 self.xmax = self.xmax if self.xmax else np.nanmax(x)
280 self.xmin = self.xmin if self.xmin else -self.xmax
307 self.xmin = self.xmin if self.xmin else -self.xmax
281 self.ymin = self.ymin if self.ymin else np.nanmin(y)
308 self.ymin = self.ymin if self.ymin else np.nanmin(y)
282 self.ymax = self.ymax if self.ymax else np.nanmax(y)
309 self.ymax = self.ymax if self.ymax else np.nanmax(y)
283 self.zmin = self.zmin if self.zmin else np.nanmin(z)
310 self.zmin = self.zmin if self.zmin else np.nanmin(z)
284 self.zmax = self.zmax if self.zmax else np.nanmax(z)
311 self.zmax = self.zmax if self.zmax else np.nanmax(z)
285 ax.plot = ax.pcolormesh(x, y, z[n].T,
312 ax.plot = ax.pcolormesh(x, y, z[n].T,
286 vmin=self.zmin,
313 vmin=self.zmin,
287 vmax=self.zmax,
314 vmax=self.zmax,
288 cmap=plt.get_cmap(self.colormap)
315 cmap=plt.get_cmap(self.colormap)
289 )
316 )
290 divider = make_axes_locatable(ax)
317 divider = make_axes_locatable(ax)
291 cax = divider.new_horizontal(size='3%', pad=0.05)
318 cax = divider.new_horizontal(size='3%', pad=0.05)
292 self.figure.add_axes(cax)
319 self.figure.add_axes(cax)
293 plt.colorbar(ax.plot, cax)
320 plt.colorbar(ax.plot, cax)
294
321
295 ax.set_xlim(self.xmin, self.xmax)
322 ax.set_xlim(self.xmin, self.xmax)
296 ax.set_ylim(self.ymin, self.ymax)
323 ax.set_ylim(self.ymin, self.ymax)
297
324
298 ax.set_ylabel(self.ylabel)
325 ax.set_ylabel(self.ylabel)
299 ax.set_xlabel(xlabel)
326 ax.set_xlabel(xlabel)
300
327
301 ax.firsttime = False
328 ax.firsttime = False
302
329
303 if self.showprofile:
330 if self.showprofile:
304 ax.plot_profile= ax.ax_profile.plot(self.data['rti'][self.max_time][n], y)[0]
331 ax.plot_profile= ax.ax_profile.plot(self.data['rti'][self.max_time][n], y)[0]
305 ax.ax_profile.set_xlim(self.zmin, self.zmax)
332 ax.ax_profile.set_xlim(self.zmin, self.zmax)
306 ax.ax_profile.set_ylim(self.ymin, self.ymax)
333 ax.ax_profile.set_ylim(self.ymin, self.ymax)
307 ax.ax_profile.set_xlabel('dB')
334 ax.ax_profile.set_xlabel('dB')
308 ax.ax_profile.grid(b=True, axis='x')
335 ax.ax_profile.grid(b=True, axis='x')
309 ax.plot_noise = ax.ax_profile.plot(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y,
336 ax.plot_noise = ax.ax_profile.plot(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y,
310 color="k", linestyle="dashed", lw=2)[0]
337 color="k", linestyle="dashed", lw=2)[0]
311 [tick.set_visible(False) for tick in ax.ax_profile.get_yticklabels()]
338 [tick.set_visible(False) for tick in ax.ax_profile.get_yticklabels()]
312 else:
339 else:
313 ax.plot.set_array(z[n].T.ravel())
340 ax.plot.set_array(z[n].T.ravel())
314 if self.showprofile:
341 if self.showprofile:
315 ax.plot_profile.set_data(self.data['rti'][self.max_time][n], y)
342 ax.plot_profile.set_data(self.data['rti'][self.max_time][n], y)
316 ax.plot_noise.set_data(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y)
343 ax.plot_noise.set_data(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y)
317
344
318 ax.set_title('{} - Noise: {:.2f} dB'.format(self.titles[n], self.data['noise'][self.max_time][n]),
345 ax.set_title('{} - Noise: {:.2f} dB'.format(self.titles[n], self.data['noise'][self.max_time][n]),
319 size=8)
346 size=8)
320 self.saveTime = self.max_time
347 self.saveTime = self.max_time
321
348
322
349
323 class PlotCrossSpectraData(PlotData):
350 class PlotCrossSpectraData(PlotData):
324
351
325 CODE = 'cspc'
352 CODE = 'cspc'
326 zmin_coh = None
353 zmin_coh = None
327 zmax_coh = None
354 zmax_coh = None
328 zmin_phase = None
355 zmin_phase = None
329 zmax_phase = None
356 zmax_phase = None
330 CONFLATE = False
357 CONFLATE = False
331
358
332 def setup(self):
359 def setup(self):
333
360
334 ncolspan = 1
361 ncolspan = 1
335 colspan = 1
362 colspan = 1
336 self.ncols = 2
363 self.ncols = 2
337 self.nrows = self.dataOut.nPairs
364 self.nrows = self.dataOut.nPairs
338 self.width = 3.6*self.ncols
365 self.width = 3.6*self.ncols
339 self.height = 3.2*self.nrows
366 self.height = 3.2*self.nrows
340
367
341 self.ylabel = 'Range [Km]'
368 self.ylabel = 'Range [Km]'
342 self.titles = ['Channel {}'.format(x) for x in self.dataOut.channelList]
369 self.titles = ['Channel {}'.format(x) for x in self.dataOut.channelList]
343
370
344 if self.figure is None:
371 if self.figure is None:
345 self.figure = plt.figure(figsize=(self.width, self.height),
372 self.figure = plt.figure(figsize=(self.width, self.height),
346 edgecolor='k',
373 edgecolor='k',
347 facecolor='w')
374 facecolor='w')
348 else:
375 else:
349 self.figure.clf()
376 self.figure.clf()
350
377
351 for y in range(self.nrows):
378 for y in range(self.nrows):
352 for x in range(self.ncols):
379 for x in range(self.ncols):
353 ax = plt.subplot2grid((self.nrows, self.ncols), (y, x), 1, 1)
380 ax = plt.subplot2grid((self.nrows, self.ncols), (y, x), 1, 1)
354 ax.firsttime = True
381 ax.firsttime = True
355 self.axes.append(ax)
382 self.axes.append(ax)
356
383
357 def plot(self):
384 def plot(self):
358
385
359 if self.xaxis == "frequency":
386 if self.xaxis == "frequency":
360 x = self.dataOut.getFreqRange(1)/1000.
387 x = self.dataOut.getFreqRange(1)/1000.
361 xlabel = "Frequency (kHz)"
388 xlabel = "Frequency (kHz)"
362 elif self.xaxis == "time":
389 elif self.xaxis == "time":
363 x = self.dataOut.getAcfRange(1)
390 x = self.dataOut.getAcfRange(1)
364 xlabel = "Time (ms)"
391 xlabel = "Time (ms)"
365 else:
392 else:
366 x = self.dataOut.getVelRange(1)
393 x = self.dataOut.getVelRange(1)
367 xlabel = "Velocity (m/s)"
394 xlabel = "Velocity (m/s)"
368
395
369 y = self.dataOut.getHeiRange()
396 y = self.dataOut.getHeiRange()
370 z_coh = self.data['cspc_coh']
397 z_coh = self.data['cspc_coh']
371 z_phase = self.data['cspc_phase']
398 z_phase = self.data['cspc_phase']
372
399
373 for n in range(self.nrows):
400 for n in range(self.nrows):
374 ax = self.axes[2*n]
401 ax = self.axes[2*n]
375 ax1 = self.axes[2*n+1]
402 ax1 = self.axes[2*n+1]
376 if ax.firsttime:
403 if ax.firsttime:
377 self.xmax = self.xmax if self.xmax else np.nanmax(x)
404 self.xmax = self.xmax if self.xmax else np.nanmax(x)
378 self.xmin = self.xmin if self.xmin else -self.xmax
405 self.xmin = self.xmin if self.xmin else -self.xmax
379 self.ymin = self.ymin if self.ymin else np.nanmin(y)
406 self.ymin = self.ymin if self.ymin else np.nanmin(y)
380 self.ymax = self.ymax if self.ymax else np.nanmax(y)
407 self.ymax = self.ymax if self.ymax else np.nanmax(y)
381 self.zmin_coh = self.zmin_coh if self.zmin_coh else 0.0
408 self.zmin_coh = self.zmin_coh if self.zmin_coh else 0.0
382 self.zmax_coh = self.zmax_coh if self.zmax_coh else 1.0
409 self.zmax_coh = self.zmax_coh if self.zmax_coh else 1.0
383 self.zmin_phase = self.zmin_phase if self.zmin_phase else -180
410 self.zmin_phase = self.zmin_phase if self.zmin_phase else -180
384 self.zmax_phase = self.zmax_phase if self.zmax_phase else 180
411 self.zmax_phase = self.zmax_phase if self.zmax_phase else 180
385
412
386 ax.plot = ax.pcolormesh(x, y, z_coh[n].T,
413 ax.plot = ax.pcolormesh(x, y, z_coh[n].T,
387 vmin=self.zmin_coh,
414 vmin=self.zmin_coh,
388 vmax=self.zmax_coh,
415 vmax=self.zmax_coh,
389 cmap=plt.get_cmap(self.colormap_coh)
416 cmap=plt.get_cmap(self.colormap_coh)
390 )
417 )
391 divider = make_axes_locatable(ax)
418 divider = make_axes_locatable(ax)
392 cax = divider.new_horizontal(size='3%', pad=0.05)
419 cax = divider.new_horizontal(size='3%', pad=0.05)
393 self.figure.add_axes(cax)
420 self.figure.add_axes(cax)
394 plt.colorbar(ax.plot, cax)
421 plt.colorbar(ax.plot, cax)
395
422
396 ax.set_xlim(self.xmin, self.xmax)
423 ax.set_xlim(self.xmin, self.xmax)
397 ax.set_ylim(self.ymin, self.ymax)
424 ax.set_ylim(self.ymin, self.ymax)
398
425
399 ax.set_ylabel(self.ylabel)
426 ax.set_ylabel(self.ylabel)
400 ax.set_xlabel(xlabel)
427 ax.set_xlabel(xlabel)
401 ax.firsttime = False
428 ax.firsttime = False
402
429
403 ax1.plot = ax1.pcolormesh(x, y, z_phase[n].T,
430 ax1.plot = ax1.pcolormesh(x, y, z_phase[n].T,
404 vmin=self.zmin_phase,
431 vmin=self.zmin_phase,
405 vmax=self.zmax_phase,
432 vmax=self.zmax_phase,
406 cmap=plt.get_cmap(self.colormap_phase)
433 cmap=plt.get_cmap(self.colormap_phase)
407 )
434 )
408 divider = make_axes_locatable(ax1)
435 divider = make_axes_locatable(ax1)
409 cax = divider.new_horizontal(size='3%', pad=0.05)
436 cax = divider.new_horizontal(size='3%', pad=0.05)
410 self.figure.add_axes(cax)
437 self.figure.add_axes(cax)
411 plt.colorbar(ax1.plot, cax)
438 plt.colorbar(ax1.plot, cax)
412
439
413 ax1.set_xlim(self.xmin, self.xmax)
440 ax1.set_xlim(self.xmin, self.xmax)
414 ax1.set_ylim(self.ymin, self.ymax)
441 ax1.set_ylim(self.ymin, self.ymax)
415
442
416 ax1.set_ylabel(self.ylabel)
443 ax1.set_ylabel(self.ylabel)
417 ax1.set_xlabel(xlabel)
444 ax1.set_xlabel(xlabel)
418 ax1.firsttime = False
445 ax1.firsttime = False
419 else:
446 else:
420 ax.plot.set_array(z_coh[n].T.ravel())
447 ax.plot.set_array(z_coh[n].T.ravel())
421 ax1.plot.set_array(z_phase[n].T.ravel())
448 ax1.plot.set_array(z_phase[n].T.ravel())
422
449
423 ax.set_title('Coherence Ch{} * Ch{}'.format(self.dataOut.pairsList[n][0], self.dataOut.pairsList[n][1]), size=8)
450 ax.set_title('Coherence Ch{} * Ch{}'.format(self.dataOut.pairsList[n][0], self.dataOut.pairsList[n][1]), size=8)
424 ax1.set_title('Phase Ch{} * Ch{}'.format(self.dataOut.pairsList[n][0], self.dataOut.pairsList[n][1]), size=8)
451 ax1.set_title('Phase Ch{} * Ch{}'.format(self.dataOut.pairsList[n][0], self.dataOut.pairsList[n][1]), size=8)
425 self.saveTime = self.max_time
452 self.saveTime = self.max_time
426
453
427
454
428 class PlotSpectraMeanData(PlotSpectraData):
455 class PlotSpectraMeanData(PlotSpectraData):
429
456
430 CODE = 'spc_mean'
457 CODE = 'spc_mean'
431 colormap = 'jet'
458 colormap = 'jet'
432
459
433 def plot(self):
460 def plot(self):
434
461
435 if self.xaxis == "frequency":
462 if self.xaxis == "frequency":
436 x = self.dataOut.getFreqRange(1)/1000.
463 x = self.dataOut.getFreqRange(1)/1000.
437 xlabel = "Frequency (kHz)"
464 xlabel = "Frequency (kHz)"
438 elif self.xaxis == "time":
465 elif self.xaxis == "time":
439 x = self.dataOut.getAcfRange(1)
466 x = self.dataOut.getAcfRange(1)
440 xlabel = "Time (ms)"
467 xlabel = "Time (ms)"
441 else:
468 else:
442 x = self.dataOut.getVelRange(1)
469 x = self.dataOut.getVelRange(1)
443 xlabel = "Velocity (m/s)"
470 xlabel = "Velocity (m/s)"
444
471
445 y = self.dataOut.getHeiRange()
472 y = self.dataOut.getHeiRange()
446 z = self.data['spc']
473 z = self.data['spc']
447 mean = self.data['mean'][self.max_time]
474 mean = self.data['mean'][self.max_time]
448
475
449 for n, ax in enumerate(self.axes):
476 for n, ax in enumerate(self.axes):
450
477
451 if ax.firsttime:
478 if ax.firsttime:
452 self.xmax = self.xmax if self.xmax else np.nanmax(x)
479 self.xmax = self.xmax if self.xmax else np.nanmax(x)
453 self.xmin = self.xmin if self.xmin else -self.xmax
480 self.xmin = self.xmin if self.xmin else -self.xmax
454 self.ymin = self.ymin if self.ymin else np.nanmin(y)
481 self.ymin = self.ymin if self.ymin else np.nanmin(y)
455 self.ymax = self.ymax if self.ymax else np.nanmax(y)
482 self.ymax = self.ymax if self.ymax else np.nanmax(y)
456 self.zmin = self.zmin if self.zmin else np.nanmin(z)
483 self.zmin = self.zmin if self.zmin else np.nanmin(z)
457 self.zmax = self.zmax if self.zmax else np.nanmax(z)
484 self.zmax = self.zmax if self.zmax else np.nanmax(z)
458 ax.plt = ax.pcolormesh(x, y, z[n].T,
485 ax.plt = ax.pcolormesh(x, y, z[n].T,
459 vmin=self.zmin,
486 vmin=self.zmin,
460 vmax=self.zmax,
487 vmax=self.zmax,
461 cmap=plt.get_cmap(self.colormap)
488 cmap=plt.get_cmap(self.colormap)
462 )
489 )
463 ax.plt_dop = ax.plot(mean[n], y,
490 ax.plt_dop = ax.plot(mean[n], y,
464 color='k')[0]
491 color='k')[0]
465
492
466 divider = make_axes_locatable(ax)
493 divider = make_axes_locatable(ax)
467 cax = divider.new_horizontal(size='3%', pad=0.05)
494 cax = divider.new_horizontal(size='3%', pad=0.05)
468 self.figure.add_axes(cax)
495 self.figure.add_axes(cax)
469 plt.colorbar(ax.plt, cax)
496 plt.colorbar(ax.plt, cax)
470
497
471 ax.set_xlim(self.xmin, self.xmax)
498 ax.set_xlim(self.xmin, self.xmax)
472 ax.set_ylim(self.ymin, self.ymax)
499 ax.set_ylim(self.ymin, self.ymax)
473
500
474 ax.set_ylabel(self.ylabel)
501 ax.set_ylabel(self.ylabel)
475 ax.set_xlabel(xlabel)
502 ax.set_xlabel(xlabel)
476
503
477 ax.firsttime = False
504 ax.firsttime = False
478
505
479 if self.showprofile:
506 if self.showprofile:
480 ax.plt_profile= ax.ax_profile.plot(self.data['rti'][self.max_time][n], y)[0]
507 ax.plt_profile= ax.ax_profile.plot(self.data['rti'][self.max_time][n], y)[0]
481 ax.ax_profile.set_xlim(self.zmin, self.zmax)
508 ax.ax_profile.set_xlim(self.zmin, self.zmax)
482 ax.ax_profile.set_ylim(self.ymin, self.ymax)
509 ax.ax_profile.set_ylim(self.ymin, self.ymax)
483 ax.ax_profile.set_xlabel('dB')
510 ax.ax_profile.set_xlabel('dB')
484 ax.ax_profile.grid(b=True, axis='x')
511 ax.ax_profile.grid(b=True, axis='x')
485 ax.plt_noise = ax.ax_profile.plot(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y,
512 ax.plt_noise = ax.ax_profile.plot(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y,
486 color="k", linestyle="dashed", lw=2)[0]
513 color="k", linestyle="dashed", lw=2)[0]
487 [tick.set_visible(False) for tick in ax.ax_profile.get_yticklabels()]
514 [tick.set_visible(False) for tick in ax.ax_profile.get_yticklabels()]
488 else:
515 else:
489 ax.plt.set_array(z[n].T.ravel())
516 ax.plt.set_array(z[n].T.ravel())
490 ax.plt_dop.set_data(mean[n], y)
517 ax.plt_dop.set_data(mean[n], y)
491 if self.showprofile:
518 if self.showprofile:
492 ax.plt_profile.set_data(self.data['rti'][self.max_time][n], y)
519 ax.plt_profile.set_data(self.data['rti'][self.max_time][n], y)
493 ax.plt_noise.set_data(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y)
520 ax.plt_noise.set_data(numpy.repeat(self.data['noise'][self.max_time][n], len(y)), y)
494
521
495 ax.set_title('{} - Noise: {:.2f} dB'.format(self.titles[n], self.data['noise'][self.max_time][n]),
522 ax.set_title('{} - Noise: {:.2f} dB'.format(self.titles[n], self.data['noise'][self.max_time][n]),
496 size=8)
523 size=8)
497 self.saveTime = self.max_time
524 self.saveTime = self.max_time
498
525
499
526
500 class PlotRTIData(PlotData):
527 class PlotRTIData(PlotData):
501
528
502 CODE = 'rti'
529 CODE = 'rti'
503 colormap = 'jro'
530 colormap = 'jro'
504
531
505 def setup(self):
532 def setup(self):
506 self.ncols = 1
533 self.ncols = 1
507 self.nrows = self.dataOut.nChannels
534 self.nrows = self.dataOut.nChannels
508 self.width = 10
535 self.width = 10
509 self.height = 2.2*self.nrows if self.nrows<6 else 12
536 self.height = 2.2*self.nrows if self.nrows<6 else 12
510 if self.nrows==1:
537 if self.nrows==1:
511 self.height += 1
538 self.height += 1
512 self.ylabel = 'Range [Km]'
539 self.ylabel = 'Range [Km]'
513 self.titles = ['Channel {}'.format(x) for x in self.dataOut.channelList]
540 self.titles = ['Channel {}'.format(x) for x in self.dataOut.channelList]
514
541
515 '''
542 '''
516 Logica:
543 Logica:
517 1) Si la variable ind_plt_ch es True, va a crear mas de 1 figura
544 1) Si la variable ind_plt_ch es True, va a crear mas de 1 figura
518 2) guardamos "Figures" en una lista y "axes" en otra, quizas se deberia guardar el
545 2) guardamos "Figures" en una lista y "axes" en otra, quizas se deberia guardar el
519 axis dentro de "Figures" como un diccionario.
546 axis dentro de "Figures" como un diccionario.
520 '''
547 '''
521 if self.ind_plt_ch is False: #standard mode
548 if self.ind_plt_ch is False: #standard mode
522
549
523 if self.figure is None: #solo para la priemra vez
550 if self.figure is None: #solo para la priemra vez
524 self.figure = plt.figure(figsize=(self.width, self.height),
551 self.figure = plt.figure(figsize=(self.width, self.height),
525 edgecolor='k',
552 edgecolor='k',
526 facecolor='w')
553 facecolor='w')
527 else:
554 else:
528 self.figure.clf()
555 self.figure.clf()
529 self.axes = []
556 self.axes = []
530
557
531
558
532 for n in range(self.nrows):
559 for n in range(self.nrows):
533 ax = self.figure.add_subplot(self.nrows, self.ncols, n+1)
560 ax = self.figure.add_subplot(self.nrows, self.ncols, n+1)
534 #ax = self.figure(n+1)
561 #ax = self.figure(n+1)
535 ax.firsttime = True
562 ax.firsttime = True
536 self.axes.append(ax)
563 self.axes.append(ax)
537
564
538 else : #append one figure foreach channel in channelList
565 else : #append one figure foreach channel in channelList
539 if self.figurelist == None:
566 if self.figurelist == None:
540 self.figurelist = []
567 self.figurelist = []
541 for n in range(self.nrows):
568 for n in range(self.nrows):
542 self.figure = plt.figure(figsize=(self.width, self.height),
569 self.figure = plt.figure(figsize=(self.width, self.height),
543 edgecolor='k',
570 edgecolor='k',
544 facecolor='w')
571 facecolor='w')
545 #add always one subplot
572 #add always one subplot
546 self.figurelist.append(self.figure)
573 self.figurelist.append(self.figure)
547
574
548 else : # cada dia nuevo limpia el axes, pero mantiene el figure
575 else : # cada dia nuevo limpia el axes, pero mantiene el figure
549 for eachfigure in self.figurelist:
576 for eachfigure in self.figurelist:
550 eachfigure.clf() # eliminaria todas las figuras de la lista?
577 eachfigure.clf() # eliminaria todas las figuras de la lista?
551 self.axes = []
578 self.axes = []
552
579
553 for eachfigure in self.figurelist:
580 for eachfigure in self.figurelist:
554 ax = eachfigure.add_subplot(1,1,1) #solo 1 axis por figura
581 ax = eachfigure.add_subplot(1,1,1) #solo 1 axis por figura
555 #ax = self.figure(n+1)
582 #ax = self.figure(n+1)
556 ax.firsttime = True
583 ax.firsttime = True
557 #Cada figura tiene un distinto puntero
584 #Cada figura tiene un distinto puntero
558 self.axes.append(ax)
585 self.axes.append(ax)
559 #plt.close(eachfigure)
586 #plt.close(eachfigure)
560
587
561
588
562 def plot(self):
589 def plot(self):
563
590
564 if self.ind_plt_ch is False: #standard mode
591 if self.ind_plt_ch is False: #standard mode
565 self.x = np.array(self.times)
592 self.x = np.array(self.times)
566 self.y = self.dataOut.getHeiRange()
593 self.y = self.dataOut.getHeiRange()
567 self.z = []
594 self.z = []
568
595
569 for ch in range(self.nrows):
596 for ch in range(self.nrows):
570 self.z.append([self.data[self.CODE][t][ch] for t in self.times])
597 self.z.append([self.data[self.CODE][t][ch] for t in self.times])
571
598
572 self.z = np.array(self.z)
599 self.z = np.array(self.z)
573 for n, ax in enumerate(self.axes):
600 for n, ax in enumerate(self.axes):
574 x, y, z = self.fill_gaps(*self.decimate())
601 x, y, z = self.fill_gaps(*self.decimate())
575 xmin = self.min_time
602 xmin = self.min_time
576 xmax = xmin+self.xrange*60*60
603 xmax = xmin+self.xrange*60*60
577 self.zmin = self.zmin if self.zmin else np.min(self.z)
604 self.zmin = self.zmin if self.zmin else np.min(self.z)
578 self.zmax = self.zmax if self.zmax else np.max(self.z)
605 self.zmax = self.zmax if self.zmax else np.max(self.z)
579 if ax.firsttime:
606 if ax.firsttime:
580 self.ymin = self.ymin if self.ymin else np.nanmin(self.y)
607 self.ymin = self.ymin if self.ymin else np.nanmin(self.y)
581 self.ymax = self.ymax if self.ymax else np.nanmax(self.y)
608 self.ymax = self.ymax if self.ymax else np.nanmax(self.y)
582 plot = ax.pcolormesh(x, y, z[n].T,
609 plot = ax.pcolormesh(x, y, z[n].T,
583 vmin=self.zmin,
610 vmin=self.zmin,
584 vmax=self.zmax,
611 vmax=self.zmax,
585 cmap=plt.get_cmap(self.colormap)
612 cmap=plt.get_cmap(self.colormap)
586 )
613 )
587 divider = make_axes_locatable(ax)
614 divider = make_axes_locatable(ax)
588 cax = divider.new_horizontal(size='2%', pad=0.05)
615 cax = divider.new_horizontal(size='2%', pad=0.05)
589 self.figure.add_axes(cax)
616 self.figure.add_axes(cax)
590 plt.colorbar(plot, cax)
617 plt.colorbar(plot, cax)
591 ax.set_ylim(self.ymin, self.ymax)
618 ax.set_ylim(self.ymin, self.ymax)
592 ax.xaxis.set_major_formatter(FuncFormatter(func))
619 ax.xaxis.set_major_formatter(FuncFormatter(func))
593 ax.xaxis.set_major_locator(LinearLocator(6))
620 ax.xaxis.set_major_locator(LinearLocator(6))
594 ax.set_ylabel(self.ylabel)
621 ax.set_ylabel(self.ylabel)
595 if self.xmin is None:
622 if self.xmin is None:
596 xmin = self.min_time
623 xmin = self.min_time
597 else:
624 else:
598 xmin = (datetime.datetime.combine(self.dataOut.datatime.date(),
625 xmin = (datetime.datetime.combine(self.dataOut.datatime.date(),
599 datetime.time(self.xmin, 0, 0))-d1970).total_seconds()
626 datetime.time(self.xmin, 0, 0))-d1970).total_seconds()
600 ax.set_xlim(xmin, xmax)
627 ax.set_xlim(xmin, xmax)
601 ax.firsttime = False
628 ax.firsttime = False
602 else:
629 else:
603 ax.collections.remove(ax.collections[0])
630 ax.collections.remove(ax.collections[0])
604 ax.set_xlim(xmin, xmax)
631 ax.set_xlim(xmin, xmax)
605 plot = ax.pcolormesh(x, y, z[n].T,
632 plot = ax.pcolormesh(x, y, z[n].T,
606 vmin=self.zmin,
633 vmin=self.zmin,
607 vmax=self.zmax,
634 vmax=self.zmax,
608 cmap=plt.get_cmap(self.colormap)
635 cmap=plt.get_cmap(self.colormap)
609 )
636 )
610 ax.set_title('{} {}'.format(self.titles[n],
637 ax.set_title('{} {}'.format(self.titles[n],
611 datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')),
638 datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')),
612 size=8)
639 size=8)
613
640
614 self.saveTime = self.min_time
641 self.saveTime = self.min_time
615 else :
642 else :
616 self.x = np.array(self.times)
643 self.x = np.array(self.times)
617 self.y = self.dataOut.getHeiRange()
644 self.y = self.dataOut.getHeiRange()
618 self.z = []
645 self.z = []
619
646
620 for ch in range(self.nrows):
647 for ch in range(self.nrows):
621 self.z.append([self.data[self.CODE][t][ch] for t in self.times])
648 self.z.append([self.data[self.CODE][t][ch] for t in self.times])
622
649
623 self.z = np.array(self.z)
650 self.z = np.array(self.z)
624 for n, eachfigure in enumerate(self.figurelist): #estaba ax in axes
651 for n, eachfigure in enumerate(self.figurelist): #estaba ax in axes
625
652
626 x, y, z = self.fill_gaps(*self.decimate())
653 x, y, z = self.fill_gaps(*self.decimate())
627 xmin = self.min_time
654 xmin = self.min_time
628 xmax = xmin+self.xrange*60*60
655 xmax = xmin+self.xrange*60*60
629 self.zmin = self.zmin if self.zmin else np.min(self.z)
656 self.zmin = self.zmin if self.zmin else np.min(self.z)
630 self.zmax = self.zmax if self.zmax else np.max(self.z)
657 self.zmax = self.zmax if self.zmax else np.max(self.z)
631 if self.axes[n].firsttime:
658 if self.axes[n].firsttime:
632 self.ymin = self.ymin if self.ymin else np.nanmin(self.y)
659 self.ymin = self.ymin if self.ymin else np.nanmin(self.y)
633 self.ymax = self.ymax if self.ymax else np.nanmax(self.y)
660 self.ymax = self.ymax if self.ymax else np.nanmax(self.y)
634 plot = self.axes[n].pcolormesh(x, y, z[n].T,
661 plot = self.axes[n].pcolormesh(x, y, z[n].T,
635 vmin=self.zmin,
662 vmin=self.zmin,
636 vmax=self.zmax,
663 vmax=self.zmax,
637 cmap=plt.get_cmap(self.colormap)
664 cmap=plt.get_cmap(self.colormap)
638 )
665 )
639 divider = make_axes_locatable(self.axes[n])
666 divider = make_axes_locatable(self.axes[n])
640 cax = divider.new_horizontal(size='2%', pad=0.05)
667 cax = divider.new_horizontal(size='2%', pad=0.05)
641 eachfigure.add_axes(cax)
668 eachfigure.add_axes(cax)
642 #self.figure2.add_axes(cax)
669 #self.figure2.add_axes(cax)
643 plt.colorbar(plot, cax)
670 plt.colorbar(plot, cax)
644 self.axes[n].set_ylim(self.ymin, self.ymax)
671 self.axes[n].set_ylim(self.ymin, self.ymax)
645
672
646 self.axes[n].xaxis.set_major_formatter(FuncFormatter(func))
673 self.axes[n].xaxis.set_major_formatter(FuncFormatter(func))
647 self.axes[n].xaxis.set_major_locator(LinearLocator(6))
674 self.axes[n].xaxis.set_major_locator(LinearLocator(6))
648
675
649 self.axes[n].set_ylabel(self.ylabel)
676 self.axes[n].set_ylabel(self.ylabel)
650
677
651 if self.xmin is None:
678 if self.xmin is None:
652 xmin = self.min_time
679 xmin = self.min_time
653 else:
680 else:
654 xmin = (datetime.datetime.combine(self.dataOut.datatime.date(),
681 xmin = (datetime.datetime.combine(self.dataOut.datatime.date(),
655 datetime.time(self.xmin, 0, 0))-d1970).total_seconds()
682 datetime.time(self.xmin, 0, 0))-d1970).total_seconds()
656
683
657 self.axes[n].set_xlim(xmin, xmax)
684 self.axes[n].set_xlim(xmin, xmax)
658 self.axes[n].firsttime = False
685 self.axes[n].firsttime = False
659 else:
686 else:
660 self.axes[n].collections.remove(self.axes[n].collections[0])
687 self.axes[n].collections.remove(self.axes[n].collections[0])
661 self.axes[n].set_xlim(xmin, xmax)
688 self.axes[n].set_xlim(xmin, xmax)
662 plot = self.axes[n].pcolormesh(x, y, z[n].T,
689 plot = self.axes[n].pcolormesh(x, y, z[n].T,
663 vmin=self.zmin,
690 vmin=self.zmin,
664 vmax=self.zmax,
691 vmax=self.zmax,
665 cmap=plt.get_cmap(self.colormap)
692 cmap=plt.get_cmap(self.colormap)
666 )
693 )
667 self.axes[n].set_title('{} {}'.format(self.titles[n],
694 self.axes[n].set_title('{} {}'.format(self.titles[n],
668 datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')),
695 datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')),
669 size=8)
696 size=8)
670
697
671 self.saveTime = self.min_time
698 self.saveTime = self.min_time
672
699
673
700
674 class PlotCOHData(PlotRTIData):
701 class PlotCOHData(PlotRTIData):
675
702
676 CODE = 'coh'
703 CODE = 'coh'
677
704
678 def setup(self):
705 def setup(self):
679
706
680 self.ncols = 1
707 self.ncols = 1
681 self.nrows = self.dataOut.nPairs
708 self.nrows = self.dataOut.nPairs
682 self.width = 10
709 self.width = 10
683 self.height = 2.2*self.nrows if self.nrows<6 else 12
710 self.height = 2.2*self.nrows if self.nrows<6 else 12
684 if self.nrows==1:
711 if self.nrows==1:
685 self.height += 1
712 self.height += 1
686 self.ylabel = 'Range [Km]'
713 self.ylabel = 'Range [Km]'
687 self.titles = ['{} Ch{} * Ch{}'.format(self.CODE.upper(), x[0], x[1]) for x in self.dataOut.pairsList]
714 self.titles = ['{} Ch{} * Ch{}'.format(self.CODE.upper(), x[0], x[1]) for x in self.dataOut.pairsList]
688
715
689 if self.figure is None:
716 if self.figure is None:
690 self.figure = plt.figure(figsize=(self.width, self.height),
717 self.figure = plt.figure(figsize=(self.width, self.height),
691 edgecolor='k',
718 edgecolor='k',
692 facecolor='w')
719 facecolor='w')
693 else:
720 else:
694 self.figure.clf()
721 self.figure.clf()
695 self.axes = []
722 self.axes = []
696
723
697 for n in range(self.nrows):
724 for n in range(self.nrows):
698 ax = self.figure.add_subplot(self.nrows, self.ncols, n+1)
725 ax = self.figure.add_subplot(self.nrows, self.ncols, n+1)
699 ax.firsttime = True
726 ax.firsttime = True
700 self.axes.append(ax)
727 self.axes.append(ax)
701
728
702
729
703 class PlotNoiseData(PlotData):
730 class PlotNoiseData(PlotData):
704 CODE = 'noise'
731 CODE = 'noise'
705
732
706 def setup(self):
733 def setup(self):
707
734
708 self.ncols = 1
735 self.ncols = 1
709 self.nrows = 1
736 self.nrows = 1
710 self.width = 10
737 self.width = 10
711 self.height = 3.2
738 self.height = 3.2
712 self.ylabel = 'Intensity [dB]'
739 self.ylabel = 'Intensity [dB]'
713 self.titles = ['Noise']
740 self.titles = ['Noise']
714
741
715 if self.figure is None:
742 if self.figure is None:
716 self.figure = plt.figure(figsize=(self.width, self.height),
743 self.figure = plt.figure(figsize=(self.width, self.height),
717 edgecolor='k',
744 edgecolor='k',
718 facecolor='w')
745 facecolor='w')
719 else:
746 else:
720 self.figure.clf()
747 self.figure.clf()
721 self.axes = []
748 self.axes = []
722
749
723 self.ax = self.figure.add_subplot(self.nrows, self.ncols, 1)
750 self.ax = self.figure.add_subplot(self.nrows, self.ncols, 1)
724 self.ax.firsttime = True
751 self.ax.firsttime = True
725
752
726 def plot(self):
753 def plot(self):
727
754
728 x = self.times
755 x = self.times
729 xmin = self.min_time
756 xmin = self.min_time
730 xmax = xmin+self.xrange*60*60
757 xmax = xmin+self.xrange*60*60
731 if self.ax.firsttime:
758 if self.ax.firsttime:
732 for ch in self.dataOut.channelList:
759 for ch in self.dataOut.channelList:
733 y = [self.data[self.CODE][t][ch] for t in self.times]
760 y = [self.data[self.CODE][t][ch] for t in self.times]
734 self.ax.plot(x, y, lw=1, label='Ch{}'.format(ch))
761 self.ax.plot(x, y, lw=1, label='Ch{}'.format(ch))
735 self.ax.firsttime = False
762 self.ax.firsttime = False
736 self.ax.xaxis.set_major_formatter(FuncFormatter(func))
763 self.ax.xaxis.set_major_formatter(FuncFormatter(func))
737 self.ax.xaxis.set_major_locator(LinearLocator(6))
764 self.ax.xaxis.set_major_locator(LinearLocator(6))
738 self.ax.set_ylabel(self.ylabel)
765 self.ax.set_ylabel(self.ylabel)
739 plt.legend()
766 plt.legend()
740 else:
767 else:
741 for ch in self.dataOut.channelList:
768 for ch in self.dataOut.channelList:
742 y = [self.data[self.CODE][t][ch] for t in self.times]
769 y = [self.data[self.CODE][t][ch] for t in self.times]
743 self.ax.lines[ch].set_data(x, y)
770 self.ax.lines[ch].set_data(x, y)
744
771
745 self.ax.set_xlim(xmin, xmax)
772 self.ax.set_xlim(xmin, xmax)
746 self.ax.set_ylim(min(y)-5, max(y)+5)
773 self.ax.set_ylim(min(y)-5, max(y)+5)
747 self.saveTime = self.min_time
774 self.saveTime = self.min_time
748
775
749
776
750 class PlotWindProfilerData(PlotRTIData):
777 class PlotWindProfilerData(PlotRTIData):
751
778
752 CODE = 'wind'
779 CODE = 'wind'
753 colormap = 'seismic'
780 colormap = 'seismic'
754
781
755 def setup(self):
782 def setup(self):
756 self.ncols = 1
783 self.ncols = 1
757 self.nrows = self.dataOut.data_output.shape[0]
784 self.nrows = self.dataOut.data_output.shape[0]
758 self.width = 10
785 self.width = 10
759 self.height = 2.2*self.nrows
786 self.height = 2.2*self.nrows
760 self.ylabel = 'Height [Km]'
787 self.ylabel = 'Height [Km]'
761 self.titles = ['Zonal Wind' ,'Meridional Wind', 'Vertical Wind']
788 self.titles = ['Zonal Wind' ,'Meridional Wind', 'Vertical Wind']
762 self.clabels = ['Velocity (m/s)','Velocity (m/s)','Velocity (cm/s)']
789 self.clabels = ['Velocity (m/s)','Velocity (m/s)','Velocity (cm/s)']
763 self.windFactor = [1, 1, 100]
790 self.windFactor = [1, 1, 100]
764
791
765 if self.figure is None:
792 if self.figure is None:
766 self.figure = plt.figure(figsize=(self.width, self.height),
793 self.figure = plt.figure(figsize=(self.width, self.height),
767 edgecolor='k',
794 edgecolor='k',
768 facecolor='w')
795 facecolor='w')
769 else:
796 else:
770 self.figure.clf()
797 self.figure.clf()
771 self.axes = []
798 self.axes = []
772
799
773 for n in range(self.nrows):
800 for n in range(self.nrows):
774 ax = self.figure.add_subplot(self.nrows, self.ncols, n+1)
801 ax = self.figure.add_subplot(self.nrows, self.ncols, n+1)
775 ax.firsttime = True
802 ax.firsttime = True
776 self.axes.append(ax)
803 self.axes.append(ax)
777
804
778 def plot(self):
805 def plot(self):
779
806
780 self.x = np.array(self.times)
807 self.x = np.array(self.times)
781 self.y = self.dataOut.heightList
808 self.y = self.dataOut.heightList
782 self.z = []
809 self.z = []
783
810
784 for ch in range(self.nrows):
811 for ch in range(self.nrows):
785 self.z.append([self.data['output'][t][ch] for t in self.times])
812 self.z.append([self.data['output'][t][ch] for t in self.times])
786
813
787 self.z = np.array(self.z)
814 self.z = np.array(self.z)
788 self.z = numpy.ma.masked_invalid(self.z)
815 self.z = numpy.ma.masked_invalid(self.z)
789
816
790 cmap=plt.get_cmap(self.colormap)
817 cmap=plt.get_cmap(self.colormap)
791 cmap.set_bad('black', 1.)
818 cmap.set_bad('black', 1.)
792
819
793 for n, ax in enumerate(self.axes):
820 for n, ax in enumerate(self.axes):
794 x, y, z = self.fill_gaps(*self.decimate())
821 x, y, z = self.fill_gaps(*self.decimate())
795 xmin = self.min_time
822 xmin = self.min_time
796 xmax = xmin+self.xrange*60*60
823 xmax = xmin+self.xrange*60*60
797 if ax.firsttime:
824 if ax.firsttime:
798 self.ymin = self.ymin if self.ymin else np.nanmin(self.y)
825 self.ymin = self.ymin if self.ymin else np.nanmin(self.y)
799 self.ymax = self.ymax if self.ymax else np.nanmax(self.y)
826 self.ymax = self.ymax if self.ymax else np.nanmax(self.y)
800 self.zmax = self.zmax if self.zmax else numpy.nanmax(abs(self.z[:-1, :]))
827 self.zmax = self.zmax if self.zmax else numpy.nanmax(abs(self.z[:-1, :]))
801 self.zmin = self.zmin if self.zmin else -self.zmax
828 self.zmin = self.zmin if self.zmin else -self.zmax
802
829
803 plot = ax.pcolormesh(x, y, z[n].T*self.windFactor[n],
830 plot = ax.pcolormesh(x, y, z[n].T*self.windFactor[n],
804 vmin=self.zmin,
831 vmin=self.zmin,
805 vmax=self.zmax,
832 vmax=self.zmax,
806 cmap=cmap
833 cmap=cmap
807 )
834 )
808 divider = make_axes_locatable(ax)
835 divider = make_axes_locatable(ax)
809 cax = divider.new_horizontal(size='2%', pad=0.05)
836 cax = divider.new_horizontal(size='2%', pad=0.05)
810 self.figure.add_axes(cax)
837 self.figure.add_axes(cax)
811 cb = plt.colorbar(plot, cax)
838 cb = plt.colorbar(plot, cax)
812 cb.set_label(self.clabels[n])
839 cb.set_label(self.clabels[n])
813 ax.set_ylim(self.ymin, self.ymax)
840 ax.set_ylim(self.ymin, self.ymax)
814
841
815 ax.xaxis.set_major_formatter(FuncFormatter(func))
842 ax.xaxis.set_major_formatter(FuncFormatter(func))
816 ax.xaxis.set_major_locator(LinearLocator(6))
843 ax.xaxis.set_major_locator(LinearLocator(6))
817
844
818 ax.set_ylabel(self.ylabel)
845 ax.set_ylabel(self.ylabel)
819
846
820 ax.set_xlim(xmin, xmax)
847 ax.set_xlim(xmin, xmax)
821 ax.firsttime = False
848 ax.firsttime = False
822 else:
849 else:
823 ax.collections.remove(ax.collections[0])
850 ax.collections.remove(ax.collections[0])
824 ax.set_xlim(xmin, xmax)
851 ax.set_xlim(xmin, xmax)
825 plot = ax.pcolormesh(x, y, z[n].T*self.windFactor[n],
852 plot = ax.pcolormesh(x, y, z[n].T*self.windFactor[n],
826 vmin=self.zmin,
853 vmin=self.zmin,
827 vmax=self.zmax,
854 vmax=self.zmax,
828 cmap=plt.get_cmap(self.colormap)
855 cmap=plt.get_cmap(self.colormap)
829 )
856 )
830 ax.set_title('{} {}'.format(self.titles[n],
857 ax.set_title('{} {}'.format(self.titles[n],
831 datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')),
858 datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')),
832 size=8)
859 size=8)
833
860
834 self.saveTime = self.min_time
861 self.saveTime = self.min_time
835
862
836
863
837 class PlotSNRData(PlotRTIData):
864 class PlotSNRData(PlotRTIData):
838 CODE = 'snr'
865 CODE = 'snr'
839 colormap = 'jet'
866 colormap = 'jet'
840
867
841 class PlotDOPData(PlotRTIData):
868 class PlotDOPData(PlotRTIData):
842 CODE = 'dop'
869 CODE = 'dop'
843 colormap = 'jet'
870 colormap = 'jet'
844
871
845
872
846 class PlotPHASEData(PlotCOHData):
873 class PlotPHASEData(PlotCOHData):
847 CODE = 'phase'
874 CODE = 'phase'
848 colormap = 'seismic'
875 colormap = 'seismic'
849
876
850
877
851 class PlotSkyMapData(PlotData):
878 class PlotSkyMapData(PlotData):
852
879
853 CODE = 'met'
880 CODE = 'met'
854
881
855 def setup(self):
882 def setup(self):
856
883
857 self.ncols = 1
884 self.ncols = 1
858 self.nrows = 1
885 self.nrows = 1
859 self.width = 7.2
886 self.width = 7.2
860 self.height = 7.2
887 self.height = 7.2
861
888
862 self.xlabel = 'Zonal Zenith Angle (deg)'
889 self.xlabel = 'Zonal Zenith Angle (deg)'
863 self.ylabel = 'Meridional Zenith Angle (deg)'
890 self.ylabel = 'Meridional Zenith Angle (deg)'
864
891
865 if self.figure is None:
892 if self.figure is None:
866 self.figure = plt.figure(figsize=(self.width, self.height),
893 self.figure = plt.figure(figsize=(self.width, self.height),
867 edgecolor='k',
894 edgecolor='k',
868 facecolor='w')
895 facecolor='w')
869 else:
896 else:
870 self.figure.clf()
897 self.figure.clf()
871
898
872 self.ax = plt.subplot2grid((self.nrows, self.ncols), (0, 0), 1, 1, polar=True)
899 self.ax = plt.subplot2grid((self.nrows, self.ncols), (0, 0), 1, 1, polar=True)
873 self.ax.firsttime = True
900 self.ax.firsttime = True
874
901
875
902
876 def plot(self):
903 def plot(self):
877
904
878 arrayParameters = np.concatenate([self.data['param'][t] for t in self.times])
905 arrayParameters = np.concatenate([self.data['param'][t] for t in self.times])
879 error = arrayParameters[:,-1]
906 error = arrayParameters[:,-1]
880 indValid = numpy.where(error == 0)[0]
907 indValid = numpy.where(error == 0)[0]
881 finalMeteor = arrayParameters[indValid,:]
908 finalMeteor = arrayParameters[indValid,:]
882 finalAzimuth = finalMeteor[:,3]
909 finalAzimuth = finalMeteor[:,3]
883 finalZenith = finalMeteor[:,4]
910 finalZenith = finalMeteor[:,4]
884
911
885 x = finalAzimuth*numpy.pi/180
912 x = finalAzimuth*numpy.pi/180
886 y = finalZenith
913 y = finalZenith
887
914
888 if self.ax.firsttime:
915 if self.ax.firsttime:
889 self.ax.plot = self.ax.plot(x, y, 'bo', markersize=5)[0]
916 self.ax.plot = self.ax.plot(x, y, 'bo', markersize=5)[0]
890 self.ax.set_ylim(0,90)
917 self.ax.set_ylim(0,90)
891 self.ax.set_yticks(numpy.arange(0,90,20))
918 self.ax.set_yticks(numpy.arange(0,90,20))
892 self.ax.set_xlabel(self.xlabel)
919 self.ax.set_xlabel(self.xlabel)
893 self.ax.set_ylabel(self.ylabel)
920 self.ax.set_ylabel(self.ylabel)
894 self.ax.yaxis.labelpad = 40
921 self.ax.yaxis.labelpad = 40
895 self.ax.firsttime = False
922 self.ax.firsttime = False
896 else:
923 else:
897 self.ax.plot.set_data(x, y)
924 self.ax.plot.set_data(x, y)
898
925
899
926
900 dt1 = datetime.datetime.fromtimestamp(self.min_time).strftime('%y/%m/%d %H:%M:%S')
927 dt1 = datetime.datetime.fromtimestamp(self.min_time).strftime('%y/%m/%d %H:%M:%S')
901 dt2 = datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')
928 dt2 = datetime.datetime.fromtimestamp(self.max_time).strftime('%y/%m/%d %H:%M:%S')
902 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
929 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
903 dt2,
930 dt2,
904 len(x))
931 len(x))
905 self.ax.set_title(title, size=8)
932 self.ax.set_title(title, size=8)
906
933
907 self.saveTime = self.max_time
934 self.saveTime = self.max_time
@@ -1,1 +1,1
1 <Project description="HF_EXAMPLE" id="191" name="test01"><ReadUnit datatype="SpectraReader" id="1911" inputId="0" name="SpectraReader"><Operation id="19111" name="run" priority="1" type="self"><Parameter format="str" id="191111" name="datatype" value="SpectraReader" /><Parameter format="str" id="191112" name="path" value="/media/ci-81/Huancayo/DATA/hfradar_2016/pdata/sp1_f1" /><Parameter format="date" id="191113" name="startDate" value="2016/04/27" /><Parameter format="date" id="191114" name="endDate" value="2016/04/27" /><Parameter format="time" id="191115" name="startTime" value="00:00:00" /><Parameter format="time" id="191116" name="endTime" value="23:59:59" /><Parameter format="int" id="191118" name="cursor" value="0" /><Parameter format="int" id="191119" name="skip" value="0" /><Parameter format="int" id="191120" name="delay" value="10" /><Parameter format="int" id="191121" name="walk" value="1" /><Parameter format="int" id="191122" name="online" value="0" /></Operation></ReadUnit><ProcUnit datatype="ParametersProc" id="1913" inputId="1911" name="ParametersProc"><Operation id="19131" name="run" priority="1" type="self" /><Operation id="19132" name="SpectralMoments" priority="2" type="other" /><Operation id="19133" name="PublishData" priority="3" type="other"><Parameter format="int" id="191331" name="zeromq" value="1" /></Operation></ProcUnit><ProcUnit datatype="Spectra" id="1912" inputId="1911" name="SpectraProc"><Operation id="19121" name="run" priority="1" type="self" /><Operation id="19122" name="removeInterference" priority="2" type="self" /></ProcUnit></Project> No newline at end of file
1 <Project description="HF_EXAMPLE" id="191" name="test01"><ReadUnit datatype="SpectraReader" id="1911" inputId="0" name="SpectraReader"><Operation id="19111" name="run" priority="1" type="self"><Parameter format="str" id="191111" name="datatype" value="SpectraReader" /><Parameter format="str" id="191112" name="path" value="/media/ci-81/Huancayo/DATA/hfradar_2016/pdata/sp1_f1" /><Parameter format="date" id="191113" name="startDate" value="2016/04/24" /><Parameter format="date" id="191114" name="endDate" value="2016/04/24" /><Parameter format="time" id="191115" name="startTime" value="00:00:00" /><Parameter format="time" id="191116" name="endTime" value="23:59:59" /><Parameter format="int" id="191118" name="cursor" value="8" /><Parameter format="int" id="191119" name="skip" value="18" /><Parameter format="int" id="191120" name="delay" value="10" /><Parameter format="int" id="191121" name="walk" value="1" /><Parameter format="int" id="191122" name="online" value="0" /></Operation></ReadUnit><ProcUnit datatype="ParametersProc" id="1913" inputId="1911" name="ParametersProc"><Operation id="19131" name="run" priority="1" type="self" /><Operation id="19132" name="SpectralMoments" priority="2" type="other" /><Operation id="19133" name="PublishData" priority="3" type="other"><Parameter format="int" id="191331" name="zeromq" value="1" /></Operation></ProcUnit><ProcUnit datatype="Spectra" id="1912" inputId="1911" name="SpectraProc"><Operation id="19121" name="run" priority="1" type="self" /><Operation id="19122" name="removeInterference" priority="2" type="self" /></ProcUnit></Project> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now