##// END OF EJS Templates
Fix bugs in SpectraCutPlot, GenericRTIPlot and saving when using throttle
jespinoza -
r1359:7cde62c34a28
parent child
Show More
@@ -1,688 +1,691
1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
2 # All rights reserved.
2 # All rights reserved.
3 #
3 #
4 # Distributed under the terms of the BSD 3-clause license.
4 # Distributed under the terms of the BSD 3-clause license.
5 """Base class to create plot operations
5 """Base class to create plot operations
6
6
7 """
7 """
8
8
9 import os
9 import os
10 import sys
10 import sys
11 import zmq
11 import zmq
12 import time
12 import time
13 import numpy
13 import numpy
14 import datetime
14 import datetime
15 from collections import deque
15 from collections import deque
16 from functools import wraps
16 from functools import wraps
17 from threading import Thread
17 from threading import Thread
18 import matplotlib
18 import matplotlib
19
19
20 if 'BACKEND' in os.environ:
20 if 'BACKEND' in os.environ:
21 matplotlib.use(os.environ['BACKEND'])
21 matplotlib.use(os.environ['BACKEND'])
22 elif 'linux' in sys.platform:
22 elif 'linux' in sys.platform:
23 matplotlib.use("TkAgg")
23 matplotlib.use("TkAgg")
24 elif 'darwin' in sys.platform:
24 elif 'darwin' in sys.platform:
25 matplotlib.use('MacOSX')
25 matplotlib.use('MacOSX')
26 else:
26 else:
27 from schainpy.utils import log
27 from schainpy.utils import log
28 log.warning('Using default Backend="Agg"', 'INFO')
28 log.warning('Using default Backend="Agg"', 'INFO')
29 matplotlib.use('Agg')
29 matplotlib.use('Agg')
30
30
31 import matplotlib.pyplot as plt
31 import matplotlib.pyplot as plt
32 from matplotlib.patches import Polygon
32 from matplotlib.patches import Polygon
33 from mpl_toolkits.axes_grid1 import make_axes_locatable
33 from mpl_toolkits.axes_grid1 import make_axes_locatable
34 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
34 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
35
35
36 from schainpy.model.data.jrodata import PlotterData
36 from schainpy.model.data.jrodata import PlotterData
37 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
37 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
38 from schainpy.utils import log
38 from schainpy.utils import log
39
39
40 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
40 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
41 blu_values = matplotlib.pyplot.get_cmap(
41 blu_values = matplotlib.pyplot.get_cmap(
42 'seismic_r', 20)(numpy.arange(20))[10:15]
42 'seismic_r', 20)(numpy.arange(20))[10:15]
43 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
43 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
44 'jro', numpy.vstack((blu_values, jet_values)))
44 'jro', numpy.vstack((blu_values, jet_values)))
45 matplotlib.pyplot.register_cmap(cmap=ncmap)
45 matplotlib.pyplot.register_cmap(cmap=ncmap)
46
46
47 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
47 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
48 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
48 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
49
49
50 EARTH_RADIUS = 6.3710e3
50 EARTH_RADIUS = 6.3710e3
51
51
52 def ll2xy(lat1, lon1, lat2, lon2):
52 def ll2xy(lat1, lon1, lat2, lon2):
53
53
54 p = 0.017453292519943295
54 p = 0.017453292519943295
55 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
55 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
56 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
56 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
57 r = 12742 * numpy.arcsin(numpy.sqrt(a))
57 r = 12742 * numpy.arcsin(numpy.sqrt(a))
58 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
58 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
59 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
59 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
60 theta = -theta + numpy.pi/2
60 theta = -theta + numpy.pi/2
61 return r*numpy.cos(theta), r*numpy.sin(theta)
61 return r*numpy.cos(theta), r*numpy.sin(theta)
62
62
63
63
64 def km2deg(km):
64 def km2deg(km):
65 '''
65 '''
66 Convert distance in km to degrees
66 Convert distance in km to degrees
67 '''
67 '''
68
68
69 return numpy.rad2deg(km/EARTH_RADIUS)
69 return numpy.rad2deg(km/EARTH_RADIUS)
70
70
71
71
72 def figpause(interval):
72 def figpause(interval):
73 backend = plt.rcParams['backend']
73 backend = plt.rcParams['backend']
74 if backend in matplotlib.rcsetup.interactive_bk:
74 if backend in matplotlib.rcsetup.interactive_bk:
75 figManager = matplotlib._pylab_helpers.Gcf.get_active()
75 figManager = matplotlib._pylab_helpers.Gcf.get_active()
76 if figManager is not None:
76 if figManager is not None:
77 canvas = figManager.canvas
77 canvas = figManager.canvas
78 if canvas.figure.stale:
78 if canvas.figure.stale:
79 canvas.draw()
79 canvas.draw()
80 try:
80 try:
81 canvas.start_event_loop(interval)
81 canvas.start_event_loop(interval)
82 except:
82 except:
83 pass
83 pass
84 return
84 return
85
85
86 def popup(message):
86 def popup(message):
87 '''
87 '''
88 '''
88 '''
89
89
90 fig = plt.figure(figsize=(12, 8), facecolor='r')
90 fig = plt.figure(figsize=(12, 8), facecolor='r')
91 text = '\n'.join([s.strip() for s in message.split(':')])
91 text = '\n'.join([s.strip() for s in message.split(':')])
92 fig.text(0.01, 0.5, text, ha='left', va='center',
92 fig.text(0.01, 0.5, text, ha='left', va='center',
93 size='20', weight='heavy', color='w')
93 size='20', weight='heavy', color='w')
94 fig.show()
94 fig.show()
95 figpause(1000)
95 figpause(1000)
96
96
97
97
98 class Throttle(object):
98 class Throttle(object):
99 '''
99 '''
100 Decorator that prevents a function from being called more than once every
100 Decorator that prevents a function from being called more than once every
101 time period.
101 time period.
102 To create a function that cannot be called more than once a minute, but
102 To create a function that cannot be called more than once a minute, but
103 will sleep until it can be called:
103 will sleep until it can be called:
104 @Throttle(minutes=1)
104 @Throttle(minutes=1)
105 def foo():
105 def foo():
106 pass
106 pass
107
107
108 for i in range(10):
108 for i in range(10):
109 foo()
109 foo()
110 print "This function has run %s times." % i
110 print "This function has run %s times." % i
111 '''
111 '''
112
112
113 def __init__(self, seconds=0, minutes=0, hours=0):
113 def __init__(self, seconds=0, minutes=0, hours=0):
114 self.throttle_period = datetime.timedelta(
114 self.throttle_period = datetime.timedelta(
115 seconds=seconds, minutes=minutes, hours=hours
115 seconds=seconds, minutes=minutes, hours=hours
116 )
116 )
117
117
118 self.time_of_last_call = datetime.datetime.min
118 self.time_of_last_call = datetime.datetime.min
119
119
120 def __call__(self, fn):
120 def __call__(self, fn):
121 @wraps(fn)
121 @wraps(fn)
122 def wrapper(*args, **kwargs):
122 def wrapper(*args, **kwargs):
123 coerce = kwargs.pop('coerce', None)
123 coerce = kwargs.pop('coerce', None)
124 if coerce:
124 if coerce:
125 self.time_of_last_call = datetime.datetime.now()
125 self.time_of_last_call = datetime.datetime.now()
126 return fn(*args, **kwargs)
126 return fn(*args, **kwargs)
127 else:
127 else:
128 now = datetime.datetime.now()
128 now = datetime.datetime.now()
129 time_since_last_call = now - self.time_of_last_call
129 time_since_last_call = now - self.time_of_last_call
130 time_left = self.throttle_period - time_since_last_call
130 time_left = self.throttle_period - time_since_last_call
131
131
132 if time_left > datetime.timedelta(seconds=0):
132 if time_left > datetime.timedelta(seconds=0):
133 return
133 return
134
134
135 self.time_of_last_call = datetime.datetime.now()
135 self.time_of_last_call = datetime.datetime.now()
136 return fn(*args, **kwargs)
136 return fn(*args, **kwargs)
137
137
138 return wrapper
138 return wrapper
139
139
140 def apply_throttle(value):
140 def apply_throttle(value):
141
141
142 @Throttle(seconds=value)
142 @Throttle(seconds=value)
143 def fnThrottled(fn):
143 def fnThrottled(fn):
144 fn()
144 fn()
145
145
146 return fnThrottled
146 return fnThrottled
147
147
148
148
149 @MPDecorator
149 @MPDecorator
150 class Plot(Operation):
150 class Plot(Operation):
151 """Base class for Schain plotting operations
151 """Base class for Schain plotting operations
152
152
153 This class should never be use directtly you must subclass a new operation,
153 This class should never be use directtly you must subclass a new operation,
154 children classes must be defined as follow:
154 children classes must be defined as follow:
155
155
156 ExamplePlot(Plot):
156 ExamplePlot(Plot):
157
157
158 CODE = 'code'
158 CODE = 'code'
159 colormap = 'jet'
159 colormap = 'jet'
160 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
160 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
161
161
162 def setup(self):
162 def setup(self):
163 pass
163 pass
164
164
165 def plot(self):
165 def plot(self):
166 pass
166 pass
167
167
168 """
168 """
169
169
170 CODE = 'Figure'
170 CODE = 'Figure'
171 colormap = 'jet'
171 colormap = 'jet'
172 bgcolor = 'white'
172 bgcolor = 'white'
173 buffering = True
173 buffering = True
174 __missing = 1E30
174 __missing = 1E30
175
175
176 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
176 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
177 'showprofile']
177 'showprofile']
178
178
179 def __init__(self):
179 def __init__(self):
180
180
181 Operation.__init__(self)
181 Operation.__init__(self)
182 self.isConfig = False
182 self.isConfig = False
183 self.isPlotConfig = False
183 self.isPlotConfig = False
184 self.save_time = 0
184 self.save_time = 0
185 self.sender_time = 0
185 self.sender_time = 0
186 self.data = None
186 self.data = None
187 self.firsttime = True
187 self.firsttime = True
188 self.sender_queue = deque(maxlen=10)
188 self.sender_queue = deque(maxlen=10)
189 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
189 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
190
190
191 def __fmtTime(self, x, pos):
191 def __fmtTime(self, x, pos):
192 '''
192 '''
193 '''
193 '''
194
194
195 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
195 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
196
196
197 def __setup(self, **kwargs):
197 def __setup(self, **kwargs):
198 '''
198 '''
199 Initialize variables
199 Initialize variables
200 '''
200 '''
201
201
202 self.figures = []
202 self.figures = []
203 self.axes = []
203 self.axes = []
204 self.cb_axes = []
204 self.cb_axes = []
205 self.localtime = kwargs.pop('localtime', True)
205 self.localtime = kwargs.pop('localtime', True)
206 self.show = kwargs.get('show', True)
206 self.show = kwargs.get('show', True)
207 self.save = kwargs.get('save', False)
207 self.save = kwargs.get('save', False)
208 self.save_period = kwargs.get('save_period', 0)
208 self.save_period = kwargs.get('save_period', 0)
209 self.colormap = kwargs.get('colormap', self.colormap)
209 self.colormap = kwargs.get('colormap', self.colormap)
210 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
210 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
211 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
211 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
212 self.colormaps = kwargs.get('colormaps', None)
212 self.colormaps = kwargs.get('colormaps', None)
213 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
213 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
214 self.showprofile = kwargs.get('showprofile', False)
214 self.showprofile = kwargs.get('showprofile', False)
215 self.title = kwargs.get('wintitle', self.CODE.upper())
215 self.title = kwargs.get('wintitle', self.CODE.upper())
216 self.cb_label = kwargs.get('cb_label', None)
216 self.cb_label = kwargs.get('cb_label', None)
217 self.cb_labels = kwargs.get('cb_labels', None)
217 self.cb_labels = kwargs.get('cb_labels', None)
218 self.labels = kwargs.get('labels', None)
218 self.labels = kwargs.get('labels', None)
219 self.xaxis = kwargs.get('xaxis', 'frequency')
219 self.xaxis = kwargs.get('xaxis', 'frequency')
220 self.zmin = kwargs.get('zmin', None)
220 self.zmin = kwargs.get('zmin', None)
221 self.zmax = kwargs.get('zmax', None)
221 self.zmax = kwargs.get('zmax', None)
222 self.zlimits = kwargs.get('zlimits', None)
222 self.zlimits = kwargs.get('zlimits', None)
223 self.xmin = kwargs.get('xmin', None)
223 self.xmin = kwargs.get('xmin', None)
224 self.xmax = kwargs.get('xmax', None)
224 self.xmax = kwargs.get('xmax', None)
225 self.xrange = kwargs.get('xrange', 12)
225 self.xrange = kwargs.get('xrange', 12)
226 self.xscale = kwargs.get('xscale', None)
226 self.xscale = kwargs.get('xscale', None)
227 self.ymin = kwargs.get('ymin', None)
227 self.ymin = kwargs.get('ymin', None)
228 self.ymax = kwargs.get('ymax', None)
228 self.ymax = kwargs.get('ymax', None)
229 self.yscale = kwargs.get('yscale', None)
229 self.yscale = kwargs.get('yscale', None)
230 self.xlabel = kwargs.get('xlabel', None)
230 self.xlabel = kwargs.get('xlabel', None)
231 self.attr_time = kwargs.get('attr_time', 'utctime')
231 self.attr_time = kwargs.get('attr_time', 'utctime')
232 self.attr_data = kwargs.get('attr_data', 'data_param')
232 self.attr_data = kwargs.get('attr_data', 'data_param')
233 self.decimation = kwargs.get('decimation', None)
233 self.decimation = kwargs.get('decimation', None)
234 self.showSNR = kwargs.get('showSNR', False)
235 self.oneFigure = kwargs.get('oneFigure', True)
234 self.oneFigure = kwargs.get('oneFigure', True)
236 self.width = kwargs.get('width', None)
235 self.width = kwargs.get('width', None)
237 self.height = kwargs.get('height', None)
236 self.height = kwargs.get('height', None)
238 self.colorbar = kwargs.get('colorbar', True)
237 self.colorbar = kwargs.get('colorbar', True)
239 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
238 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
240 self.channels = kwargs.get('channels', None)
239 self.channels = kwargs.get('channels', None)
241 self.titles = kwargs.get('titles', [])
240 self.titles = kwargs.get('titles', [])
242 self.polar = False
241 self.polar = False
243 self.type = kwargs.get('type', 'iq')
242 self.type = kwargs.get('type', 'iq')
244 self.grid = kwargs.get('grid', False)
243 self.grid = kwargs.get('grid', False)
245 self.pause = kwargs.get('pause', False)
244 self.pause = kwargs.get('pause', False)
246 self.save_code = kwargs.get('save_code', self.CODE)
245 self.save_code = kwargs.get('save_code', self.CODE)
247 self.throttle = kwargs.get('throttle', 0)
246 self.throttle = kwargs.get('throttle', 0)
248 self.exp_code = kwargs.get('exp_code', None)
247 self.exp_code = kwargs.get('exp_code', None)
249 self.server = kwargs.get('server', False)
248 self.server = kwargs.get('server', False)
250 self.sender_period = kwargs.get('sender_period', 60)
249 self.sender_period = kwargs.get('sender_period', 60)
251 self.tag = kwargs.get('tag', '')
250 self.tag = kwargs.get('tag', '')
252 self.height_index = kwargs.get('height_index', None)
251 self.height_index = kwargs.get('height_index', None)
253 self.__throttle_plot = apply_throttle(self.throttle)
252 self.__throttle_plot = apply_throttle(self.throttle)
254 code = self.attr_data if self.attr_data else self.CODE
253 code = self.attr_data if self.attr_data else self.CODE
255 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
254 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
256
255
257 if self.server:
256 if self.server:
258 if not self.server.startswith('tcp://'):
257 if not self.server.startswith('tcp://'):
259 self.server = 'tcp://{}'.format(self.server)
258 self.server = 'tcp://{}'.format(self.server)
260 log.success(
259 log.success(
261 'Sending to server: {}'.format(self.server),
260 'Sending to server: {}'.format(self.server),
262 self.name
261 self.name
263 )
262 )
264
263
264 if isinstance(self.attr_data, str):
265 self.attr_data = [self.attr_data]
266
265 def __setup_plot(self):
267 def __setup_plot(self):
266 '''
268 '''
267 Common setup for all figures, here figures and axes are created
269 Common setup for all figures, here figures and axes are created
268 '''
270 '''
269
271
270 self.setup()
272 self.setup()
271
273
272 self.time_label = 'LT' if self.localtime else 'UTC'
274 self.time_label = 'LT' if self.localtime else 'UTC'
273
275
274 if self.width is None:
276 if self.width is None:
275 self.width = 8
277 self.width = 8
276
278
277 self.figures = []
279 self.figures = []
278 self.axes = []
280 self.axes = []
279 self.cb_axes = []
281 self.cb_axes = []
280 self.pf_axes = []
282 self.pf_axes = []
281 self.cmaps = []
283 self.cmaps = []
282
284
283 size = '15%' if self.ncols == 1 else '30%'
285 size = '15%' if self.ncols == 1 else '30%'
284 pad = '4%' if self.ncols == 1 else '8%'
286 pad = '4%' if self.ncols == 1 else '8%'
285
287
286 if self.oneFigure:
288 if self.oneFigure:
287 if self.height is None:
289 if self.height is None:
288 self.height = 1.4 * self.nrows + 1
290 self.height = 1.4 * self.nrows + 1
289 fig = plt.figure(figsize=(self.width, self.height),
291 fig = plt.figure(figsize=(self.width, self.height),
290 edgecolor='k',
292 edgecolor='k',
291 facecolor='w')
293 facecolor='w')
292 self.figures.append(fig)
294 self.figures.append(fig)
293 for n in range(self.nplots):
295 for n in range(self.nplots):
294 ax = fig.add_subplot(self.nrows, self.ncols,
296 ax = fig.add_subplot(self.nrows, self.ncols,
295 n + 1, polar=self.polar)
297 n + 1, polar=self.polar)
296 ax.tick_params(labelsize=8)
298 ax.tick_params(labelsize=8)
297 ax.firsttime = True
299 ax.firsttime = True
298 ax.index = 0
300 ax.index = 0
299 ax.press = None
301 ax.press = None
300 self.axes.append(ax)
302 self.axes.append(ax)
301 if self.showprofile:
303 if self.showprofile:
302 cax = self.__add_axes(ax, size=size, pad=pad)
304 cax = self.__add_axes(ax, size=size, pad=pad)
303 cax.tick_params(labelsize=8)
305 cax.tick_params(labelsize=8)
304 self.pf_axes.append(cax)
306 self.pf_axes.append(cax)
305 else:
307 else:
306 if self.height is None:
308 if self.height is None:
307 self.height = 3
309 self.height = 3
308 for n in range(self.nplots):
310 for n in range(self.nplots):
309 fig = plt.figure(figsize=(self.width, self.height),
311 fig = plt.figure(figsize=(self.width, self.height),
310 edgecolor='k',
312 edgecolor='k',
311 facecolor='w')
313 facecolor='w')
312 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
314 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
313 ax.tick_params(labelsize=8)
315 ax.tick_params(labelsize=8)
314 ax.firsttime = True
316 ax.firsttime = True
315 ax.index = 0
317 ax.index = 0
316 ax.press = None
318 ax.press = None
317 self.figures.append(fig)
319 self.figures.append(fig)
318 self.axes.append(ax)
320 self.axes.append(ax)
319 if self.showprofile:
321 if self.showprofile:
320 cax = self.__add_axes(ax, size=size, pad=pad)
322 cax = self.__add_axes(ax, size=size, pad=pad)
321 cax.tick_params(labelsize=8)
323 cax.tick_params(labelsize=8)
322 self.pf_axes.append(cax)
324 self.pf_axes.append(cax)
323
325
324 for n in range(self.nrows):
326 for n in range(self.nrows):
327 print(self.nrows)
325 if self.colormaps is not None:
328 if self.colormaps is not None:
326 cmap = plt.get_cmap(self.colormaps[n])
329 cmap = plt.get_cmap(self.colormaps[n])
327 else:
330 else:
328 cmap = plt.get_cmap(self.colormap)
331 cmap = plt.get_cmap(self.colormap)
329 cmap.set_bad(self.bgcolor, 1.)
332 cmap.set_bad(self.bgcolor, 1.)
330 self.cmaps.append(cmap)
333 self.cmaps.append(cmap)
331
334
332 def __add_axes(self, ax, size='30%', pad='8%'):
335 def __add_axes(self, ax, size='30%', pad='8%'):
333 '''
336 '''
334 Add new axes to the given figure
337 Add new axes to the given figure
335 '''
338 '''
336 divider = make_axes_locatable(ax)
339 divider = make_axes_locatable(ax)
337 nax = divider.new_horizontal(size=size, pad=pad)
340 nax = divider.new_horizontal(size=size, pad=pad)
338 ax.figure.add_axes(nax)
341 ax.figure.add_axes(nax)
339 return nax
342 return nax
340
343
341 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
344 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
342 '''
345 '''
343 Create a masked array for missing data
346 Create a masked array for missing data
344 '''
347 '''
345 if x_buffer.shape[0] < 2:
348 if x_buffer.shape[0] < 2:
346 return x_buffer, y_buffer, z_buffer
349 return x_buffer, y_buffer, z_buffer
347
350
348 deltas = x_buffer[1:] - x_buffer[0:-1]
351 deltas = x_buffer[1:] - x_buffer[0:-1]
349 x_median = numpy.median(deltas)
352 x_median = numpy.median(deltas)
350
353
351 index = numpy.where(deltas > 5 * x_median)
354 index = numpy.where(deltas > 5 * x_median)
352
355
353 if len(index[0]) != 0:
356 if len(index[0]) != 0:
354 z_buffer[::, index[0], ::] = self.__missing
357 z_buffer[::, index[0], ::] = self.__missing
355 z_buffer = numpy.ma.masked_inside(z_buffer,
358 z_buffer = numpy.ma.masked_inside(z_buffer,
356 0.99 * self.__missing,
359 0.99 * self.__missing,
357 1.01 * self.__missing)
360 1.01 * self.__missing)
358
361
359 return x_buffer, y_buffer, z_buffer
362 return x_buffer, y_buffer, z_buffer
360
363
361 def decimate(self):
364 def decimate(self):
362
365
363 # dx = int(len(self.x)/self.__MAXNUMX) + 1
366 # dx = int(len(self.x)/self.__MAXNUMX) + 1
364 dy = int(len(self.y) / self.decimation) + 1
367 dy = int(len(self.y) / self.decimation) + 1
365
368
366 # x = self.x[::dx]
369 # x = self.x[::dx]
367 x = self.x
370 x = self.x
368 y = self.y[::dy]
371 y = self.y[::dy]
369 z = self.z[::, ::, ::dy]
372 z = self.z[::, ::, ::dy]
370
373
371 return x, y, z
374 return x, y, z
372
375
373 def format(self):
376 def format(self):
374 '''
377 '''
375 Set min and max values, labels, ticks and titles
378 Set min and max values, labels, ticks and titles
376 '''
379 '''
377
380
378 for n, ax in enumerate(self.axes):
381 for n, ax in enumerate(self.axes):
379 if ax.firsttime:
382 if ax.firsttime:
380 if self.xaxis != 'time':
383 if self.xaxis != 'time':
381 xmin = self.xmin
384 xmin = self.xmin
382 xmax = self.xmax
385 xmax = self.xmax
383 else:
386 else:
384 xmin = self.tmin
387 xmin = self.tmin
385 xmax = self.tmin + self.xrange*60*60
388 xmax = self.tmin + self.xrange*60*60
386 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
389 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
387 ax.xaxis.set_major_locator(LinearLocator(9))
390 ax.xaxis.set_major_locator(LinearLocator(9))
388 ymin = self.ymin if self.ymin is not None else numpy.nanmin(self.y[numpy.isfinite(self.y)])
391 ymin = self.ymin if self.ymin is not None else numpy.nanmin(self.y[numpy.isfinite(self.y)])
389 ymax = self.ymax if self.ymax is not None else numpy.nanmax(self.y[numpy.isfinite(self.y)])
392 ymax = self.ymax if self.ymax is not None else numpy.nanmax(self.y[numpy.isfinite(self.y)])
390 ax.set_facecolor(self.bgcolor)
393 ax.set_facecolor(self.bgcolor)
391 if self.xscale:
394 if self.xscale:
392 ax.xaxis.set_major_formatter(FuncFormatter(
395 ax.xaxis.set_major_formatter(FuncFormatter(
393 lambda x, pos: '{0:g}'.format(x*self.xscale)))
396 lambda x, pos: '{0:g}'.format(x*self.xscale)))
394 if self.yscale:
397 if self.yscale:
395 ax.yaxis.set_major_formatter(FuncFormatter(
398 ax.yaxis.set_major_formatter(FuncFormatter(
396 lambda x, pos: '{0:g}'.format(x*self.yscale)))
399 lambda x, pos: '{0:g}'.format(x*self.yscale)))
397 if self.xlabel is not None:
400 if self.xlabel is not None:
398 ax.set_xlabel(self.xlabel)
401 ax.set_xlabel(self.xlabel)
399 if self.ylabel is not None:
402 if self.ylabel is not None:
400 ax.set_ylabel(self.ylabel)
403 ax.set_ylabel(self.ylabel)
401 if self.showprofile:
404 if self.showprofile:
402 self.pf_axes[n].set_ylim(ymin, ymax)
405 self.pf_axes[n].set_ylim(ymin, ymax)
403 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
406 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
404 self.pf_axes[n].set_xlabel('dB')
407 self.pf_axes[n].set_xlabel('dB')
405 self.pf_axes[n].grid(b=True, axis='x')
408 self.pf_axes[n].grid(b=True, axis='x')
406 [tick.set_visible(False)
409 [tick.set_visible(False)
407 for tick in self.pf_axes[n].get_yticklabels()]
410 for tick in self.pf_axes[n].get_yticklabels()]
408 if self.colorbar:
411 if self.colorbar:
409 ax.cbar = plt.colorbar(
412 ax.cbar = plt.colorbar(
410 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
413 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
411 ax.cbar.ax.tick_params(labelsize=8)
414 ax.cbar.ax.tick_params(labelsize=8)
412 ax.cbar.ax.press = None
415 ax.cbar.ax.press = None
413 if self.cb_label:
416 if self.cb_label:
414 ax.cbar.set_label(self.cb_label, size=8)
417 ax.cbar.set_label(self.cb_label, size=8)
415 elif self.cb_labels:
418 elif self.cb_labels:
416 ax.cbar.set_label(self.cb_labels[n], size=8)
419 ax.cbar.set_label(self.cb_labels[n], size=8)
417 else:
420 else:
418 ax.cbar = None
421 ax.cbar = None
419 ax.set_xlim(xmin, xmax)
422 ax.set_xlim(xmin, xmax)
420 ax.set_ylim(ymin, ymax)
423 ax.set_ylim(ymin, ymax)
421 ax.firsttime = False
424 ax.firsttime = False
422 if self.grid:
425 if self.grid:
423 ax.grid(True)
426 ax.grid(True)
424 if not self.polar:
427 if not self.polar:
425 ax.set_title('{} {} {}'.format(
428 ax.set_title('{} {} {}'.format(
426 self.titles[n],
429 self.titles[n],
427 self.getDateTime(self.data.max_time).strftime(
430 self.getDateTime(self.data.max_time).strftime(
428 '%Y-%m-%d %H:%M:%S'),
431 '%Y-%m-%d %H:%M:%S'),
429 self.time_label),
432 self.time_label),
430 size=8)
433 size=8)
431 else:
434 else:
432 ax.set_title('{}'.format(self.titles[n]), size=8)
435 ax.set_title('{}'.format(self.titles[n]), size=8)
433 ax.set_ylim(0, 90)
436 ax.set_ylim(0, 90)
434 ax.set_yticks(numpy.arange(0, 90, 20))
437 ax.set_yticks(numpy.arange(0, 90, 20))
435 ax.yaxis.labelpad = 40
438 ax.yaxis.labelpad = 40
436
439
437 if self.firsttime:
440 if self.firsttime:
438 for n, fig in enumerate(self.figures):
441 for n, fig in enumerate(self.figures):
439 fig.subplots_adjust(**self.plots_adjust)
442 fig.subplots_adjust(**self.plots_adjust)
440 self.firsttime = False
443 self.firsttime = False
441
444
442 def clear_figures(self):
445 def clear_figures(self):
443 '''
446 '''
444 Reset axes for redraw plots
447 Reset axes for redraw plots
445 '''
448 '''
446
449
447 for ax in self.axes+self.pf_axes+self.cb_axes:
450 for ax in self.axes+self.pf_axes+self.cb_axes:
448 ax.clear()
451 ax.clear()
449 ax.firsttime = True
452 ax.firsttime = True
450 if hasattr(ax, 'cbar') and ax.cbar:
453 if hasattr(ax, 'cbar') and ax.cbar:
451 ax.cbar.remove()
454 ax.cbar.remove()
452
455
453 def __plot(self):
456 def __plot(self):
454 '''
457 '''
455 Main function to plot, format and save figures
458 Main function to plot, format and save figures
456 '''
459 '''
457
460
458 self.plot()
461 self.plot()
459 self.format()
462 self.format()
460
463
461 for n, fig in enumerate(self.figures):
464 for n, fig in enumerate(self.figures):
462 if self.nrows == 0 or self.nplots == 0:
465 if self.nrows == 0 or self.nplots == 0:
463 log.warning('No data', self.name)
466 log.warning('No data', self.name)
464 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
467 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
465 fig.canvas.manager.set_window_title(self.CODE)
468 fig.canvas.manager.set_window_title(self.CODE)
466 continue
469 continue
467
470
468 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
471 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
469 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
472 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
470 fig.canvas.draw()
473 fig.canvas.draw()
471 if self.show:
474 if self.show:
472 fig.show()
475 fig.show()
473 figpause(0.01)
476 figpause(0.01)
474
477
475 if self.save:
478 if self.save:
476 self.save_figure(n)
479 self.save_figure(n)
477
480
478 if self.server:
481 if self.server:
479 self.send_to_server()
482 self.send_to_server()
480
483
481 def __update(self, dataOut, timestamp):
484 def __update(self, dataOut, timestamp):
482 '''
485 '''
483 '''
486 '''
484
487
485 metadata = {
488 metadata = {
486 'yrange': dataOut.heightList,
489 'yrange': dataOut.heightList,
487 'interval': dataOut.timeInterval,
490 'interval': dataOut.timeInterval,
488 'channels': dataOut.channelList
491 'channels': dataOut.channelList
489 }
492 }
490
493
491 data, meta = self.update(dataOut)
494 data, meta = self.update(dataOut)
492 metadata.update(meta)
495 metadata.update(meta)
493 self.data.update(data, timestamp, metadata)
496 self.data.update(data, timestamp, metadata)
494
497
495 def save_figure(self, n):
498 def save_figure(self, n):
496 '''
499 '''
497 '''
500 '''
498
501
499 if (self.data.max_time - self.save_time) <= self.save_period:
502 if (self.data.max_time - self.save_time) <= self.save_period:
500 return
503 return
501
504
502 self.save_time = self.data.max_time
505 self.save_time = self.data.max_time
503
506
504 fig = self.figures[n]
507 fig = self.figures[n]
505
508
506 figname = os.path.join(
507 self.save,
508 self.save_code,
509 '{}_{}.png'.format(
510 self.save_code,
511 self.getDateTime(self.data.max_time).strftime(
512 '%Y%m%d_%H%M%S'
513 ),
514 )
515 )
516 log.log('Saving figure: {}'.format(figname), self.name)
517 if not os.path.isdir(os.path.dirname(figname)):
518 os.makedirs(os.path.dirname(figname))
519 fig.savefig(figname)
520
521 if self.throttle == 0:
509 if self.throttle == 0:
522 figname = os.path.join(
510 figname = os.path.join(
523 self.save,
511 self.save,
524 '{}_{}.png'.format(
512 self.save_code,
513 '{}_{}.png'.format(
525 self.save_code,
514 self.save_code,
526 self.getDateTime(self.data.min_time).strftime(
515 self.getDateTime(self.data.max_time).strftime(
527 '%Y%m%d'
516 '%Y%m%d_%H%M%S'
528 ),
517 ),
529 )
518 )
530 )
519 )
520 log.log('Saving figure: {}'.format(figname), self.name)
521 if not os.path.isdir(os.path.dirname(figname)):
522 os.makedirs(os.path.dirname(figname))
531 fig.savefig(figname)
523 fig.savefig(figname)
532
524
525 figname = os.path.join(
526 self.save,
527 '{}_{}.png'.format(
528 self.save_code,
529 self.getDateTime(self.data.min_time).strftime(
530 '%Y%m%d'
531 ),
532 )
533 )
534 fig.savefig(figname)
535
533 def send_to_server(self):
536 def send_to_server(self):
534 '''
537 '''
535 '''
538 '''
536
539
537 if self.exp_code == None:
540 if self.exp_code == None:
538 log.warning('Missing `exp_code` skipping sending to server...')
541 log.warning('Missing `exp_code` skipping sending to server...')
539
542
540 last_time = self.data.max_time
543 last_time = self.data.max_time
541 interval = last_time - self.sender_time
544 interval = last_time - self.sender_time
542 if interval < self.sender_period:
545 if interval < self.sender_period:
543 return
546 return
544
547
545 self.sender_time = last_time
548 self.sender_time = last_time
546
549
547 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
550 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
548 for attr in attrs:
551 for attr in attrs:
549 value = getattr(self, attr)
552 value = getattr(self, attr)
550 if value:
553 if value:
551 if isinstance(value, (numpy.float32, numpy.float64)):
554 if isinstance(value, (numpy.float32, numpy.float64)):
552 value = round(float(value), 2)
555 value = round(float(value), 2)
553 self.data.meta[attr] = value
556 self.data.meta[attr] = value
554 if self.colormap == 'jet':
557 if self.colormap == 'jet':
555 self.data.meta['colormap'] = 'Jet'
558 self.data.meta['colormap'] = 'Jet'
556 elif 'RdBu' in self.colormap:
559 elif 'RdBu' in self.colormap:
557 self.data.meta['colormap'] = 'RdBu'
560 self.data.meta['colormap'] = 'RdBu'
558 else:
561 else:
559 self.data.meta['colormap'] = 'Viridis'
562 self.data.meta['colormap'] = 'Viridis'
560 self.data.meta['interval'] = int(interval)
563 self.data.meta['interval'] = int(interval)
561
564
562 self.sender_queue.append(last_time)
565 self.sender_queue.append(last_time)
563
566
564 while True:
567 while True:
565 try:
568 try:
566 tm = self.sender_queue.popleft()
569 tm = self.sender_queue.popleft()
567 except IndexError:
570 except IndexError:
568 break
571 break
569 msg = self.data.jsonify(tm, self.save_code, self.plot_type)
572 msg = self.data.jsonify(tm, self.save_code, self.plot_type)
570 self.socket.send_string(msg)
573 self.socket.send_string(msg)
571 socks = dict(self.poll.poll(2000))
574 socks = dict(self.poll.poll(2000))
572 if socks.get(self.socket) == zmq.POLLIN:
575 if socks.get(self.socket) == zmq.POLLIN:
573 reply = self.socket.recv_string()
576 reply = self.socket.recv_string()
574 if reply == 'ok':
577 if reply == 'ok':
575 log.log("Response from server ok", self.name)
578 log.log("Response from server ok", self.name)
576 time.sleep(0.1)
579 time.sleep(0.1)
577 continue
580 continue
578 else:
581 else:
579 log.warning(
582 log.warning(
580 "Malformed reply from server: {}".format(reply), self.name)
583 "Malformed reply from server: {}".format(reply), self.name)
581 else:
584 else:
582 log.warning(
585 log.warning(
583 "No response from server, retrying...", self.name)
586 "No response from server, retrying...", self.name)
584 self.sender_queue.appendleft(tm)
587 self.sender_queue.appendleft(tm)
585 self.socket.setsockopt(zmq.LINGER, 0)
588 self.socket.setsockopt(zmq.LINGER, 0)
586 self.socket.close()
589 self.socket.close()
587 self.poll.unregister(self.socket)
590 self.poll.unregister(self.socket)
588 self.socket = self.context.socket(zmq.REQ)
591 self.socket = self.context.socket(zmq.REQ)
589 self.socket.connect(self.server)
592 self.socket.connect(self.server)
590 self.poll.register(self.socket, zmq.POLLIN)
593 self.poll.register(self.socket, zmq.POLLIN)
591 break
594 break
592
595
593 def setup(self):
596 def setup(self):
594 '''
597 '''
595 This method should be implemented in the child class, the following
598 This method should be implemented in the child class, the following
596 attributes should be set:
599 attributes should be set:
597
600
598 self.nrows: number of rows
601 self.nrows: number of rows
599 self.ncols: number of cols
602 self.ncols: number of cols
600 self.nplots: number of plots (channels or pairs)
603 self.nplots: number of plots (channels or pairs)
601 self.ylabel: label for Y axes
604 self.ylabel: label for Y axes
602 self.titles: list of axes title
605 self.titles: list of axes title
603
606
604 '''
607 '''
605 raise NotImplementedError
608 raise NotImplementedError
606
609
607 def plot(self):
610 def plot(self):
608 '''
611 '''
609 Must be defined in the child class, the actual plotting method
612 Must be defined in the child class, the actual plotting method
610 '''
613 '''
611 raise NotImplementedError
614 raise NotImplementedError
612
615
613 def update(self, dataOut):
616 def update(self, dataOut):
614 '''
617 '''
615 Must be defined in the child class, update self.data with new data
618 Must be defined in the child class, update self.data with new data
616 '''
619 '''
617
620
618 data = {
621 data = {
619 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
622 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
620 }
623 }
621 meta = {}
624 meta = {}
622
625
623 return data, meta
626 return data, meta
624
627
625 def run(self, dataOut, **kwargs):
628 def run(self, dataOut, **kwargs):
626 '''
629 '''
627 Main plotting routine
630 Main plotting routine
628 '''
631 '''
629
632
630 if self.isConfig is False:
633 if self.isConfig is False:
631 self.__setup(**kwargs)
634 self.__setup(**kwargs)
632
635
633 if self.localtime:
636 if self.localtime:
634 self.getDateTime = datetime.datetime.fromtimestamp
637 self.getDateTime = datetime.datetime.fromtimestamp
635 else:
638 else:
636 self.getDateTime = datetime.datetime.utcfromtimestamp
639 self.getDateTime = datetime.datetime.utcfromtimestamp
637
640
638 self.data.setup()
641 self.data.setup()
639 self.isConfig = True
642 self.isConfig = True
640 if self.server:
643 if self.server:
641 self.context = zmq.Context()
644 self.context = zmq.Context()
642 self.socket = self.context.socket(zmq.REQ)
645 self.socket = self.context.socket(zmq.REQ)
643 self.socket.connect(self.server)
646 self.socket.connect(self.server)
644 self.poll = zmq.Poller()
647 self.poll = zmq.Poller()
645 self.poll.register(self.socket, zmq.POLLIN)
648 self.poll.register(self.socket, zmq.POLLIN)
646
649
647 tm = getattr(dataOut, self.attr_time)
650 tm = getattr(dataOut, self.attr_time)
648
651
649 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
652 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
650 self.save_time = tm
653 self.save_time = tm
651 self.__plot()
654 self.__plot()
652 self.tmin += self.xrange*60*60
655 self.tmin += self.xrange*60*60
653 self.data.setup()
656 self.data.setup()
654 self.clear_figures()
657 self.clear_figures()
655
658
656 self.__update(dataOut, tm)
659 self.__update(dataOut, tm)
657
660
658 if self.isPlotConfig is False:
661 if self.isPlotConfig is False:
659 self.__setup_plot()
662 self.__setup_plot()
660 self.isPlotConfig = True
663 self.isPlotConfig = True
661 if self.xaxis == 'time':
664 if self.xaxis == 'time':
662 dt = self.getDateTime(tm)
665 dt = self.getDateTime(tm)
663 if self.xmin is None:
666 if self.xmin is None:
664 self.tmin = tm
667 self.tmin = tm
665 self.xmin = dt.hour
668 self.xmin = dt.hour
666 minutes = (self.xmin-int(self.xmin)) * 60
669 minutes = (self.xmin-int(self.xmin)) * 60
667 seconds = (minutes - int(minutes)) * 60
670 seconds = (minutes - int(minutes)) * 60
668 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
671 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
669 datetime.datetime(1970, 1, 1)).total_seconds()
672 datetime.datetime(1970, 1, 1)).total_seconds()
670 if self.localtime:
673 if self.localtime:
671 self.tmin += time.timezone
674 self.tmin += time.timezone
672
675
673 if self.xmin is not None and self.xmax is not None:
676 if self.xmin is not None and self.xmax is not None:
674 self.xrange = self.xmax - self.xmin
677 self.xrange = self.xmax - self.xmin
675
678
676 if self.throttle == 0:
679 if self.throttle == 0:
677 self.__plot()
680 self.__plot()
678 else:
681 else:
679 self.__throttle_plot(self.__plot)#, coerce=coerce)
682 self.__throttle_plot(self.__plot)#, coerce=coerce)
680
683
681 def close(self):
684 def close(self):
682
685
683 if self.data and not self.data.flagNoData:
686 if self.data and not self.data.flagNoData:
684 self.save_time = self.data.max_time
687 self.save_time = self.data.max_time
685 self.__plot()
688 self.__plot()
686 if self.data and not self.data.flagNoData and self.pause:
689 if self.data and not self.data.flagNoData and self.pause:
687 figpause(10)
690 figpause(10)
688
691
@@ -1,358 +1,358
1 import os
1 import os
2 import datetime
2 import datetime
3 import numpy
3 import numpy
4
4
5 from schainpy.model.graphics.jroplot_base import Plot, plt
5 from schainpy.model.graphics.jroplot_base import Plot, plt
6 from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot
6 from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot
7 from schainpy.utils import log
7 from schainpy.utils import log
8
8
9 EARTH_RADIUS = 6.3710e3
9 EARTH_RADIUS = 6.3710e3
10
10
11
11
12 def ll2xy(lat1, lon1, lat2, lon2):
12 def ll2xy(lat1, lon1, lat2, lon2):
13
13
14 p = 0.017453292519943295
14 p = 0.017453292519943295
15 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
15 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
16 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
16 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
17 r = 12742 * numpy.arcsin(numpy.sqrt(a))
17 r = 12742 * numpy.arcsin(numpy.sqrt(a))
18 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
18 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
19 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
19 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
20 theta = -theta + numpy.pi/2
20 theta = -theta + numpy.pi/2
21 return r*numpy.cos(theta), r*numpy.sin(theta)
21 return r*numpy.cos(theta), r*numpy.sin(theta)
22
22
23
23
24 def km2deg(km):
24 def km2deg(km):
25 '''
25 '''
26 Convert distance in km to degrees
26 Convert distance in km to degrees
27 '''
27 '''
28
28
29 return numpy.rad2deg(km/EARTH_RADIUS)
29 return numpy.rad2deg(km/EARTH_RADIUS)
30
30
31
31
32
32
33 class SpectralMomentsPlot(SpectraPlot):
33 class SpectralMomentsPlot(SpectraPlot):
34 '''
34 '''
35 Plot for Spectral Moments
35 Plot for Spectral Moments
36 '''
36 '''
37 CODE = 'spc_moments'
37 CODE = 'spc_moments'
38 colormap = 'jet'
38 colormap = 'jet'
39 plot_type = 'pcolor'
39 plot_type = 'pcolor'
40
40
41
41
42 class SnrPlot(RTIPlot):
42 class SnrPlot(RTIPlot):
43 '''
43 '''
44 Plot for SNR Data
44 Plot for SNR Data
45 '''
45 '''
46
46
47 CODE = 'snr'
47 CODE = 'snr'
48 colormap = 'jet'
48 colormap = 'jet'
49
49
50 def update(self, dataOut):
50 def update(self, dataOut):
51
51
52 data = {
52 data = {
53 'snr': 10*numpy.log10(dataOut.data_snr)
53 'snr': 10*numpy.log10(dataOut.data_snr)
54 }
54 }
55
55
56 return data, {}
56 return data, {}
57
57
58 class DopplerPlot(RTIPlot):
58 class DopplerPlot(RTIPlot):
59 '''
59 '''
60 Plot for DOPPLER Data (1st moment)
60 Plot for DOPPLER Data (1st moment)
61 '''
61 '''
62
62
63 CODE = 'dop'
63 CODE = 'dop'
64 colormap = 'jet'
64 colormap = 'jet'
65
65
66 def update(self, dataOut):
66 def update(self, dataOut):
67
67
68 data = {
68 data = {
69 'dop': 10*numpy.log10(dataOut.data_dop)
69 'dop': 10*numpy.log10(dataOut.data_dop)
70 }
70 }
71
71
72 return data, {}
72 return data, {}
73
73
74 class PowerPlot(RTIPlot):
74 class PowerPlot(RTIPlot):
75 '''
75 '''
76 Plot for Power Data (0 moment)
76 Plot for Power Data (0 moment)
77 '''
77 '''
78
78
79 CODE = 'pow'
79 CODE = 'pow'
80 colormap = 'jet'
80 colormap = 'jet'
81
81
82 def update(self, dataOut):
82 def update(self, dataOut):
83
83
84 data = {
84 data = {
85 'pow': 10*numpy.log10(dataOut.data_pow)
85 'pow': 10*numpy.log10(dataOut.data_pow)
86 }
86 }
87
87
88 return data, {}
88 return data, {}
89
89
90 class SpectralWidthPlot(RTIPlot):
90 class SpectralWidthPlot(RTIPlot):
91 '''
91 '''
92 Plot for Spectral Width Data (2nd moment)
92 Plot for Spectral Width Data (2nd moment)
93 '''
93 '''
94
94
95 CODE = 'width'
95 CODE = 'width'
96 colormap = 'jet'
96 colormap = 'jet'
97
97
98 def update(self, dataOut):
98 def update(self, dataOut):
99
99
100 data = {
100 data = {
101 'width': dataOut.data_width
101 'width': dataOut.data_width
102 }
102 }
103
103
104 return data, {}
104 return data, {}
105
105
106 class SkyMapPlot(Plot):
106 class SkyMapPlot(Plot):
107 '''
107 '''
108 Plot for meteors detection data
108 Plot for meteors detection data
109 '''
109 '''
110
110
111 CODE = 'param'
111 CODE = 'param'
112
112
113 def setup(self):
113 def setup(self):
114
114
115 self.ncols = 1
115 self.ncols = 1
116 self.nrows = 1
116 self.nrows = 1
117 self.width = 7.2
117 self.width = 7.2
118 self.height = 7.2
118 self.height = 7.2
119 self.nplots = 1
119 self.nplots = 1
120 self.xlabel = 'Zonal Zenith Angle (deg)'
120 self.xlabel = 'Zonal Zenith Angle (deg)'
121 self.ylabel = 'Meridional Zenith Angle (deg)'
121 self.ylabel = 'Meridional Zenith Angle (deg)'
122 self.polar = True
122 self.polar = True
123 self.ymin = -180
123 self.ymin = -180
124 self.ymax = 180
124 self.ymax = 180
125 self.colorbar = False
125 self.colorbar = False
126
126
127 def plot(self):
127 def plot(self):
128
128
129 arrayParameters = numpy.concatenate(self.data['param'])
129 arrayParameters = numpy.concatenate(self.data['param'])
130 error = arrayParameters[:, -1]
130 error = arrayParameters[:, -1]
131 indValid = numpy.where(error == 0)[0]
131 indValid = numpy.where(error == 0)[0]
132 finalMeteor = arrayParameters[indValid, :]
132 finalMeteor = arrayParameters[indValid, :]
133 finalAzimuth = finalMeteor[:, 3]
133 finalAzimuth = finalMeteor[:, 3]
134 finalZenith = finalMeteor[:, 4]
134 finalZenith = finalMeteor[:, 4]
135
135
136 x = finalAzimuth * numpy.pi / 180
136 x = finalAzimuth * numpy.pi / 180
137 y = finalZenith
137 y = finalZenith
138
138
139 ax = self.axes[0]
139 ax = self.axes[0]
140
140
141 if ax.firsttime:
141 if ax.firsttime:
142 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
142 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
143 else:
143 else:
144 ax.plot.set_data(x, y)
144 ax.plot.set_data(x, y)
145
145
146 dt1 = self.getDateTime(self.data.min_time).strftime('%y/%m/%d %H:%M:%S')
146 dt1 = self.getDateTime(self.data.min_time).strftime('%y/%m/%d %H:%M:%S')
147 dt2 = self.getDateTime(self.data.max_time).strftime('%y/%m/%d %H:%M:%S')
147 dt2 = self.getDateTime(self.data.max_time).strftime('%y/%m/%d %H:%M:%S')
148 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
148 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
149 dt2,
149 dt2,
150 len(x))
150 len(x))
151 self.titles[0] = title
151 self.titles[0] = title
152
152
153
153
154 class GenericRTIPlot(Plot):
154 class GenericRTIPlot(Plot):
155 '''
155 '''
156 Plot for data_xxxx object
156 Plot for data_xxxx object
157 '''
157 '''
158
158
159 CODE = 'param'
159 CODE = 'param'
160 colormap = 'viridis'
160 colormap = 'viridis'
161 plot_type = 'pcolorbuffer'
161 plot_type = 'pcolorbuffer'
162
162
163 def setup(self):
163 def setup(self):
164 self.xaxis = 'time'
164 self.xaxis = 'time'
165 self.ncols = 1
165 self.ncols = 1
166 self.nrows = self.data.shape(self.attr_data)[0]
166 self.nrows = self.data.shape('param')[0]
167 self.nplots = self.nrows
167 self.nplots = self.nrows
168 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95, 'top': 0.95})
168 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95, 'top': 0.95})
169
169
170 if not self.xlabel:
170 if not self.xlabel:
171 self.xlabel = 'Time'
171 self.xlabel = 'Time'
172
172
173 self.ylabel = 'Height [km]'
173 self.ylabel = 'Height [km]'
174 if not self.titles:
174 if not self.titles:
175 self.titles = self.data.parameters \
175 self.titles = self.data.parameters \
176 if self.data.parameters else ['Param {}'.format(x) for x in range(self.nrows)]
176 if self.data.parameters else ['Param {}'.format(x) for x in range(self.nrows)]
177
177
178 def update(self, dataOut):
178 def update(self, dataOut):
179
179
180 data = {
180 data = {
181 self.attr_data : getattr(dataOut, self.attr_data)
181 'param' : numpy.concatenate([getattr(dataOut, attr) for attr in self.attr_data], axis=0)
182 }
182 }
183
183
184 meta = {}
184 meta = {}
185
185
186 return data, meta
186 return data, meta
187
187
188 def plot(self):
188 def plot(self):
189 # self.data.normalize_heights()
189 # self.data.normalize_heights()
190 self.x = self.data.times
190 self.x = self.data.times
191 self.y = self.data.yrange
191 self.y = self.data.yrange
192 self.z = self.data[self.attr_data]
192 self.z = self.data['param']
193
193
194 self.z = numpy.ma.masked_invalid(self.z)
194 self.z = numpy.ma.masked_invalid(self.z)
195
195
196 if self.decimation is None:
196 if self.decimation is None:
197 x, y, z = self.fill_gaps(self.x, self.y, self.z)
197 x, y, z = self.fill_gaps(self.x, self.y, self.z)
198 else:
198 else:
199 x, y, z = self.fill_gaps(*self.decimate())
199 x, y, z = self.fill_gaps(*self.decimate())
200
200
201 for n, ax in enumerate(self.axes):
201 for n, ax in enumerate(self.axes):
202
202
203 self.zmax = self.zmax if self.zmax is not None else numpy.max(
203 self.zmax = self.zmax if self.zmax is not None else numpy.max(
204 self.z[n])
204 self.z[n])
205 self.zmin = self.zmin if self.zmin is not None else numpy.min(
205 self.zmin = self.zmin if self.zmin is not None else numpy.min(
206 self.z[n])
206 self.z[n])
207
207
208 if ax.firsttime:
208 if ax.firsttime:
209 if self.zlimits is not None:
209 if self.zlimits is not None:
210 self.zmin, self.zmax = self.zlimits[n]
210 self.zmin, self.zmax = self.zlimits[n]
211
211
212 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
212 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
213 vmin=self.zmin,
213 vmin=self.zmin,
214 vmax=self.zmax,
214 vmax=self.zmax,
215 cmap=self.cmaps[n]
215 cmap=self.cmaps[n]
216 )
216 )
217 else:
217 else:
218 if self.zlimits is not None:
218 if self.zlimits is not None:
219 self.zmin, self.zmax = self.zlimits[n]
219 self.zmin, self.zmax = self.zlimits[n]
220 ax.collections.remove(ax.collections[0])
220 ax.collections.remove(ax.collections[0])
221 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
221 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
222 vmin=self.zmin,
222 vmin=self.zmin,
223 vmax=self.zmax,
223 vmax=self.zmax,
224 cmap=self.cmaps[n]
224 cmap=self.cmaps[n]
225 )
225 )
226
226
227
227
228 class PolarMapPlot(Plot):
228 class PolarMapPlot(Plot):
229 '''
229 '''
230 Plot for weather radar
230 Plot for weather radar
231 '''
231 '''
232
232
233 CODE = 'param'
233 CODE = 'param'
234 colormap = 'seismic'
234 colormap = 'seismic'
235
235
236 def setup(self):
236 def setup(self):
237 self.ncols = 1
237 self.ncols = 1
238 self.nrows = 1
238 self.nrows = 1
239 self.width = 9
239 self.width = 9
240 self.height = 8
240 self.height = 8
241 self.mode = self.data.meta['mode']
241 self.mode = self.data.meta['mode']
242 if self.channels is not None:
242 if self.channels is not None:
243 self.nplots = len(self.channels)
243 self.nplots = len(self.channels)
244 self.nrows = len(self.channels)
244 self.nrows = len(self.channels)
245 else:
245 else:
246 self.nplots = self.data.shape(self.CODE)[0]
246 self.nplots = self.data.shape(self.CODE)[0]
247 self.nrows = self.nplots
247 self.nrows = self.nplots
248 self.channels = list(range(self.nplots))
248 self.channels = list(range(self.nplots))
249 if self.mode == 'E':
249 if self.mode == 'E':
250 self.xlabel = 'Longitude'
250 self.xlabel = 'Longitude'
251 self.ylabel = 'Latitude'
251 self.ylabel = 'Latitude'
252 else:
252 else:
253 self.xlabel = 'Range (km)'
253 self.xlabel = 'Range (km)'
254 self.ylabel = 'Height (km)'
254 self.ylabel = 'Height (km)'
255 self.bgcolor = 'white'
255 self.bgcolor = 'white'
256 self.cb_labels = self.data.meta['units']
256 self.cb_labels = self.data.meta['units']
257 self.lat = self.data.meta['latitude']
257 self.lat = self.data.meta['latitude']
258 self.lon = self.data.meta['longitude']
258 self.lon = self.data.meta['longitude']
259 self.xmin, self.xmax = float(
259 self.xmin, self.xmax = float(
260 km2deg(self.xmin) + self.lon), float(km2deg(self.xmax) + self.lon)
260 km2deg(self.xmin) + self.lon), float(km2deg(self.xmax) + self.lon)
261 self.ymin, self.ymax = float(
261 self.ymin, self.ymax = float(
262 km2deg(self.ymin) + self.lat), float(km2deg(self.ymax) + self.lat)
262 km2deg(self.ymin) + self.lat), float(km2deg(self.ymax) + self.lat)
263 # self.polar = True
263 # self.polar = True
264
264
265 def plot(self):
265 def plot(self):
266
266
267 for n, ax in enumerate(self.axes):
267 for n, ax in enumerate(self.axes):
268 data = self.data['param'][self.channels[n]]
268 data = self.data['param'][self.channels[n]]
269
269
270 zeniths = numpy.linspace(
270 zeniths = numpy.linspace(
271 0, self.data.meta['max_range'], data.shape[1])
271 0, self.data.meta['max_range'], data.shape[1])
272 if self.mode == 'E':
272 if self.mode == 'E':
273 azimuths = -numpy.radians(self.data.yrange)+numpy.pi/2
273 azimuths = -numpy.radians(self.data.yrange)+numpy.pi/2
274 r, theta = numpy.meshgrid(zeniths, azimuths)
274 r, theta = numpy.meshgrid(zeniths, azimuths)
275 x, y = r*numpy.cos(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])), r*numpy.sin(
275 x, y = r*numpy.cos(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])), r*numpy.sin(
276 theta)*numpy.cos(numpy.radians(self.data.meta['elevation']))
276 theta)*numpy.cos(numpy.radians(self.data.meta['elevation']))
277 x = km2deg(x) + self.lon
277 x = km2deg(x) + self.lon
278 y = km2deg(y) + self.lat
278 y = km2deg(y) + self.lat
279 else:
279 else:
280 azimuths = numpy.radians(self.data.yrange)
280 azimuths = numpy.radians(self.data.yrange)
281 r, theta = numpy.meshgrid(zeniths, azimuths)
281 r, theta = numpy.meshgrid(zeniths, azimuths)
282 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
282 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
283 self.y = zeniths
283 self.y = zeniths
284
284
285 if ax.firsttime:
285 if ax.firsttime:
286 if self.zlimits is not None:
286 if self.zlimits is not None:
287 self.zmin, self.zmax = self.zlimits[n]
287 self.zmin, self.zmax = self.zlimits[n]
288 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
288 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
289 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
289 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
290 vmin=self.zmin,
290 vmin=self.zmin,
291 vmax=self.zmax,
291 vmax=self.zmax,
292 cmap=self.cmaps[n])
292 cmap=self.cmaps[n])
293 else:
293 else:
294 if self.zlimits is not None:
294 if self.zlimits is not None:
295 self.zmin, self.zmax = self.zlimits[n]
295 self.zmin, self.zmax = self.zlimits[n]
296 ax.collections.remove(ax.collections[0])
296 ax.collections.remove(ax.collections[0])
297 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
297 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
298 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
298 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
299 vmin=self.zmin,
299 vmin=self.zmin,
300 vmax=self.zmax,
300 vmax=self.zmax,
301 cmap=self.cmaps[n])
301 cmap=self.cmaps[n])
302
302
303 if self.mode == 'A':
303 if self.mode == 'A':
304 continue
304 continue
305
305
306 # plot district names
306 # plot district names
307 f = open('/data/workspace/schain_scripts/distrito.csv')
307 f = open('/data/workspace/schain_scripts/distrito.csv')
308 for line in f:
308 for line in f:
309 label, lon, lat = [s.strip() for s in line.split(',') if s]
309 label, lon, lat = [s.strip() for s in line.split(',') if s]
310 lat = float(lat)
310 lat = float(lat)
311 lon = float(lon)
311 lon = float(lon)
312 # ax.plot(lon, lat, '.b', ms=2)
312 # ax.plot(lon, lat, '.b', ms=2)
313 ax.text(lon, lat, label.decode('utf8'), ha='center',
313 ax.text(lon, lat, label.decode('utf8'), ha='center',
314 va='bottom', size='8', color='black')
314 va='bottom', size='8', color='black')
315
315
316 # plot limites
316 # plot limites
317 limites = []
317 limites = []
318 tmp = []
318 tmp = []
319 for line in open('/data/workspace/schain_scripts/lima.csv'):
319 for line in open('/data/workspace/schain_scripts/lima.csv'):
320 if '#' in line:
320 if '#' in line:
321 if tmp:
321 if tmp:
322 limites.append(tmp)
322 limites.append(tmp)
323 tmp = []
323 tmp = []
324 continue
324 continue
325 values = line.strip().split(',')
325 values = line.strip().split(',')
326 tmp.append((float(values[0]), float(values[1])))
326 tmp.append((float(values[0]), float(values[1])))
327 for points in limites:
327 for points in limites:
328 ax.add_patch(
328 ax.add_patch(
329 Polygon(points, ec='k', fc='none', ls='--', lw=0.5))
329 Polygon(points, ec='k', fc='none', ls='--', lw=0.5))
330
330
331 # plot Cuencas
331 # plot Cuencas
332 for cuenca in ('rimac', 'lurin', 'mala', 'chillon', 'chilca', 'chancay-huaral'):
332 for cuenca in ('rimac', 'lurin', 'mala', 'chillon', 'chilca', 'chancay-huaral'):
333 f = open('/data/workspace/schain_scripts/{}.csv'.format(cuenca))
333 f = open('/data/workspace/schain_scripts/{}.csv'.format(cuenca))
334 values = [line.strip().split(',') for line in f]
334 values = [line.strip().split(',') for line in f]
335 points = [(float(s[0]), float(s[1])) for s in values]
335 points = [(float(s[0]), float(s[1])) for s in values]
336 ax.add_patch(Polygon(points, ec='b', fc='none'))
336 ax.add_patch(Polygon(points, ec='b', fc='none'))
337
337
338 # plot grid
338 # plot grid
339 for r in (15, 30, 45, 60):
339 for r in (15, 30, 45, 60):
340 ax.add_artist(plt.Circle((self.lon, self.lat),
340 ax.add_artist(plt.Circle((self.lon, self.lat),
341 km2deg(r), color='0.6', fill=False, lw=0.2))
341 km2deg(r), color='0.6', fill=False, lw=0.2))
342 ax.text(
342 ax.text(
343 self.lon + (km2deg(r))*numpy.cos(60*numpy.pi/180),
343 self.lon + (km2deg(r))*numpy.cos(60*numpy.pi/180),
344 self.lat + (km2deg(r))*numpy.sin(60*numpy.pi/180),
344 self.lat + (km2deg(r))*numpy.sin(60*numpy.pi/180),
345 '{}km'.format(r),
345 '{}km'.format(r),
346 ha='center', va='bottom', size='8', color='0.6', weight='heavy')
346 ha='center', va='bottom', size='8', color='0.6', weight='heavy')
347
347
348 if self.mode == 'E':
348 if self.mode == 'E':
349 title = 'El={}$^\circ$'.format(self.data.meta['elevation'])
349 title = 'El={}$^\circ$'.format(self.data.meta['elevation'])
350 label = 'E{:02d}'.format(int(self.data.meta['elevation']))
350 label = 'E{:02d}'.format(int(self.data.meta['elevation']))
351 else:
351 else:
352 title = 'Az={}$^\circ$'.format(self.data.meta['azimuth'])
352 title = 'Az={}$^\circ$'.format(self.data.meta['azimuth'])
353 label = 'A{:02d}'.format(int(self.data.meta['azimuth']))
353 label = 'A{:02d}'.format(int(self.data.meta['azimuth']))
354
354
355 self.save_labels = ['{}-{}'.format(lbl, label) for lbl in self.labels]
355 self.save_labels = ['{}-{}'.format(lbl, label) for lbl in self.labels]
356 self.titles = ['{} {}'.format(
356 self.titles = ['{} {}'.format(
357 self.data.parameters[x], title) for x in self.channels]
357 self.data.parameters[x], title) for x in self.channels]
358
358
@@ -1,702 +1,702
1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
1 # Copyright (c) 2012-2020 Jicamarca Radio Observatory
2 # All rights reserved.
2 # All rights reserved.
3 #
3 #
4 # Distributed under the terms of the BSD 3-clause license.
4 # Distributed under the terms of the BSD 3-clause license.
5 """Classes to plot Spectra data
5 """Classes to plot Spectra data
6
6
7 """
7 """
8
8
9 import os
9 import os
10 import numpy
10 import numpy
11
11
12 from schainpy.model.graphics.jroplot_base import Plot, plt, log
12 from schainpy.model.graphics.jroplot_base import Plot, plt, log
13
13
14
14
15 class SpectraPlot(Plot):
15 class SpectraPlot(Plot):
16 '''
16 '''
17 Plot for Spectra data
17 Plot for Spectra data
18 '''
18 '''
19
19
20 CODE = 'spc'
20 CODE = 'spc'
21 colormap = 'jet'
21 colormap = 'jet'
22 plot_type = 'pcolor'
22 plot_type = 'pcolor'
23 buffering = False
23 buffering = False
24
24
25 def setup(self):
25 def setup(self):
26 self.nplots = len(self.data.channels)
26 self.nplots = len(self.data.channels)
27 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
27 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
28 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
28 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
29 self.height = 2.6 * self.nrows
29 self.height = 2.6 * self.nrows
30 self.cb_label = 'dB'
30 self.cb_label = 'dB'
31 if self.showprofile:
31 if self.showprofile:
32 self.width = 4 * self.ncols
32 self.width = 4 * self.ncols
33 else:
33 else:
34 self.width = 3.5 * self.ncols
34 self.width = 3.5 * self.ncols
35 self.plots_adjust.update({'wspace': 0.4, 'hspace':0.4, 'left': 0.1, 'right': 0.9, 'bottom': 0.08})
35 self.plots_adjust.update({'wspace': 0.4, 'hspace':0.4, 'left': 0.1, 'right': 0.9, 'bottom': 0.08})
36 self.ylabel = 'Range [km]'
36 self.ylabel = 'Range [km]'
37
37
38 def update(self, dataOut):
38 def update(self, dataOut):
39
39
40 data = {}
40 data = {}
41 meta = {}
41 meta = {}
42 spc = 10*numpy.log10(dataOut.data_spc/dataOut.normFactor)
42 spc = 10*numpy.log10(dataOut.data_spc/dataOut.normFactor)
43 data['spc'] = spc
43 data['spc'] = spc
44 data['rti'] = dataOut.getPower()
44 data['rti'] = dataOut.getPower()
45 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
45 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
46 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
46 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
47 if self.CODE == 'spc_moments':
47 if self.CODE == 'spc_moments':
48 data['moments'] = dataOut.moments
48 data['moments'] = dataOut.moments
49
49
50 return data, meta
50 return data, meta
51
51
52 def plot(self):
52 def plot(self):
53 if self.xaxis == "frequency":
53 if self.xaxis == "frequency":
54 x = self.data.xrange[0]
54 x = self.data.xrange[0]
55 self.xlabel = "Frequency (kHz)"
55 self.xlabel = "Frequency (kHz)"
56 elif self.xaxis == "time":
56 elif self.xaxis == "time":
57 x = self.data.xrange[1]
57 x = self.data.xrange[1]
58 self.xlabel = "Time (ms)"
58 self.xlabel = "Time (ms)"
59 else:
59 else:
60 x = self.data.xrange[2]
60 x = self.data.xrange[2]
61 self.xlabel = "Velocity (m/s)"
61 self.xlabel = "Velocity (m/s)"
62
62
63 if self.CODE == 'spc_moments':
63 if self.CODE == 'spc_moments':
64 x = self.data.xrange[2]
64 x = self.data.xrange[2]
65 self.xlabel = "Velocity (m/s)"
65 self.xlabel = "Velocity (m/s)"
66
66
67 self.titles = []
67 self.titles = []
68
68
69 y = self.data.yrange
69 y = self.data.yrange
70 self.y = y
70 self.y = y
71
71
72 data = self.data[-1]
72 data = self.data[-1]
73 z = data['spc']
73 z = data['spc']
74
74
75 for n, ax in enumerate(self.axes):
75 for n, ax in enumerate(self.axes):
76 noise = data['noise'][n]
76 noise = data['noise'][n]
77 if self.CODE == 'spc_moments':
77 if self.CODE == 'spc_moments':
78 mean = data['moments'][n, 2]
78 mean = data['moments'][n, 1]
79 if ax.firsttime:
79 if ax.firsttime:
80 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
80 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
81 self.xmin = self.xmin if self.xmin else -self.xmax
81 self.xmin = self.xmin if self.xmin else -self.xmax
82 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
82 self.zmin = self.zmin if self.zmin else numpy.nanmin(z)
83 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
83 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
84 ax.plt = ax.pcolormesh(x, y, z[n].T,
84 ax.plt = ax.pcolormesh(x, y, z[n].T,
85 vmin=self.zmin,
85 vmin=self.zmin,
86 vmax=self.zmax,
86 vmax=self.zmax,
87 cmap=plt.get_cmap(self.colormap)
87 cmap=plt.get_cmap(self.colormap)
88 )
88 )
89
89
90 if self.showprofile:
90 if self.showprofile:
91 ax.plt_profile = self.pf_axes[n].plot(
91 ax.plt_profile = self.pf_axes[n].plot(
92 data['rti'][n], y)[0]
92 data['rti'][n], y)[0]
93 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
93 ax.plt_noise = self.pf_axes[n].plot(numpy.repeat(noise, len(y)), y,
94 color="k", linestyle="dashed", lw=1)[0]
94 color="k", linestyle="dashed", lw=1)[0]
95 if self.CODE == 'spc_moments':
95 if self.CODE == 'spc_moments':
96 ax.plt_mean = ax.plot(mean, y, color='k')[0]
96 ax.plt_mean = ax.plot(mean, y, color='k')[0]
97 else:
97 else:
98 ax.plt.set_array(z[n].T.ravel())
98 ax.plt.set_array(z[n].T.ravel())
99 if self.showprofile:
99 if self.showprofile:
100 ax.plt_profile.set_data(data['rti'][n], y)
100 ax.plt_profile.set_data(data['rti'][n], y)
101 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
101 ax.plt_noise.set_data(numpy.repeat(noise, len(y)), y)
102 if self.CODE == 'spc_moments':
102 if self.CODE == 'spc_moments':
103 ax.plt_mean.set_data(mean, y)
103 ax.plt_mean.set_data(mean, y)
104 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
104 self.titles.append('CH {}: {:3.2f}dB'.format(n, noise))
105
105
106
106
107 class CrossSpectraPlot(Plot):
107 class CrossSpectraPlot(Plot):
108
108
109 CODE = 'cspc'
109 CODE = 'cspc'
110 colormap = 'jet'
110 colormap = 'jet'
111 plot_type = 'pcolor'
111 plot_type = 'pcolor'
112 zmin_coh = None
112 zmin_coh = None
113 zmax_coh = None
113 zmax_coh = None
114 zmin_phase = None
114 zmin_phase = None
115 zmax_phase = None
115 zmax_phase = None
116
116
117 def setup(self):
117 def setup(self):
118
118
119 self.ncols = 4
119 self.ncols = 4
120 self.nplots = len(self.data.pairs) * 2
120 self.nplots = len(self.data.pairs) * 2
121 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
121 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
122 self.width = 3.1 * self.ncols
122 self.width = 3.1 * self.ncols
123 self.height = 2.6 * self.nrows
123 self.height = 2.6 * self.nrows
124 self.ylabel = 'Range [km]'
124 self.ylabel = 'Range [km]'
125 self.showprofile = False
125 self.showprofile = False
126 self.plots_adjust.update({'left': 0.08, 'right': 0.92, 'wspace': 0.5, 'hspace':0.4, 'top':0.95, 'bottom': 0.08})
126 self.plots_adjust.update({'left': 0.08, 'right': 0.92, 'wspace': 0.5, 'hspace':0.4, 'top':0.95, 'bottom': 0.08})
127
127
128 def update(self, dataOut):
128 def update(self, dataOut):
129
129
130 data = {}
130 data = {}
131 meta = {}
131 meta = {}
132
132
133 spc = dataOut.data_spc
133 spc = dataOut.data_spc
134 cspc = dataOut.data_cspc
134 cspc = dataOut.data_cspc
135 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
135 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
136 meta['pairs'] = dataOut.pairsList
136 meta['pairs'] = dataOut.pairsList
137
137
138 tmp = []
138 tmp = []
139
139
140 for n, pair in enumerate(meta['pairs']):
140 for n, pair in enumerate(meta['pairs']):
141 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
141 out = cspc[n] / numpy.sqrt(spc[pair[0]] * spc[pair[1]])
142 coh = numpy.abs(out)
142 coh = numpy.abs(out)
143 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
143 phase = numpy.arctan2(out.imag, out.real) * 180 / numpy.pi
144 tmp.append(coh)
144 tmp.append(coh)
145 tmp.append(phase)
145 tmp.append(phase)
146
146
147 data['cspc'] = numpy.array(tmp)
147 data['cspc'] = numpy.array(tmp)
148
148
149 return data, meta
149 return data, meta
150
150
151 def plot(self):
151 def plot(self):
152
152
153 if self.xaxis == "frequency":
153 if self.xaxis == "frequency":
154 x = self.data.xrange[0]
154 x = self.data.xrange[0]
155 self.xlabel = "Frequency (kHz)"
155 self.xlabel = "Frequency (kHz)"
156 elif self.xaxis == "time":
156 elif self.xaxis == "time":
157 x = self.data.xrange[1]
157 x = self.data.xrange[1]
158 self.xlabel = "Time (ms)"
158 self.xlabel = "Time (ms)"
159 else:
159 else:
160 x = self.data.xrange[2]
160 x = self.data.xrange[2]
161 self.xlabel = "Velocity (m/s)"
161 self.xlabel = "Velocity (m/s)"
162
162
163 self.titles = []
163 self.titles = []
164
164
165 y = self.data.yrange
165 y = self.data.yrange
166 self.y = y
166 self.y = y
167
167
168 data = self.data[-1]
168 data = self.data[-1]
169 cspc = data['cspc']
169 cspc = data['cspc']
170
170
171 for n in range(len(self.data.pairs)):
171 for n in range(len(self.data.pairs)):
172 pair = self.data.pairs[n]
172 pair = self.data.pairs[n]
173 coh = cspc[n*2]
173 coh = cspc[n*2]
174 phase = cspc[n*2+1]
174 phase = cspc[n*2+1]
175 ax = self.axes[2 * n]
175 ax = self.axes[2 * n]
176 if ax.firsttime:
176 if ax.firsttime:
177 ax.plt = ax.pcolormesh(x, y, coh.T,
177 ax.plt = ax.pcolormesh(x, y, coh.T,
178 vmin=0,
178 vmin=0,
179 vmax=1,
179 vmax=1,
180 cmap=plt.get_cmap(self.colormap_coh)
180 cmap=plt.get_cmap(self.colormap_coh)
181 )
181 )
182 else:
182 else:
183 ax.plt.set_array(coh.T.ravel())
183 ax.plt.set_array(coh.T.ravel())
184 self.titles.append(
184 self.titles.append(
185 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
185 'Coherence Ch{} * Ch{}'.format(pair[0], pair[1]))
186
186
187 ax = self.axes[2 * n + 1]
187 ax = self.axes[2 * n + 1]
188 if ax.firsttime:
188 if ax.firsttime:
189 ax.plt = ax.pcolormesh(x, y, phase.T,
189 ax.plt = ax.pcolormesh(x, y, phase.T,
190 vmin=-180,
190 vmin=-180,
191 vmax=180,
191 vmax=180,
192 cmap=plt.get_cmap(self.colormap_phase)
192 cmap=plt.get_cmap(self.colormap_phase)
193 )
193 )
194 else:
194 else:
195 ax.plt.set_array(phase.T.ravel())
195 ax.plt.set_array(phase.T.ravel())
196 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
196 self.titles.append('Phase CH{} * CH{}'.format(pair[0], pair[1]))
197
197
198
198
199 class RTIPlot(Plot):
199 class RTIPlot(Plot):
200 '''
200 '''
201 Plot for RTI data
201 Plot for RTI data
202 '''
202 '''
203
203
204 CODE = 'rti'
204 CODE = 'rti'
205 colormap = 'jet'
205 colormap = 'jet'
206 plot_type = 'pcolorbuffer'
206 plot_type = 'pcolorbuffer'
207
207
208 def setup(self):
208 def setup(self):
209 self.xaxis = 'time'
209 self.xaxis = 'time'
210 self.ncols = 1
210 self.ncols = 1
211 self.nrows = len(self.data.channels)
211 self.nrows = len(self.data.channels)
212 self.nplots = len(self.data.channels)
212 self.nplots = len(self.data.channels)
213 self.ylabel = 'Range [km]'
213 self.ylabel = 'Range [km]'
214 self.xlabel = 'Time'
214 self.xlabel = 'Time'
215 self.cb_label = 'dB'
215 self.cb_label = 'dB'
216 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95})
216 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95})
217 self.titles = ['{} Channel {}'.format(
217 self.titles = ['{} Channel {}'.format(
218 self.CODE.upper(), x) for x in range(self.nrows)]
218 self.CODE.upper(), x) for x in range(self.nrows)]
219
219
220 def update(self, dataOut):
220 def update(self, dataOut):
221
221
222 data = {}
222 data = {}
223 meta = {}
223 meta = {}
224 data['rti'] = dataOut.getPower()
224 data['rti'] = dataOut.getPower()
225 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
225 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor)
226
226
227 return data, meta
227 return data, meta
228
228
229 def plot(self):
229 def plot(self):
230 self.x = self.data.times
230 self.x = self.data.times
231 self.y = self.data.yrange
231 self.y = self.data.yrange
232 self.z = self.data[self.CODE]
232 self.z = self.data[self.CODE]
233 self.z = numpy.ma.masked_invalid(self.z)
233 self.z = numpy.ma.masked_invalid(self.z)
234
234
235 if self.decimation is None:
235 if self.decimation is None:
236 x, y, z = self.fill_gaps(self.x, self.y, self.z)
236 x, y, z = self.fill_gaps(self.x, self.y, self.z)
237 else:
237 else:
238 x, y, z = self.fill_gaps(*self.decimate())
238 x, y, z = self.fill_gaps(*self.decimate())
239
239
240 for n, ax in enumerate(self.axes):
240 for n, ax in enumerate(self.axes):
241 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
241 self.zmin = self.zmin if self.zmin else numpy.min(self.z)
242 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
242 self.zmax = self.zmax if self.zmax else numpy.max(self.z)
243 data = self.data[-1]
243 data = self.data[-1]
244 if ax.firsttime:
244 if ax.firsttime:
245 ax.plt = ax.pcolormesh(x, y, z[n].T,
245 ax.plt = ax.pcolormesh(x, y, z[n].T,
246 vmin=self.zmin,
246 vmin=self.zmin,
247 vmax=self.zmax,
247 vmax=self.zmax,
248 cmap=plt.get_cmap(self.colormap)
248 cmap=plt.get_cmap(self.colormap)
249 )
249 )
250 if self.showprofile:
250 if self.showprofile:
251 ax.plot_profile = self.pf_axes[n].plot(
251 ax.plot_profile = self.pf_axes[n].plot(
252 data['rti'][n], self.y)[0]
252 data['rti'][n], self.y)[0]
253 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(data['noise'][n], len(self.y)), self.y,
253 ax.plot_noise = self.pf_axes[n].plot(numpy.repeat(data['noise'][n], len(self.y)), self.y,
254 color="k", linestyle="dashed", lw=1)[0]
254 color="k", linestyle="dashed", lw=1)[0]
255 else:
255 else:
256 ax.collections.remove(ax.collections[0])
256 ax.collections.remove(ax.collections[0])
257 ax.plt = ax.pcolormesh(x, y, z[n].T,
257 ax.plt = ax.pcolormesh(x, y, z[n].T,
258 vmin=self.zmin,
258 vmin=self.zmin,
259 vmax=self.zmax,
259 vmax=self.zmax,
260 cmap=plt.get_cmap(self.colormap)
260 cmap=plt.get_cmap(self.colormap)
261 )
261 )
262 if self.showprofile:
262 if self.showprofile:
263 ax.plot_profile.set_data(data['rti'][n], self.y)
263 ax.plot_profile.set_data(data['rti'][n], self.y)
264 ax.plot_noise.set_data(numpy.repeat(
264 ax.plot_noise.set_data(numpy.repeat(
265 data['noise'][n], len(self.y)), self.y)
265 data['noise'][n], len(self.y)), self.y)
266
266
267
267
268 class CoherencePlot(RTIPlot):
268 class CoherencePlot(RTIPlot):
269 '''
269 '''
270 Plot for Coherence data
270 Plot for Coherence data
271 '''
271 '''
272
272
273 CODE = 'coh'
273 CODE = 'coh'
274
274
275 def setup(self):
275 def setup(self):
276 self.xaxis = 'time'
276 self.xaxis = 'time'
277 self.ncols = 1
277 self.ncols = 1
278 self.nrows = len(self.data.pairs)
278 self.nrows = len(self.data.pairs)
279 self.nplots = len(self.data.pairs)
279 self.nplots = len(self.data.pairs)
280 self.ylabel = 'Range [km]'
280 self.ylabel = 'Range [km]'
281 self.xlabel = 'Time'
281 self.xlabel = 'Time'
282 self.plots_adjust.update({'hspace':0.6, 'left': 0.1, 'bottom': 0.1,'right':0.95})
282 self.plots_adjust.update({'hspace':0.6, 'left': 0.1, 'bottom': 0.1,'right':0.95})
283 if self.CODE == 'coh':
283 if self.CODE == 'coh':
284 self.cb_label = ''
284 self.cb_label = ''
285 self.titles = [
285 self.titles = [
286 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
286 'Coherence Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
287 else:
287 else:
288 self.cb_label = 'Degrees'
288 self.cb_label = 'Degrees'
289 self.titles = [
289 self.titles = [
290 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
290 'Phase Map Ch{} * Ch{}'.format(x[0], x[1]) for x in self.data.pairs]
291
291
292 def update(self, dataOut):
292 def update(self, dataOut):
293
293
294 data = {}
294 data = {}
295 meta = {}
295 meta = {}
296 data['coh'] = dataOut.getCoherence()
296 data['coh'] = dataOut.getCoherence()
297 meta['pairs'] = dataOut.pairsList
297 meta['pairs'] = dataOut.pairsList
298
298
299 return data, meta
299 return data, meta
300
300
301 class PhasePlot(CoherencePlot):
301 class PhasePlot(CoherencePlot):
302 '''
302 '''
303 Plot for Phase map data
303 Plot for Phase map data
304 '''
304 '''
305
305
306 CODE = 'phase'
306 CODE = 'phase'
307 colormap = 'seismic'
307 colormap = 'seismic'
308
308
309 def update(self, dataOut):
309 def update(self, dataOut):
310
310
311 data = {}
311 data = {}
312 meta = {}
312 meta = {}
313 data['phase'] = dataOut.getCoherence(phase=True)
313 data['phase'] = dataOut.getCoherence(phase=True)
314 meta['pairs'] = dataOut.pairsList
314 meta['pairs'] = dataOut.pairsList
315
315
316 return data, meta
316 return data, meta
317
317
318 class NoisePlot(Plot):
318 class NoisePlot(Plot):
319 '''
319 '''
320 Plot for noise
320 Plot for noise
321 '''
321 '''
322
322
323 CODE = 'noise'
323 CODE = 'noise'
324 plot_type = 'scatterbuffer'
324 plot_type = 'scatterbuffer'
325
325
326 def setup(self):
326 def setup(self):
327 self.xaxis = 'time'
327 self.xaxis = 'time'
328 self.ncols = 1
328 self.ncols = 1
329 self.nrows = 1
329 self.nrows = 1
330 self.nplots = 1
330 self.nplots = 1
331 self.ylabel = 'Intensity [dB]'
331 self.ylabel = 'Intensity [dB]'
332 self.xlabel = 'Time'
332 self.xlabel = 'Time'
333 self.titles = ['Noise']
333 self.titles = ['Noise']
334 self.colorbar = False
334 self.colorbar = False
335 self.plots_adjust.update({'right': 0.85 })
335 self.plots_adjust.update({'right': 0.85 })
336
336
337 def update(self, dataOut):
337 def update(self, dataOut):
338
338
339 data = {}
339 data = {}
340 meta = {}
340 meta = {}
341 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor).reshape(dataOut.nChannels, 1)
341 data['noise'] = 10*numpy.log10(dataOut.getNoise()/dataOut.normFactor).reshape(dataOut.nChannels, 1)
342 meta['yrange'] = numpy.array([])
342 meta['yrange'] = numpy.array([])
343
343
344 return data, meta
344 return data, meta
345
345
346 def plot(self):
346 def plot(self):
347
347
348 x = self.data.times
348 x = self.data.times
349 xmin = self.data.min_time
349 xmin = self.data.min_time
350 xmax = xmin + self.xrange * 60 * 60
350 xmax = xmin + self.xrange * 60 * 60
351 Y = self.data['noise']
351 Y = self.data['noise']
352
352
353 if self.axes[0].firsttime:
353 if self.axes[0].firsttime:
354 self.ymin = numpy.nanmin(Y) - 5
354 self.ymin = numpy.nanmin(Y) - 5
355 self.ymax = numpy.nanmax(Y) + 5
355 self.ymax = numpy.nanmax(Y) + 5
356 for ch in self.data.channels:
356 for ch in self.data.channels:
357 y = Y[ch]
357 y = Y[ch]
358 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
358 self.axes[0].plot(x, y, lw=1, label='Ch{}'.format(ch))
359 plt.legend(bbox_to_anchor=(1.18, 1.0))
359 plt.legend(bbox_to_anchor=(1.18, 1.0))
360 else:
360 else:
361 for ch in self.data.channels:
361 for ch in self.data.channels:
362 y = Y[ch]
362 y = Y[ch]
363 self.axes[0].lines[ch].set_data(x, y)
363 self.axes[0].lines[ch].set_data(x, y)
364
364
365
365
366 class PowerProfilePlot(Plot):
366 class PowerProfilePlot(Plot):
367
367
368 CODE = 'pow_profile'
368 CODE = 'pow_profile'
369 plot_type = 'scatter'
369 plot_type = 'scatter'
370
370
371 def setup(self):
371 def setup(self):
372
372
373 self.ncols = 1
373 self.ncols = 1
374 self.nrows = 1
374 self.nrows = 1
375 self.nplots = 1
375 self.nplots = 1
376 self.height = 4
376 self.height = 4
377 self.width = 3
377 self.width = 3
378 self.ylabel = 'Range [km]'
378 self.ylabel = 'Range [km]'
379 self.xlabel = 'Intensity [dB]'
379 self.xlabel = 'Intensity [dB]'
380 self.titles = ['Power Profile']
380 self.titles = ['Power Profile']
381 self.colorbar = False
381 self.colorbar = False
382
382
383 def update(self, dataOut):
383 def update(self, dataOut):
384
384
385 data = {}
385 data = {}
386 meta = {}
386 meta = {}
387 data[self.CODE] = dataOut.getPower()
387 data[self.CODE] = dataOut.getPower()
388
388
389 return data, meta
389 return data, meta
390
390
391 def plot(self):
391 def plot(self):
392
392
393 y = self.data.yrange
393 y = self.data.yrange
394 self.y = y
394 self.y = y
395
395
396 x = self.data[-1][self.CODE]
396 x = self.data[-1][self.CODE]
397
397
398 if self.xmin is None: self.xmin = numpy.nanmin(x)*0.9
398 if self.xmin is None: self.xmin = numpy.nanmin(x)*0.9
399 if self.xmax is None: self.xmax = numpy.nanmax(x)*1.1
399 if self.xmax is None: self.xmax = numpy.nanmax(x)*1.1
400
400
401 if self.axes[0].firsttime:
401 if self.axes[0].firsttime:
402 for ch in self.data.channels:
402 for ch in self.data.channels:
403 self.axes[0].plot(x[ch], y, lw=1, label='Ch{}'.format(ch))
403 self.axes[0].plot(x[ch], y, lw=1, label='Ch{}'.format(ch))
404 plt.legend()
404 plt.legend()
405 else:
405 else:
406 for ch in self.data.channels:
406 for ch in self.data.channels:
407 self.axes[0].lines[ch].set_data(x[ch], y)
407 self.axes[0].lines[ch].set_data(x[ch], y)
408
408
409
409
410 class SpectraCutPlot(Plot):
410 class SpectraCutPlot(Plot):
411
411
412 CODE = 'spc_cut'
412 CODE = 'spc_cut'
413 plot_type = 'scatter'
413 plot_type = 'scatter'
414 buffering = False
414 buffering = False
415
415
416 def setup(self):
416 def setup(self):
417
417
418 self.nplots = len(self.data.channels)
418 self.nplots = len(self.data.channels)
419 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
419 self.ncols = int(numpy.sqrt(self.nplots) + 0.9)
420 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
420 self.nrows = int((1.0 * self.nplots / self.ncols) + 0.9)
421 self.width = 3.4 * self.ncols + 1.5
421 self.width = 3.4 * self.ncols + 1.5
422 self.height = 3 * self.nrows
422 self.height = 3 * self.nrows
423 self.ylabel = 'Power [dB]'
423 self.ylabel = 'Power [dB]'
424 self.colorbar = False
424 self.colorbar = False
425 self.plots_adjust.update({'left':0.1, 'hspace':0.3, 'right': 0.75, 'bottom':0.08})
425 self.plots_adjust.update({'left':0.1, 'hspace':0.3, 'right': 0.75, 'bottom':0.08})
426
426
427 def update(self, dataOut):
427 def update(self, dataOut):
428
428
429 data = {}
429 data = {}
430 meta = {}
430 meta = {}
431 spc = 10*numpy.log10(dataOut.data_spc/dataOut.normFactor)
431 spc = 10*numpy.log10(dataOut.data_spc/dataOut.normFactor)
432 data['spc'] = spc
432 data['spc'] = spc
433 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
433 meta['xrange'] = (dataOut.getFreqRange(1)/1000., dataOut.getAcfRange(1), dataOut.getVelRange(1))
434
434
435 return data, meta
435 return data, meta
436
436
437 def plot(self):
437 def plot(self):
438 if self.xaxis == "frequency":
438 if self.xaxis == "frequency":
439 x = self.data.xrange[0][1:]
439 x = self.data.xrange[0][1:]
440 self.xlabel = "Frequency (kHz)"
440 self.xlabel = "Frequency (kHz)"
441 elif self.xaxis == "time":
441 elif self.xaxis == "time":
442 x = self.data.xrange[1]
442 x = self.data.xrange[1]
443 self.xlabel = "Time (ms)"
443 self.xlabel = "Time (ms)"
444 else:
444 else:
445 x = self.data.xrange[2]
445 x = self.data.xrange[2]
446 self.xlabel = "Velocity (m/s)"
446 self.xlabel = "Velocity (m/s)"
447
447
448 self.titles = []
448 self.titles = []
449
449
450 y = self.data.yrange
450 y = self.data.yrange
451 z = self.data[-1]['spc']
451 z = self.data[-1]['spc']
452
452
453 if self.height_index:
453 if self.height_index:
454 index = numpy.array(self.height_index)
454 index = numpy.array(self.height_index)
455 else:
455 else:
456 index = numpy.arange(0, len(y), int((len(y))/9))
456 index = numpy.arange(0, len(y), int((len(y))/9))
457
457
458 for n, ax in enumerate(self.axes):
458 for n, ax in enumerate(self.axes):
459 if ax.firsttime:
459 if ax.firsttime:
460 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
460 self.xmax = self.xmax if self.xmax else numpy.nanmax(x)
461 self.xmin = self.xmin if self.xmin else -self.xmax
461 self.xmin = self.xmin if self.xmin else -self.xmax
462 self.ymin = self.ymin if self.ymin else numpy.nanmin(z)
462 self.ymin = self.ymin if self.ymin else numpy.nanmin(z)
463 self.ymax = self.ymax if self.ymax else numpy.nanmax(z)
463 self.ymax = self.ymax if self.ymax else numpy.nanmax(z)
464 ax.plt = ax.plot(x, z[n, :, index].T)
464 ax.plt = ax.plot(x, z[n, :, index].T)
465 labels = ['Range = {:2.1f}km'.format(y[i]) for i in index]
465 labels = ['Range = {:2.1f}km'.format(y[i]) for i in index]
466 self.figures[0].legend(ax.plt, labels, loc='center right')
466 self.figures[0].legend(ax.plt, labels, loc='center right')
467 else:
467 else:
468 for i, line in enumerate(ax.plt):
468 for i, line in enumerate(ax.plt):
469 line.set_data(x, z[n, :, i])
469 line.set_data(x, z[n, :, index[i]])
470 self.titles.append('CH {}'.format(n))
470 self.titles.append('CH {}'.format(n))
471
471
472
472
473 class BeaconPhase(Plot):
473 class BeaconPhase(Plot):
474
474
475 __isConfig = None
475 __isConfig = None
476 __nsubplots = None
476 __nsubplots = None
477
477
478 PREFIX = 'beacon_phase'
478 PREFIX = 'beacon_phase'
479
479
480 def __init__(self):
480 def __init__(self):
481 Plot.__init__(self)
481 Plot.__init__(self)
482 self.timerange = 24*60*60
482 self.timerange = 24*60*60
483 self.isConfig = False
483 self.isConfig = False
484 self.__nsubplots = 1
484 self.__nsubplots = 1
485 self.counter_imagwr = 0
485 self.counter_imagwr = 0
486 self.WIDTH = 800
486 self.WIDTH = 800
487 self.HEIGHT = 400
487 self.HEIGHT = 400
488 self.WIDTHPROF = 120
488 self.WIDTHPROF = 120
489 self.HEIGHTPROF = 0
489 self.HEIGHTPROF = 0
490 self.xdata = None
490 self.xdata = None
491 self.ydata = None
491 self.ydata = None
492
492
493 self.PLOT_CODE = BEACON_CODE
493 self.PLOT_CODE = BEACON_CODE
494
494
495 self.FTP_WEI = None
495 self.FTP_WEI = None
496 self.EXP_CODE = None
496 self.EXP_CODE = None
497 self.SUB_EXP_CODE = None
497 self.SUB_EXP_CODE = None
498 self.PLOT_POS = None
498 self.PLOT_POS = None
499
499
500 self.filename_phase = None
500 self.filename_phase = None
501
501
502 self.figfile = None
502 self.figfile = None
503
503
504 self.xmin = None
504 self.xmin = None
505 self.xmax = None
505 self.xmax = None
506
506
507 def getSubplots(self):
507 def getSubplots(self):
508
508
509 ncol = 1
509 ncol = 1
510 nrow = 1
510 nrow = 1
511
511
512 return nrow, ncol
512 return nrow, ncol
513
513
514 def setup(self, id, nplots, wintitle, showprofile=True, show=True):
514 def setup(self, id, nplots, wintitle, showprofile=True, show=True):
515
515
516 self.__showprofile = showprofile
516 self.__showprofile = showprofile
517 self.nplots = nplots
517 self.nplots = nplots
518
518
519 ncolspan = 7
519 ncolspan = 7
520 colspan = 6
520 colspan = 6
521 self.__nsubplots = 2
521 self.__nsubplots = 2
522
522
523 self.createFigure(id = id,
523 self.createFigure(id = id,
524 wintitle = wintitle,
524 wintitle = wintitle,
525 widthplot = self.WIDTH+self.WIDTHPROF,
525 widthplot = self.WIDTH+self.WIDTHPROF,
526 heightplot = self.HEIGHT+self.HEIGHTPROF,
526 heightplot = self.HEIGHT+self.HEIGHTPROF,
527 show=show)
527 show=show)
528
528
529 nrow, ncol = self.getSubplots()
529 nrow, ncol = self.getSubplots()
530
530
531 self.addAxes(nrow, ncol*ncolspan, 0, 0, colspan, 1)
531 self.addAxes(nrow, ncol*ncolspan, 0, 0, colspan, 1)
532
532
533 def save_phase(self, filename_phase):
533 def save_phase(self, filename_phase):
534 f = open(filename_phase,'w+')
534 f = open(filename_phase,'w+')
535 f.write('\n\n')
535 f.write('\n\n')
536 f.write('JICAMARCA RADIO OBSERVATORY - Beacon Phase \n')
536 f.write('JICAMARCA RADIO OBSERVATORY - Beacon Phase \n')
537 f.write('DD MM YYYY HH MM SS pair(2,0) pair(2,1) pair(2,3) pair(2,4)\n\n' )
537 f.write('DD MM YYYY HH MM SS pair(2,0) pair(2,1) pair(2,3) pair(2,4)\n\n' )
538 f.close()
538 f.close()
539
539
540 def save_data(self, filename_phase, data, data_datetime):
540 def save_data(self, filename_phase, data, data_datetime):
541 f=open(filename_phase,'a')
541 f=open(filename_phase,'a')
542 timetuple_data = data_datetime.timetuple()
542 timetuple_data = data_datetime.timetuple()
543 day = str(timetuple_data.tm_mday)
543 day = str(timetuple_data.tm_mday)
544 month = str(timetuple_data.tm_mon)
544 month = str(timetuple_data.tm_mon)
545 year = str(timetuple_data.tm_year)
545 year = str(timetuple_data.tm_year)
546 hour = str(timetuple_data.tm_hour)
546 hour = str(timetuple_data.tm_hour)
547 minute = str(timetuple_data.tm_min)
547 minute = str(timetuple_data.tm_min)
548 second = str(timetuple_data.tm_sec)
548 second = str(timetuple_data.tm_sec)
549 f.write(day+' '+month+' '+year+' '+hour+' '+minute+' '+second+' '+str(data[0])+' '+str(data[1])+' '+str(data[2])+' '+str(data[3])+'\n')
549 f.write(day+' '+month+' '+year+' '+hour+' '+minute+' '+second+' '+str(data[0])+' '+str(data[1])+' '+str(data[2])+' '+str(data[3])+'\n')
550 f.close()
550 f.close()
551
551
552 def plot(self):
552 def plot(self):
553 log.warning('TODO: Not yet implemented...')
553 log.warning('TODO: Not yet implemented...')
554
554
555 def run(self, dataOut, id, wintitle="", pairsList=None, showprofile='True',
555 def run(self, dataOut, id, wintitle="", pairsList=None, showprofile='True',
556 xmin=None, xmax=None, ymin=None, ymax=None, hmin=None, hmax=None,
556 xmin=None, xmax=None, ymin=None, ymax=None, hmin=None, hmax=None,
557 timerange=None,
557 timerange=None,
558 save=False, figpath='./', figfile=None, show=True, ftp=False, wr_period=1,
558 save=False, figpath='./', figfile=None, show=True, ftp=False, wr_period=1,
559 server=None, folder=None, username=None, password=None,
559 server=None, folder=None, username=None, password=None,
560 ftp_wei=0, exp_code=0, sub_exp_code=0, plot_pos=0):
560 ftp_wei=0, exp_code=0, sub_exp_code=0, plot_pos=0):
561
561
562 if dataOut.flagNoData:
562 if dataOut.flagNoData:
563 return dataOut
563 return dataOut
564
564
565 if not isTimeInHourRange(dataOut.datatime, xmin, xmax):
565 if not isTimeInHourRange(dataOut.datatime, xmin, xmax):
566 return
566 return
567
567
568 if pairsList == None:
568 if pairsList == None:
569 pairsIndexList = dataOut.pairsIndexList[:10]
569 pairsIndexList = dataOut.pairsIndexList[:10]
570 else:
570 else:
571 pairsIndexList = []
571 pairsIndexList = []
572 for pair in pairsList:
572 for pair in pairsList:
573 if pair not in dataOut.pairsList:
573 if pair not in dataOut.pairsList:
574 raise ValueError("Pair %s is not in dataOut.pairsList" %(pair))
574 raise ValueError("Pair %s is not in dataOut.pairsList" %(pair))
575 pairsIndexList.append(dataOut.pairsList.index(pair))
575 pairsIndexList.append(dataOut.pairsList.index(pair))
576
576
577 if pairsIndexList == []:
577 if pairsIndexList == []:
578 return
578 return
579
579
580 # if len(pairsIndexList) > 4:
580 # if len(pairsIndexList) > 4:
581 # pairsIndexList = pairsIndexList[0:4]
581 # pairsIndexList = pairsIndexList[0:4]
582
582
583 hmin_index = None
583 hmin_index = None
584 hmax_index = None
584 hmax_index = None
585
585
586 if hmin != None and hmax != None:
586 if hmin != None and hmax != None:
587 indexes = numpy.arange(dataOut.nHeights)
587 indexes = numpy.arange(dataOut.nHeights)
588 hmin_list = indexes[dataOut.heightList >= hmin]
588 hmin_list = indexes[dataOut.heightList >= hmin]
589 hmax_list = indexes[dataOut.heightList <= hmax]
589 hmax_list = indexes[dataOut.heightList <= hmax]
590
590
591 if hmin_list.any():
591 if hmin_list.any():
592 hmin_index = hmin_list[0]
592 hmin_index = hmin_list[0]
593
593
594 if hmax_list.any():
594 if hmax_list.any():
595 hmax_index = hmax_list[-1]+1
595 hmax_index = hmax_list[-1]+1
596
596
597 x = dataOut.getTimeRange()
597 x = dataOut.getTimeRange()
598
598
599 thisDatetime = dataOut.datatime
599 thisDatetime = dataOut.datatime
600
600
601 title = wintitle + " Signal Phase" # : %s" %(thisDatetime.strftime("%d-%b-%Y"))
601 title = wintitle + " Signal Phase" # : %s" %(thisDatetime.strftime("%d-%b-%Y"))
602 xlabel = "Local Time"
602 xlabel = "Local Time"
603 ylabel = "Phase (degrees)"
603 ylabel = "Phase (degrees)"
604
604
605 update_figfile = False
605 update_figfile = False
606
606
607 nplots = len(pairsIndexList)
607 nplots = len(pairsIndexList)
608 #phase = numpy.zeros((len(pairsIndexList),len(dataOut.beacon_heiIndexList)))
608 #phase = numpy.zeros((len(pairsIndexList),len(dataOut.beacon_heiIndexList)))
609 phase_beacon = numpy.zeros(len(pairsIndexList))
609 phase_beacon = numpy.zeros(len(pairsIndexList))
610 for i in range(nplots):
610 for i in range(nplots):
611 pair = dataOut.pairsList[pairsIndexList[i]]
611 pair = dataOut.pairsList[pairsIndexList[i]]
612 ccf = numpy.average(dataOut.data_cspc[pairsIndexList[i], :, hmin_index:hmax_index], axis=0)
612 ccf = numpy.average(dataOut.data_cspc[pairsIndexList[i], :, hmin_index:hmax_index], axis=0)
613 powa = numpy.average(dataOut.data_spc[pair[0], :, hmin_index:hmax_index], axis=0)
613 powa = numpy.average(dataOut.data_spc[pair[0], :, hmin_index:hmax_index], axis=0)
614 powb = numpy.average(dataOut.data_spc[pair[1], :, hmin_index:hmax_index], axis=0)
614 powb = numpy.average(dataOut.data_spc[pair[1], :, hmin_index:hmax_index], axis=0)
615 avgcoherenceComplex = ccf/numpy.sqrt(powa*powb)
615 avgcoherenceComplex = ccf/numpy.sqrt(powa*powb)
616 phase = numpy.arctan2(avgcoherenceComplex.imag, avgcoherenceComplex.real)*180/numpy.pi
616 phase = numpy.arctan2(avgcoherenceComplex.imag, avgcoherenceComplex.real)*180/numpy.pi
617
617
618 if dataOut.beacon_heiIndexList:
618 if dataOut.beacon_heiIndexList:
619 phase_beacon[i] = numpy.average(phase[dataOut.beacon_heiIndexList])
619 phase_beacon[i] = numpy.average(phase[dataOut.beacon_heiIndexList])
620 else:
620 else:
621 phase_beacon[i] = numpy.average(phase)
621 phase_beacon[i] = numpy.average(phase)
622
622
623 if not self.isConfig:
623 if not self.isConfig:
624
624
625 nplots = len(pairsIndexList)
625 nplots = len(pairsIndexList)
626
626
627 self.setup(id=id,
627 self.setup(id=id,
628 nplots=nplots,
628 nplots=nplots,
629 wintitle=wintitle,
629 wintitle=wintitle,
630 showprofile=showprofile,
630 showprofile=showprofile,
631 show=show)
631 show=show)
632
632
633 if timerange != None:
633 if timerange != None:
634 self.timerange = timerange
634 self.timerange = timerange
635
635
636 self.xmin, self.xmax = self.getTimeLim(x, xmin, xmax, timerange)
636 self.xmin, self.xmax = self.getTimeLim(x, xmin, xmax, timerange)
637
637
638 if ymin == None: ymin = 0
638 if ymin == None: ymin = 0
639 if ymax == None: ymax = 360
639 if ymax == None: ymax = 360
640
640
641 self.FTP_WEI = ftp_wei
641 self.FTP_WEI = ftp_wei
642 self.EXP_CODE = exp_code
642 self.EXP_CODE = exp_code
643 self.SUB_EXP_CODE = sub_exp_code
643 self.SUB_EXP_CODE = sub_exp_code
644 self.PLOT_POS = plot_pos
644 self.PLOT_POS = plot_pos
645
645
646 self.name = thisDatetime.strftime("%Y%m%d_%H%M%S")
646 self.name = thisDatetime.strftime("%Y%m%d_%H%M%S")
647 self.isConfig = True
647 self.isConfig = True
648 self.figfile = figfile
648 self.figfile = figfile
649 self.xdata = numpy.array([])
649 self.xdata = numpy.array([])
650 self.ydata = numpy.array([])
650 self.ydata = numpy.array([])
651
651
652 update_figfile = True
652 update_figfile = True
653
653
654 #open file beacon phase
654 #open file beacon phase
655 path = '%s%03d' %(self.PREFIX, self.id)
655 path = '%s%03d' %(self.PREFIX, self.id)
656 beacon_file = os.path.join(path,'%s.txt'%self.name)
656 beacon_file = os.path.join(path,'%s.txt'%self.name)
657 self.filename_phase = os.path.join(figpath,beacon_file)
657 self.filename_phase = os.path.join(figpath,beacon_file)
658 #self.save_phase(self.filename_phase)
658 #self.save_phase(self.filename_phase)
659
659
660
660
661 #store data beacon phase
661 #store data beacon phase
662 #self.save_data(self.filename_phase, phase_beacon, thisDatetime)
662 #self.save_data(self.filename_phase, phase_beacon, thisDatetime)
663
663
664 self.setWinTitle(title)
664 self.setWinTitle(title)
665
665
666
666
667 title = "Phase Plot %s" %(thisDatetime.strftime("%Y/%m/%d %H:%M:%S"))
667 title = "Phase Plot %s" %(thisDatetime.strftime("%Y/%m/%d %H:%M:%S"))
668
668
669 legendlabels = ["Pair (%d,%d)"%(pair[0], pair[1]) for pair in dataOut.pairsList]
669 legendlabels = ["Pair (%d,%d)"%(pair[0], pair[1]) for pair in dataOut.pairsList]
670
670
671 axes = self.axesList[0]
671 axes = self.axesList[0]
672
672
673 self.xdata = numpy.hstack((self.xdata, x[0:1]))
673 self.xdata = numpy.hstack((self.xdata, x[0:1]))
674
674
675 if len(self.ydata)==0:
675 if len(self.ydata)==0:
676 self.ydata = phase_beacon.reshape(-1,1)
676 self.ydata = phase_beacon.reshape(-1,1)
677 else:
677 else:
678 self.ydata = numpy.hstack((self.ydata, phase_beacon.reshape(-1,1)))
678 self.ydata = numpy.hstack((self.ydata, phase_beacon.reshape(-1,1)))
679
679
680
680
681 axes.pmultilineyaxis(x=self.xdata, y=self.ydata,
681 axes.pmultilineyaxis(x=self.xdata, y=self.ydata,
682 xmin=self.xmin, xmax=self.xmax, ymin=ymin, ymax=ymax,
682 xmin=self.xmin, xmax=self.xmax, ymin=ymin, ymax=ymax,
683 xlabel=xlabel, ylabel=ylabel, title=title, legendlabels=legendlabels, marker='x', markersize=8, linestyle="solid",
683 xlabel=xlabel, ylabel=ylabel, title=title, legendlabels=legendlabels, marker='x', markersize=8, linestyle="solid",
684 XAxisAsTime=True, grid='both'
684 XAxisAsTime=True, grid='both'
685 )
685 )
686
686
687 self.draw()
687 self.draw()
688
688
689 if dataOut.ltctime >= self.xmax:
689 if dataOut.ltctime >= self.xmax:
690 self.counter_imagwr = wr_period
690 self.counter_imagwr = wr_period
691 self.isConfig = False
691 self.isConfig = False
692 update_figfile = True
692 update_figfile = True
693
693
694 self.save(figpath=figpath,
694 self.save(figpath=figpath,
695 figfile=figfile,
695 figfile=figfile,
696 save=save,
696 save=save,
697 ftp=ftp,
697 ftp=ftp,
698 wr_period=wr_period,
698 wr_period=wr_period,
699 thisDatetime=thisDatetime,
699 thisDatetime=thisDatetime,
700 update_figfile=update_figfile)
700 update_figfile=update_figfile)
701
701
702 return dataOut No newline at end of file
702 return dataOut
General Comments 0
You need to be logged in to leave comments. Login now