##// END OF EJS Templates
change mask attr in Weatherparamplot
Juan C. Espinoza -
r1515:913bfb91ded8
parent child
Show More
@@ -1,732 +1,732
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,re
18 import matplotlib,re
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 .plotting_codes import *
36 from .plotting_codes import *
37
37
38 from schainpy.model.data.jrodata import PlotterData
38 from schainpy.model.data.jrodata import PlotterData
39 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
39 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
40 from schainpy.utils import log
40 from schainpy.utils import log
41
41
42 for name, cb_table in sophy_cb_tables:
42 for name, cb_table in sophy_cb_tables:
43 ncmap = matplotlib.colors.ListedColormap(cb_table, name=name)
43 ncmap = matplotlib.colors.ListedColormap(cb_table, name=name)
44 matplotlib.pyplot.register_cmap(cmap=ncmap)
44 matplotlib.pyplot.register_cmap(cmap=ncmap)
45
45
46 EARTH_RADIUS = 6.3710e3
46 EARTH_RADIUS = 6.3710e3
47
47
48 def ll2xy(lat1, lon1, lat2, lon2):
48 def ll2xy(lat1, lon1, lat2, lon2):
49
49
50 p = 0.017453292519943295
50 p = 0.017453292519943295
51 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
51 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
52 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
52 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
53 r = 12742 * numpy.arcsin(numpy.sqrt(a))
53 r = 12742 * numpy.arcsin(numpy.sqrt(a))
54 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
54 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
55 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
55 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
56 theta = -theta + numpy.pi/2
56 theta = -theta + numpy.pi/2
57 return r*numpy.cos(theta), r*numpy.sin(theta)
57 return r*numpy.cos(theta), r*numpy.sin(theta)
58
58
59
59
60 def km2deg(km):
60 def km2deg(km):
61 '''
61 '''
62 Convert distance in km to degrees
62 Convert distance in km to degrees
63 '''
63 '''
64
64
65 return numpy.rad2deg(km/EARTH_RADIUS)
65 return numpy.rad2deg(km/EARTH_RADIUS)
66
66
67
67
68 def figpause(interval):
68 def figpause(interval):
69 backend = plt.rcParams['backend']
69 backend = plt.rcParams['backend']
70 if backend in matplotlib.rcsetup.interactive_bk:
70 if backend in matplotlib.rcsetup.interactive_bk:
71 figManager = matplotlib._pylab_helpers.Gcf.get_active()
71 figManager = matplotlib._pylab_helpers.Gcf.get_active()
72 if figManager is not None:
72 if figManager is not None:
73 canvas = figManager.canvas
73 canvas = figManager.canvas
74 if canvas.figure.stale:
74 if canvas.figure.stale:
75 canvas.draw()
75 canvas.draw()
76 try:
76 try:
77 canvas.start_event_loop(interval)
77 canvas.start_event_loop(interval)
78 except:
78 except:
79 pass
79 pass
80 return
80 return
81
81
82 def popup(message):
82 def popup(message):
83 '''
83 '''
84 '''
84 '''
85
85
86 fig = plt.figure(figsize=(12, 8), facecolor='r')
86 fig = plt.figure(figsize=(12, 8), facecolor='r')
87 text = '\n'.join([s.strip() for s in message.split(':')])
87 text = '\n'.join([s.strip() for s in message.split(':')])
88 fig.text(0.01, 0.5, text, ha='left', va='center',
88 fig.text(0.01, 0.5, text, ha='left', va='center',
89 size='20', weight='heavy', color='w')
89 size='20', weight='heavy', color='w')
90 fig.show()
90 fig.show()
91 figpause(1000)
91 figpause(1000)
92
92
93
93
94 class Throttle(object):
94 class Throttle(object):
95 '''
95 '''
96 Decorator that prevents a function from being called more than once every
96 Decorator that prevents a function from being called more than once every
97 time period.
97 time period.
98 To create a function that cannot be called more than once a minute, but
98 To create a function that cannot be called more than once a minute, but
99 will sleep until it can be called:
99 will sleep until it can be called:
100 @Throttle(minutes=1)
100 @Throttle(minutes=1)
101 def foo():
101 def foo():
102 pass
102 pass
103
103
104 for i in range(10):
104 for i in range(10):
105 foo()
105 foo()
106 print "This function has run %s times." % i
106 print "This function has run %s times." % i
107 '''
107 '''
108
108
109 def __init__(self, seconds=0, minutes=0, hours=0):
109 def __init__(self, seconds=0, minutes=0, hours=0):
110 self.throttle_period = datetime.timedelta(
110 self.throttle_period = datetime.timedelta(
111 seconds=seconds, minutes=minutes, hours=hours
111 seconds=seconds, minutes=minutes, hours=hours
112 )
112 )
113
113
114 self.time_of_last_call = datetime.datetime.min
114 self.time_of_last_call = datetime.datetime.min
115
115
116 def __call__(self, fn):
116 def __call__(self, fn):
117 @wraps(fn)
117 @wraps(fn)
118 def wrapper(*args, **kwargs):
118 def wrapper(*args, **kwargs):
119 coerce = kwargs.pop('coerce', None)
119 coerce = kwargs.pop('coerce', None)
120 if coerce:
120 if coerce:
121 self.time_of_last_call = datetime.datetime.now()
121 self.time_of_last_call = datetime.datetime.now()
122 return fn(*args, **kwargs)
122 return fn(*args, **kwargs)
123 else:
123 else:
124 now = datetime.datetime.now()
124 now = datetime.datetime.now()
125 time_since_last_call = now - self.time_of_last_call
125 time_since_last_call = now - self.time_of_last_call
126 time_left = self.throttle_period - time_since_last_call
126 time_left = self.throttle_period - time_since_last_call
127
127
128 if time_left > datetime.timedelta(seconds=0):
128 if time_left > datetime.timedelta(seconds=0):
129 return
129 return
130
130
131 self.time_of_last_call = datetime.datetime.now()
131 self.time_of_last_call = datetime.datetime.now()
132 return fn(*args, **kwargs)
132 return fn(*args, **kwargs)
133
133
134 return wrapper
134 return wrapper
135
135
136 def apply_throttle(value):
136 def apply_throttle(value):
137
137
138 @Throttle(seconds=value)
138 @Throttle(seconds=value)
139 def fnThrottled(fn):
139 def fnThrottled(fn):
140 fn()
140 fn()
141
141
142 return fnThrottled
142 return fnThrottled
143
143
144
144
145 @MPDecorator
145 @MPDecorator
146 class Plot(Operation):
146 class Plot(Operation):
147 """Base class for Schain plotting operations
147 """Base class for Schain plotting operations
148
148
149 This class should never be use directtly you must subclass a new operation,
149 This class should never be use directtly you must subclass a new operation,
150 children classes must be defined as follow:
150 children classes must be defined as follow:
151
151
152 ExamplePlot(Plot):
152 ExamplePlot(Plot):
153
153
154 CODE = 'code'
154 CODE = 'code'
155 colormap = 'jet'
155 colormap = 'jet'
156 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
156 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
157
157
158 def setup(self):
158 def setup(self):
159 pass
159 pass
160
160
161 def plot(self):
161 def plot(self):
162 pass
162 pass
163
163
164 """
164 """
165
165
166 CODE = 'Figure'
166 CODE = 'Figure'
167 colormap = 'jet'
167 colormap = 'jet'
168 bgcolor = 'white'
168 bgcolor = 'white'
169 buffering = True
169 buffering = True
170 __missing = 1E30
170 __missing = 1E30
171
171
172 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
172 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
173 'showprofile']
173 'showprofile']
174
174
175 def __init__(self):
175 def __init__(self):
176
176
177 Operation.__init__(self)
177 Operation.__init__(self)
178 self.isConfig = False
178 self.isConfig = False
179 self.isPlotConfig = False
179 self.isPlotConfig = False
180 self.save_time = 0
180 self.save_time = 0
181 self.sender_time = 0
181 self.sender_time = 0
182 self.data = None
182 self.data = None
183 self.firsttime = True
183 self.firsttime = True
184 self.sender_queue = deque(maxlen=10)
184 self.sender_queue = deque(maxlen=10)
185 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
185 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
186
186
187 def __fmtTime(self, x, pos):
187 def __fmtTime(self, x, pos):
188 '''
188 '''
189 '''
189 '''
190
190
191 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
191 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
192
192
193 def __setup(self, **kwargs):
193 def __setup(self, **kwargs):
194 '''
194 '''
195 Initialize variables
195 Initialize variables
196 '''
196 '''
197
197
198 self.figures = []
198 self.figures = []
199 self.axes = []
199 self.axes = []
200 self.cb_axes = []
200 self.cb_axes = []
201 self.localtime = kwargs.pop('localtime', True)
201 self.localtime = kwargs.pop('localtime', True)
202 self.show = kwargs.get('show', True)
202 self.show = kwargs.get('show', True)
203 self.save = kwargs.get('save', False)
203 self.save = kwargs.get('save', False)
204 self.save_period = kwargs.get('save_period', 0)
204 self.save_period = kwargs.get('save_period', 0)
205 self.colormap = kwargs.get('colormap', self.colormap)
205 self.colormap = kwargs.get('colormap', self.colormap)
206 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
206 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
207 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
207 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
208 self.colormaps = kwargs.get('colormaps', None)
208 self.colormaps = kwargs.get('colormaps', None)
209 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
209 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
210 self.showprofile = kwargs.get('showprofile', False)
210 self.showprofile = kwargs.get('showprofile', False)
211 self.title = kwargs.get('wintitle', self.CODE.upper())
211 self.title = kwargs.get('wintitle', self.CODE.upper())
212 self.cb_label = kwargs.get('cb_label', None)
212 self.cb_label = kwargs.get('cb_label', None)
213 self.cb_labels = kwargs.get('cb_labels', None)
213 self.cb_labels = kwargs.get('cb_labels', None)
214 self.labels = kwargs.get('labels', None)
214 self.labels = kwargs.get('labels', None)
215 self.xaxis = kwargs.get('xaxis', 'frequency')
215 self.xaxis = kwargs.get('xaxis', 'frequency')
216 self.zmin = kwargs.get('zmin', None)
216 self.zmin = kwargs.get('zmin', None)
217 self.zmax = kwargs.get('zmax', None)
217 self.zmax = kwargs.get('zmax', None)
218 self.zlimits = kwargs.get('zlimits', None)
218 self.zlimits = kwargs.get('zlimits', None)
219 self.xmin = kwargs.get('xmin', None)
219 self.xmin = kwargs.get('xmin', None)
220 self.xmax = kwargs.get('xmax', None)
220 self.xmax = kwargs.get('xmax', None)
221 self.xrange = kwargs.get('xrange', 12)
221 self.xrange = kwargs.get('xrange', 12)
222 self.xscale = kwargs.get('xscale', None)
222 self.xscale = kwargs.get('xscale', None)
223 self.ymin = kwargs.get('ymin', None)
223 self.ymin = kwargs.get('ymin', None)
224 self.ymax = kwargs.get('ymax', None)
224 self.ymax = kwargs.get('ymax', None)
225 self.yscale = kwargs.get('yscale', None)
225 self.yscale = kwargs.get('yscale', None)
226 self.xlabel = kwargs.get('xlabel', None)
226 self.xlabel = kwargs.get('xlabel', None)
227 self.attr_time = kwargs.get('attr_time', 'utctime')
227 self.attr_time = kwargs.get('attr_time', 'utctime')
228 self.attr_data = kwargs.get('attr_data', 'data_param')
228 self.attr_data = kwargs.get('attr_data', 'data_param')
229 self.decimation = kwargs.get('decimation', None)
229 self.decimation = kwargs.get('decimation', None)
230 self.oneFigure = kwargs.get('oneFigure', True)
230 self.oneFigure = kwargs.get('oneFigure', True)
231 self.width = kwargs.get('width', None)
231 self.width = kwargs.get('width', None)
232 self.height = kwargs.get('height', None)
232 self.height = kwargs.get('height', None)
233 self.colorbar = kwargs.get('colorbar', True)
233 self.colorbar = kwargs.get('colorbar', True)
234 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
234 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
235 self.channels = kwargs.get('channels', None)
235 self.channels = kwargs.get('channels', None)
236 self.titles = kwargs.get('titles', [])
236 self.titles = kwargs.get('titles', [])
237 self.polar = False
237 self.polar = False
238 self.type = kwargs.get('type', 'iq')
238 self.type = kwargs.get('type', 'iq')
239 self.grid = kwargs.get('grid', False)
239 self.grid = kwargs.get('grid', False)
240 self.pause = kwargs.get('pause', False)
240 self.pause = kwargs.get('pause', False)
241 self.save_code = kwargs.get('save_code', self.CODE)
241 self.save_code = kwargs.get('save_code', self.CODE)
242 self.throttle = kwargs.get('throttle', 0)
242 self.throttle = kwargs.get('throttle', 0)
243 self.exp_code = kwargs.get('exp_code', None)
243 self.exp_code = kwargs.get('exp_code', None)
244 self.server = kwargs.get('server', False)
244 self.server = kwargs.get('server', False)
245 self.sender_period = kwargs.get('sender_period', 60)
245 self.sender_period = kwargs.get('sender_period', 60)
246 self.tag = kwargs.get('tag', '')
246 self.tag = kwargs.get('tag', '')
247 self.height_index = kwargs.get('height_index', None)
247 self.height_index = kwargs.get('height_index', None)
248 self.__throttle_plot = apply_throttle(self.throttle)
248 self.__throttle_plot = apply_throttle(self.throttle)
249 code = self.attr_data if self.attr_data else self.CODE
249 code = self.attr_data if self.attr_data else self.CODE
250 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
250 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
251 self.ang_min = kwargs.get('ang_min', None)
251 self.ang_min = kwargs.get('ang_min', None)
252 self.ang_max = kwargs.get('ang_max', None)
252 self.ang_max = kwargs.get('ang_max', None)
253 self.mode = kwargs.get('mode', None)
253 self.mode = kwargs.get('mode', None)
254 self.snr_threshold = kwargs.get('snr_threshold', 0)
254 self.mask = kwargs.get('mask', False)
255
255
256
256
257 if self.server:
257 if self.server:
258 if not self.server.startswith('tcp://'):
258 if not self.server.startswith('tcp://'):
259 self.server = 'tcp://{}'.format(self.server)
259 self.server = 'tcp://{}'.format(self.server)
260 log.success(
260 log.success(
261 'Sending to server: {}'.format(self.server),
261 'Sending to server: {}'.format(self.server),
262 self.name
262 self.name
263 )
263 )
264
264
265 if isinstance(self.attr_data, str):
265 if isinstance(self.attr_data, str):
266 self.attr_data = [self.attr_data]
266 self.attr_data = [self.attr_data]
267
267
268 def __setup_plot(self):
268 def __setup_plot(self):
269 '''
269 '''
270 Common setup for all figures, here figures and axes are created
270 Common setup for all figures, here figures and axes are created
271 '''
271 '''
272
272
273 self.setup()
273 self.setup()
274
274
275 self.time_label = 'LT' if self.localtime else 'UTC'
275 self.time_label = 'LT' if self.localtime else 'UTC'
276
276
277 if self.width is None:
277 if self.width is None:
278 self.width = 8
278 self.width = 8
279
279
280 self.figures = []
280 self.figures = []
281 self.axes = []
281 self.axes = []
282 self.cb_axes = []
282 self.cb_axes = []
283 self.pf_axes = []
283 self.pf_axes = []
284 self.cmaps = []
284 self.cmaps = []
285
285
286 size = '15%' if self.ncols == 1 else '30%'
286 size = '15%' if self.ncols == 1 else '30%'
287 pad = '4%' if self.ncols == 1 else '8%'
287 pad = '4%' if self.ncols == 1 else '8%'
288
288
289 if self.oneFigure:
289 if self.oneFigure:
290 if self.height is None:
290 if self.height is None:
291 self.height = 1.4 * self.nrows + 1
291 self.height = 1.4 * self.nrows + 1
292 fig = plt.figure(figsize=(self.width, self.height),
292 fig = plt.figure(figsize=(self.width, self.height),
293 edgecolor='k',
293 edgecolor='k',
294 facecolor='w')
294 facecolor='w')
295 self.figures.append(fig)
295 self.figures.append(fig)
296 for n in range(self.nplots):
296 for n in range(self.nplots):
297 ax = fig.add_subplot(self.nrows, self.ncols,
297 ax = fig.add_subplot(self.nrows, self.ncols,
298 n + 1, polar=self.polar)
298 n + 1, polar=self.polar)
299 ax.tick_params(labelsize=8)
299 ax.tick_params(labelsize=8)
300 ax.firsttime = True
300 ax.firsttime = True
301 ax.index = 0
301 ax.index = 0
302 ax.press = None
302 ax.press = None
303 self.axes.append(ax)
303 self.axes.append(ax)
304 if self.showprofile:
304 if self.showprofile:
305 cax = self.__add_axes(ax, size=size, pad=pad)
305 cax = self.__add_axes(ax, size=size, pad=pad)
306 cax.tick_params(labelsize=8)
306 cax.tick_params(labelsize=8)
307 self.pf_axes.append(cax)
307 self.pf_axes.append(cax)
308 else:
308 else:
309 if self.height is None:
309 if self.height is None:
310 self.height = 3
310 self.height = 3
311 for n in range(self.nplots):
311 for n in range(self.nplots):
312 fig = plt.figure(figsize=(self.width, self.height),
312 fig = plt.figure(figsize=(self.width, self.height),
313 edgecolor='k',
313 edgecolor='k',
314 facecolor='w')
314 facecolor='w')
315 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
315 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
316 ax.tick_params(labelsize=8)
316 ax.tick_params(labelsize=8)
317 ax.firsttime = True
317 ax.firsttime = True
318 ax.index = 0
318 ax.index = 0
319 ax.press = None
319 ax.press = None
320 self.figures.append(fig)
320 self.figures.append(fig)
321 self.axes.append(ax)
321 self.axes.append(ax)
322 if self.showprofile:
322 if self.showprofile:
323 cax = self.__add_axes(ax, size=size, pad=pad)
323 cax = self.__add_axes(ax, size=size, pad=pad)
324 cax.tick_params(labelsize=8)
324 cax.tick_params(labelsize=8)
325 self.pf_axes.append(cax)
325 self.pf_axes.append(cax)
326
326
327 for n in range(self.nrows):
327 for n in range(self.nrows):
328 if self.colormaps is not None:
328 if self.colormaps is not None:
329 cmap = plt.get_cmap(self.colormaps[n])
329 cmap = plt.get_cmap(self.colormaps[n])
330 else:
330 else:
331 cmap = plt.get_cmap(self.colormap)
331 cmap = plt.get_cmap(self.colormap)
332 cmap.set_bad(self.bgcolor, 1.)
332 cmap.set_bad(self.bgcolor, 1.)
333 self.cmaps.append(cmap)
333 self.cmaps.append(cmap)
334
334
335 def __add_axes(self, ax, size='30%', pad='8%'):
335 def __add_axes(self, ax, size='30%', pad='8%'):
336 '''
336 '''
337 Add new axes to the given figure
337 Add new axes to the given figure
338 '''
338 '''
339 divider = make_axes_locatable(ax)
339 divider = make_axes_locatable(ax)
340 nax = divider.new_horizontal(size=size, pad=pad)
340 nax = divider.new_horizontal(size=size, pad=pad)
341 ax.figure.add_axes(nax)
341 ax.figure.add_axes(nax)
342 return nax
342 return nax
343
343
344 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
344 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
345 '''
345 '''
346 Create a masked array for missing data
346 Create a masked array for missing data
347 '''
347 '''
348 if x_buffer.shape[0] < 2:
348 if x_buffer.shape[0] < 2:
349 return x_buffer, y_buffer, z_buffer
349 return x_buffer, y_buffer, z_buffer
350
350
351 deltas = x_buffer[1:] - x_buffer[0:-1]
351 deltas = x_buffer[1:] - x_buffer[0:-1]
352 x_median = numpy.median(deltas)
352 x_median = numpy.median(deltas)
353
353
354 index = numpy.where(deltas > 5 * x_median)
354 index = numpy.where(deltas > 5 * x_median)
355
355
356 if len(index[0]) != 0:
356 if len(index[0]) != 0:
357 z_buffer[::, index[0], ::] = self.__missing
357 z_buffer[::, index[0], ::] = self.__missing
358 z_buffer = numpy.ma.masked_inside(z_buffer,
358 z_buffer = numpy.ma.masked_inside(z_buffer,
359 0.99 * self.__missing,
359 0.99 * self.__missing,
360 1.01 * self.__missing)
360 1.01 * self.__missing)
361
361
362 return x_buffer, y_buffer, z_buffer
362 return x_buffer, y_buffer, z_buffer
363
363
364 def decimate(self):
364 def decimate(self):
365
365
366 # dx = int(len(self.x)/self.__MAXNUMX) + 1
366 # dx = int(len(self.x)/self.__MAXNUMX) + 1
367 dy = int(len(self.y) / self.decimation) + 1
367 dy = int(len(self.y) / self.decimation) + 1
368
368
369 # x = self.x[::dx]
369 # x = self.x[::dx]
370 x = self.x
370 x = self.x
371 y = self.y[::dy]
371 y = self.y[::dy]
372 z = self.z[::, ::, ::dy]
372 z = self.z[::, ::, ::dy]
373
373
374 return x, y, z
374 return x, y, z
375
375
376 def format(self):
376 def format(self):
377 '''
377 '''
378 Set min and max values, labels, ticks and titles
378 Set min and max values, labels, ticks and titles
379 '''
379 '''
380
380
381 for n, ax in enumerate(self.axes):
381 for n, ax in enumerate(self.axes):
382 if ax.firsttime:
382 if ax.firsttime:
383 if self.xaxis != 'time':
383 if self.xaxis != 'time':
384 xmin = self.xmin
384 xmin = self.xmin
385 xmax = self.xmax
385 xmax = self.xmax
386 else:
386 else:
387 xmin = self.tmin
387 xmin = self.tmin
388 xmax = self.tmin + self.xrange*60*60
388 xmax = self.tmin + self.xrange*60*60
389 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
389 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
390 ax.xaxis.set_major_locator(LinearLocator(9))
390 ax.xaxis.set_major_locator(LinearLocator(9))
391 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)])
392 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)])
393 ax.set_facecolor(self.bgcolor)
393 ax.set_facecolor(self.bgcolor)
394 if self.xscale:
394 if self.xscale:
395 ax.xaxis.set_major_formatter(FuncFormatter(
395 ax.xaxis.set_major_formatter(FuncFormatter(
396 lambda x, pos: '{0:g}'.format(x*self.xscale)))
396 lambda x, pos: '{0:g}'.format(x*self.xscale)))
397 if self.yscale:
397 if self.yscale:
398 ax.yaxis.set_major_formatter(FuncFormatter(
398 ax.yaxis.set_major_formatter(FuncFormatter(
399 lambda x, pos: '{0:g}'.format(x*self.yscale)))
399 lambda x, pos: '{0:g}'.format(x*self.yscale)))
400 if self.xlabel is not None:
400 if self.xlabel is not None:
401 ax.set_xlabel(self.xlabel)
401 ax.set_xlabel(self.xlabel)
402 if self.ylabel is not None:
402 if self.ylabel is not None:
403 ax.set_ylabel(self.ylabel)
403 ax.set_ylabel(self.ylabel)
404 if self.showprofile:
404 if self.showprofile:
405 self.pf_axes[n].set_ylim(ymin, ymax)
405 self.pf_axes[n].set_ylim(ymin, ymax)
406 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
406 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
407 self.pf_axes[n].set_xlabel('dB')
407 self.pf_axes[n].set_xlabel('dB')
408 self.pf_axes[n].grid(b=True, axis='x')
408 self.pf_axes[n].grid(b=True, axis='x')
409 [tick.set_visible(False)
409 [tick.set_visible(False)
410 for tick in self.pf_axes[n].get_yticklabels()]
410 for tick in self.pf_axes[n].get_yticklabels()]
411 if self.colorbar:
411 if self.colorbar:
412 ax.cbar = plt.colorbar(
412 ax.cbar = plt.colorbar(
413 ax.plt, ax=ax, fraction=0.05, pad=0.06, aspect=10)
413 ax.plt, ax=ax, fraction=0.05, pad=0.06, aspect=10)
414 ax.cbar.ax.tick_params(labelsize=8)
414 ax.cbar.ax.tick_params(labelsize=8)
415 ax.cbar.ax.press = None
415 ax.cbar.ax.press = None
416 if self.cb_label:
416 if self.cb_label:
417 ax.cbar.set_label(self.cb_label, size=8)
417 ax.cbar.set_label(self.cb_label, size=8)
418 elif self.cb_labels:
418 elif self.cb_labels:
419 ax.cbar.set_label(self.cb_labels[n], size=8)
419 ax.cbar.set_label(self.cb_labels[n], size=8)
420 else:
420 else:
421 ax.cbar = None
421 ax.cbar = None
422 ax.set_xlim(xmin, xmax)
422 ax.set_xlim(xmin, xmax)
423 ax.set_ylim(ymin, ymax)
423 ax.set_ylim(ymin, ymax)
424 ax.firsttime = False
424 ax.firsttime = False
425 if self.grid:
425 if self.grid:
426 ax.grid(True)
426 ax.grid(True)
427 if not self.polar:
427 if not self.polar:
428 ax.set_title('{} {} {}'.format(
428 ax.set_title('{} {} {}'.format(
429 self.titles[n],
429 self.titles[n],
430 self.getDateTime(self.data.max_time).strftime(
430 self.getDateTime(self.data.max_time).strftime(
431 '%Y-%m-%d %H:%M:%S'),
431 '%Y-%m-%d %H:%M:%S'),
432 self.time_label),
432 self.time_label),
433 size=8)
433 size=8)
434 else:
434 else:
435 #ax.set_title('{}'.format(self.titles[n]), size=8)
435 #ax.set_title('{}'.format(self.titles[n]), size=8)
436 ax.set_title('{} {} {}'.format(
436 ax.set_title('{} {} {}'.format(
437 self.titles[n],
437 self.titles[n],
438 self.getDateTime(self.data.max_time).strftime(
438 self.getDateTime(self.data.max_time).strftime(
439 '%Y-%m-%d %H:%M:%S'),
439 '%Y-%m-%d %H:%M:%S'),
440 self.time_label),
440 self.time_label),
441 size=8)
441 size=8)
442 ax.set_ylim(0, self.ymax)
442 ax.set_ylim(0, self.ymax)
443 ax.set_yticks(ax.get_yticks(), labels=ax.get_yticks(), color='white')
443 ax.set_yticks(ax.get_yticks(), labels=ax.get_yticks(), color='white')
444 ax.yaxis.labelpad = 28
444 ax.yaxis.labelpad = 28
445
445
446 if self.firsttime:
446 if self.firsttime:
447 for n, fig in enumerate(self.figures):
447 for n, fig in enumerate(self.figures):
448 fig.subplots_adjust(**self.plots_adjust)
448 fig.subplots_adjust(**self.plots_adjust)
449 self.firsttime = False
449 self.firsttime = False
450
450
451 def clear_figures(self):
451 def clear_figures(self):
452 '''
452 '''
453 Reset axes for redraw plots
453 Reset axes for redraw plots
454 '''
454 '''
455
455
456 for ax in self.axes+self.pf_axes+self.cb_axes:
456 for ax in self.axes+self.pf_axes+self.cb_axes:
457 ax.clear()
457 ax.clear()
458 ax.firsttime = True
458 ax.firsttime = True
459 if hasattr(ax, 'cbar') and ax.cbar:
459 if hasattr(ax, 'cbar') and ax.cbar:
460 ax.cbar.remove()
460 ax.cbar.remove()
461
461
462 def __plot(self):
462 def __plot(self):
463 '''
463 '''
464 Main function to plot, format and save figures
464 Main function to plot, format and save figures
465 '''
465 '''
466
466
467 self.plot()
467 self.plot()
468 self.format()
468 self.format()
469
469
470 for n, fig in enumerate(self.figures):
470 for n, fig in enumerate(self.figures):
471 if self.nrows == 0 or self.nplots == 0:
471 if self.nrows == 0 or self.nplots == 0:
472 log.warning('No data', self.name)
472 log.warning('No data', self.name)
473 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
473 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
474 fig.canvas.manager.set_window_title(self.CODE)
474 fig.canvas.manager.set_window_title(self.CODE)
475 continue
475 continue
476
476
477 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
477 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
478 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
478 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
479 fig.canvas.draw()
479 fig.canvas.draw()
480 if self.show:
480 if self.show:
481 fig.show()
481 fig.show()
482 figpause(0.01)
482 figpause(0.01)
483
483
484 if self.save:
484 if self.save:
485 if self.CODE=="PPI" or self.CODE=="RHI":
485 if self.CODE=="PPI" or self.CODE=="RHI":
486 self.save_figure(n,stitle =self.titles)
486 self.save_figure(n,stitle =self.titles)
487 else:
487 else:
488 self.save_figure(n)
488 self.save_figure(n)
489
489
490 if self.server:
490 if self.server:
491 self.send_to_server()
491 self.send_to_server()
492
492
493 def __update(self, dataOut, timestamp):
493 def __update(self, dataOut, timestamp):
494 '''
494 '''
495 '''
495 '''
496
496
497 metadata = {
497 metadata = {
498 'yrange': dataOut.heightList,
498 'yrange': dataOut.heightList,
499 'interval': dataOut.timeInterval,
499 'interval': dataOut.timeInterval,
500 'channels': dataOut.channelList
500 'channels': dataOut.channelList
501 }
501 }
502
502
503 data, meta = self.update(dataOut)
503 data, meta = self.update(dataOut)
504 metadata.update(meta)
504 metadata.update(meta)
505 self.data.update(data, timestamp, metadata)
505 self.data.update(data, timestamp, metadata)
506
506
507 def save_figure(self, n,stitle=None):
507 def save_figure(self, n,stitle=None):
508 '''
508 '''
509 '''
509 '''
510 if stitle is not None:
510 if stitle is not None:
511 s_string = re.sub(r"[^A-Z0-9.]","",str(stitle))
511 s_string = re.sub(r"[^A-Z0-9.]","",str(stitle))
512 new_string=s_string[:3]+"_"+s_string[4:6]+"_"+s_string[6:]
512 new_string=s_string[:3]+"_"+s_string[4:6]+"_"+s_string[6:]
513
513
514 if self.oneFigure:
514 if self.oneFigure:
515 if (self.data.max_time - self.save_time) <= self.save_period:
515 if (self.data.max_time - self.save_time) <= self.save_period:
516 return
516 return
517
517
518 self.save_time = self.data.max_time
518 self.save_time = self.data.max_time
519
519
520 fig = self.figures[n]
520 fig = self.figures[n]
521
521
522 if self.throttle == 0:
522 if self.throttle == 0:
523 if self.oneFigure:
523 if self.oneFigure:
524 if stitle is not None:
524 if stitle is not None:
525 figname = os.path.join(
525 figname = os.path.join(
526 self.save,
526 self.save,
527 self.save_code + '_' + new_string,
527 self.save_code + '_' + new_string,
528 '{}_{}_{}.png'.format(
528 '{}_{}_{}.png'.format(
529 self.save_code,
529 self.save_code,
530 new_string,
530 new_string,
531 self.getDateTime(self.data.max_time).strftime(
531 self.getDateTime(self.data.max_time).strftime(
532 '%Y%m%d_%H%M%S',
532 '%Y%m%d_%H%M%S',
533 ),
533 ),
534 )
534 )
535 )
535 )
536 else:
536 else:
537 figname = os.path.join(
537 figname = os.path.join(
538 self.save,
538 self.save,
539 self.save_code,
539 self.save_code,
540 '{}_{}.png'.format(
540 '{}_{}.png'.format(
541 self.save_code,
541 self.save_code,
542 self.getDateTime(self.data.max_time).strftime(
542 self.getDateTime(self.data.max_time).strftime(
543 '%Y%m%d_%H%M%S'
543 '%Y%m%d_%H%M%S'
544 ),
544 ),
545 )
545 )
546 )
546 )
547 else:
547 else:
548 figname = os.path.join(
548 figname = os.path.join(
549 self.save,
549 self.save,
550 self.save_code,
550 self.save_code,
551 '{}_ch{}_{}.png'.format(
551 '{}_ch{}_{}.png'.format(
552 self.save_code,n,
552 self.save_code,n,
553 self.getDateTime(self.data.max_time).strftime(
553 self.getDateTime(self.data.max_time).strftime(
554 '%Y%m%d_%H%M%S'
554 '%Y%m%d_%H%M%S'
555 ),
555 ),
556 )
556 )
557 )
557 )
558 log.log('Saving figure: {}'.format(figname), self.name)
558 log.log('Saving figure: {}'.format(figname), self.name)
559 if not os.path.isdir(os.path.dirname(figname)):
559 if not os.path.isdir(os.path.dirname(figname)):
560 os.makedirs(os.path.dirname(figname))
560 os.makedirs(os.path.dirname(figname))
561 fig.savefig(figname)
561 fig.savefig(figname)
562
562
563 figname = os.path.join(
563 figname = os.path.join(
564 self.save,
564 self.save,
565 '{}_{}.png'.format(
565 '{}_{}.png'.format(
566 self.save_code,
566 self.save_code,
567 self.getDateTime(self.data.min_time).strftime(
567 self.getDateTime(self.data.min_time).strftime(
568 '%Y%m%d'
568 '%Y%m%d'
569 ),
569 ),
570 )
570 )
571 )
571 )
572
572
573 log.log('Saving figure: {}'.format(figname), self.name)
573 log.log('Saving figure: {}'.format(figname), self.name)
574 if not os.path.isdir(os.path.dirname(figname)):
574 if not os.path.isdir(os.path.dirname(figname)):
575 os.makedirs(os.path.dirname(figname))
575 os.makedirs(os.path.dirname(figname))
576 fig.savefig(figname)
576 fig.savefig(figname)
577
577
578 def send_to_server(self):
578 def send_to_server(self):
579 '''
579 '''
580 '''
580 '''
581
581
582 if self.exp_code == None:
582 if self.exp_code == None:
583 log.warning('Missing `exp_code` skipping sending to server...')
583 log.warning('Missing `exp_code` skipping sending to server...')
584
584
585 last_time = self.data.max_time
585 last_time = self.data.max_time
586 interval = last_time - self.sender_time
586 interval = last_time - self.sender_time
587 if interval < self.sender_period:
587 if interval < self.sender_period:
588 return
588 return
589
589
590 self.sender_time = last_time
590 self.sender_time = last_time
591
591
592 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
592 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
593 for attr in attrs:
593 for attr in attrs:
594 value = getattr(self, attr)
594 value = getattr(self, attr)
595 if value:
595 if value:
596 if isinstance(value, (numpy.float32, numpy.float64)):
596 if isinstance(value, (numpy.float32, numpy.float64)):
597 value = round(float(value), 2)
597 value = round(float(value), 2)
598 self.data.meta[attr] = value
598 self.data.meta[attr] = value
599 if self.colormap == 'jet' or self.colormap == 'sophy_w':
599 if self.colormap == 'jet' or self.colormap == 'sophy_w':
600 self.data.meta['colormap'] = 'Jet'
600 self.data.meta['colormap'] = 'Jet'
601 elif 'sophy_v' in self.colormap:
601 elif 'sophy_v' in self.colormap:
602 self.data.meta['colormap'] = 'RdBu'
602 self.data.meta['colormap'] = 'RdBu'
603 else:
603 else:
604 self.data.meta['colormap'] = 'Viridis'
604 self.data.meta['colormap'] = 'Viridis'
605 self.data.meta['interval'] = int(interval)
605 self.data.meta['interval'] = int(interval)
606
606
607 self.sender_queue.append(last_time)
607 self.sender_queue.append(last_time)
608
608
609 while True:
609 while True:
610 try:
610 try:
611 tm = self.sender_queue.popleft()
611 tm = self.sender_queue.popleft()
612 except IndexError:
612 except IndexError:
613 break
613 break
614 msg = self.data.jsonify(tm, self.save_code, self.plot_type, key='var')
614 msg = self.data.jsonify(tm, self.save_code, self.plot_type, key='var')
615 self.socket.send_string(msg)
615 self.socket.send_string(msg)
616 socks = dict(self.poll.poll(2000))
616 socks = dict(self.poll.poll(2000))
617 if socks.get(self.socket) == zmq.POLLIN:
617 if socks.get(self.socket) == zmq.POLLIN:
618 reply = self.socket.recv_string()
618 reply = self.socket.recv_string()
619 if reply == 'ok':
619 if reply == 'ok':
620 log.log("Response from server ok", self.name)
620 log.log("Response from server ok", self.name)
621 time.sleep(0.1)
621 time.sleep(0.1)
622 continue
622 continue
623 else:
623 else:
624 log.warning(
624 log.warning(
625 "Malformed reply from server: {}".format(reply), self.name)
625 "Malformed reply from server: {}".format(reply), self.name)
626 else:
626 else:
627 log.warning(
627 log.warning(
628 "No response from server, retrying...", self.name)
628 "No response from server, retrying...", self.name)
629 self.sender_queue.appendleft(tm)
629 self.sender_queue.appendleft(tm)
630 self.socket.setsockopt(zmq.LINGER, 0)
630 self.socket.setsockopt(zmq.LINGER, 0)
631 self.socket.close()
631 self.socket.close()
632 self.poll.unregister(self.socket)
632 self.poll.unregister(self.socket)
633 self.socket = self.context.socket(zmq.REQ)
633 self.socket = self.context.socket(zmq.REQ)
634 self.socket.connect(self.server)
634 self.socket.connect(self.server)
635 self.poll.register(self.socket, zmq.POLLIN)
635 self.poll.register(self.socket, zmq.POLLIN)
636 break
636 break
637
637
638 def setup(self):
638 def setup(self):
639 '''
639 '''
640 This method should be implemented in the child class, the following
640 This method should be implemented in the child class, the following
641 attributes should be set:
641 attributes should be set:
642
642
643 self.nrows: number of rows
643 self.nrows: number of rows
644 self.ncols: number of cols
644 self.ncols: number of cols
645 self.nplots: number of plots (channels or pairs)
645 self.nplots: number of plots (channels or pairs)
646 self.ylabel: label for Y axes
646 self.ylabel: label for Y axes
647 self.titles: list of axes title
647 self.titles: list of axes title
648
648
649 '''
649 '''
650 raise NotImplementedError
650 raise NotImplementedError
651
651
652 def plot(self):
652 def plot(self):
653 '''
653 '''
654 Must be defined in the child class, the actual plotting method
654 Must be defined in the child class, the actual plotting method
655 '''
655 '''
656 raise NotImplementedError
656 raise NotImplementedError
657
657
658 def update(self, dataOut):
658 def update(self, dataOut):
659 '''
659 '''
660 Must be defined in the child class, update self.data with new data
660 Must be defined in the child class, update self.data with new data
661 '''
661 '''
662
662
663 data = {
663 data = {
664 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
664 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
665 }
665 }
666 meta = {}
666 meta = {}
667
667
668 return data, meta
668 return data, meta
669
669
670 def run(self, dataOut, **kwargs):
670 def run(self, dataOut, **kwargs):
671 '''
671 '''
672 Main plotting routine
672 Main plotting routine
673 '''
673 '''
674
674
675 if self.isConfig is False:
675 if self.isConfig is False:
676 self.__setup(**kwargs)
676 self.__setup(**kwargs)
677
677
678 if self.localtime:
678 if self.localtime:
679 self.getDateTime = datetime.datetime.fromtimestamp
679 self.getDateTime = datetime.datetime.fromtimestamp
680 else:
680 else:
681 self.getDateTime = datetime.datetime.utcfromtimestamp
681 self.getDateTime = datetime.datetime.utcfromtimestamp
682
682
683 self.data.setup()
683 self.data.setup()
684 self.isConfig = True
684 self.isConfig = True
685 if self.server:
685 if self.server:
686 self.context = zmq.Context()
686 self.context = zmq.Context()
687 self.socket = self.context.socket(zmq.REQ)
687 self.socket = self.context.socket(zmq.REQ)
688 self.socket.connect(self.server)
688 self.socket.connect(self.server)
689 self.poll = zmq.Poller()
689 self.poll = zmq.Poller()
690 self.poll.register(self.socket, zmq.POLLIN)
690 self.poll.register(self.socket, zmq.POLLIN)
691
691
692 tm = getattr(dataOut, self.attr_time)
692 tm = getattr(dataOut, self.attr_time)
693
693
694 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
694 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
695 self.save_time = tm
695 self.save_time = tm
696 self.__plot()
696 self.__plot()
697 self.tmin += self.xrange*60*60
697 self.tmin += self.xrange*60*60
698 self.data.setup()
698 self.data.setup()
699 self.clear_figures()
699 self.clear_figures()
700
700
701 self.__update(dataOut, tm)
701 self.__update(dataOut, tm)
702
702
703 if self.isPlotConfig is False:
703 if self.isPlotConfig is False:
704 self.__setup_plot()
704 self.__setup_plot()
705 self.isPlotConfig = True
705 self.isPlotConfig = True
706 if self.xaxis == 'time':
706 if self.xaxis == 'time':
707 dt = self.getDateTime(tm)
707 dt = self.getDateTime(tm)
708 if self.xmin is None:
708 if self.xmin is None:
709 self.tmin = tm
709 self.tmin = tm
710 self.xmin = dt.hour
710 self.xmin = dt.hour
711 minutes = (self.xmin-int(self.xmin)) * 60
711 minutes = (self.xmin-int(self.xmin)) * 60
712 seconds = (minutes - int(minutes)) * 60
712 seconds = (minutes - int(minutes)) * 60
713 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
713 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
714 datetime.datetime(1970, 1, 1)).total_seconds()
714 datetime.datetime(1970, 1, 1)).total_seconds()
715 if self.localtime:
715 if self.localtime:
716 self.tmin += time.timezone
716 self.tmin += time.timezone
717
717
718 if self.xmin is not None and self.xmax is not None:
718 if self.xmin is not None and self.xmax is not None:
719 self.xrange = self.xmax - self.xmin
719 self.xrange = self.xmax - self.xmin
720
720
721 if self.throttle == 0:
721 if self.throttle == 0:
722 self.__plot()
722 self.__plot()
723 else:
723 else:
724 self.__throttle_plot(self.__plot)#, coerce=coerce)
724 self.__throttle_plot(self.__plot)#, coerce=coerce)
725
725
726 def close(self):
726 def close(self):
727
727
728 if self.data and not self.data.flagNoData:
728 if self.data and not self.data.flagNoData:
729 self.save_time = 0
729 self.save_time = 0
730 self.__plot()
730 self.__plot()
731 if self.data and not self.data.flagNoData and self.pause:
731 if self.data and not self.data.flagNoData and self.pause:
732 figpause(10)
732 figpause(10)
@@ -1,531 +1,537
1 import os
1 import os
2 import datetime
2 import datetime
3 import numpy
3 import numpy
4 from mpl_toolkits.axisartist.grid_finder import FixedLocator, DictFormatter
4 from mpl_toolkits.axisartist.grid_finder import FixedLocator, DictFormatter
5
5
6 from schainpy.model.graphics.jroplot_base import Plot, plt
6 from schainpy.model.graphics.jroplot_base import Plot, plt
7 from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot, SpectraCutPlot
7 from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot, SpectraCutPlot
8 from schainpy.utils import log
8 from schainpy.utils import log
9
9
10 import wradlib.georef as georef
10 import wradlib.georef as georef
11
11
12 EARTH_RADIUS = 6.3710e3
12 EARTH_RADIUS = 6.3710e3
13
13
14
14
15 def ll2xy(lat1, lon1, lat2, lon2):
15 def ll2xy(lat1, lon1, lat2, lon2):
16
16
17 p = 0.017453292519943295
17 p = 0.017453292519943295
18 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
18 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
19 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
19 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
20 r = 12742 * numpy.arcsin(numpy.sqrt(a))
20 r = 12742 * numpy.arcsin(numpy.sqrt(a))
21 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
21 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
22 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
22 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
23 theta = -theta + numpy.pi/2
23 theta = -theta + numpy.pi/2
24 return r*numpy.cos(theta), r*numpy.sin(theta)
24 return r*numpy.cos(theta), r*numpy.sin(theta)
25
25
26
26
27 def km2deg(km):
27 def km2deg(km):
28 '''
28 '''
29 Convert distance in km to degrees
29 Convert distance in km to degrees
30 '''
30 '''
31
31
32 return numpy.rad2deg(km/EARTH_RADIUS)
32 return numpy.rad2deg(km/EARTH_RADIUS)
33
33
34
34
35
35
36 class SpectralMomentsPlot(SpectraPlot):
36 class SpectralMomentsPlot(SpectraPlot):
37 '''
37 '''
38 Plot for Spectral Moments
38 Plot for Spectral Moments
39 '''
39 '''
40 CODE = 'spc_moments'
40 CODE = 'spc_moments'
41 # colormap = 'jet'
41 # colormap = 'jet'
42 # plot_type = 'pcolor'
42 # plot_type = 'pcolor'
43
43
44 class DobleGaussianPlot(SpectraPlot):
44 class DobleGaussianPlot(SpectraPlot):
45 '''
45 '''
46 Plot for Double Gaussian Plot
46 Plot for Double Gaussian Plot
47 '''
47 '''
48 CODE = 'gaussian_fit'
48 CODE = 'gaussian_fit'
49 # colormap = 'jet'
49 # colormap = 'jet'
50 # plot_type = 'pcolor'
50 # plot_type = 'pcolor'
51
51
52 class DoubleGaussianSpectraCutPlot(SpectraCutPlot):
52 class DoubleGaussianSpectraCutPlot(SpectraCutPlot):
53 '''
53 '''
54 Plot SpectraCut with Double Gaussian Fit
54 Plot SpectraCut with Double Gaussian Fit
55 '''
55 '''
56 CODE = 'cut_gaussian_fit'
56 CODE = 'cut_gaussian_fit'
57
57
58 class SnrPlot(RTIPlot):
58 class SnrPlot(RTIPlot):
59 '''
59 '''
60 Plot for SNR Data
60 Plot for SNR Data
61 '''
61 '''
62
62
63 CODE = 'snr'
63 CODE = 'snr'
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 'snr': 10*numpy.log10(dataOut.data_snr)
69 'snr': 10*numpy.log10(dataOut.data_snr)
70 }
70 }
71
71
72 return data, {}
72 return data, {}
73
73
74 class DopplerPlot(RTIPlot):
74 class DopplerPlot(RTIPlot):
75 '''
75 '''
76 Plot for DOPPLER Data (1st moment)
76 Plot for DOPPLER Data (1st moment)
77 '''
77 '''
78
78
79 CODE = 'dop'
79 CODE = 'dop'
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 'dop': 10*numpy.log10(dataOut.data_dop)
85 'dop': 10*numpy.log10(dataOut.data_dop)
86 }
86 }
87
87
88 return data, {}
88 return data, {}
89
89
90 class PowerPlot(RTIPlot):
90 class PowerPlot(RTIPlot):
91 '''
91 '''
92 Plot for Power Data (0 moment)
92 Plot for Power Data (0 moment)
93 '''
93 '''
94
94
95 CODE = 'pow'
95 CODE = 'pow'
96 colormap = 'jet'
96 colormap = 'jet'
97
97
98 def update(self, dataOut):
98 def update(self, dataOut):
99 data = {
99 data = {
100 'pow': 10*numpy.log10(dataOut.data_pow/dataOut.normFactor)
100 'pow': 10*numpy.log10(dataOut.data_pow/dataOut.normFactor)
101 }
101 }
102 return data, {}
102 return data, {}
103
103
104 class SpectralWidthPlot(RTIPlot):
104 class SpectralWidthPlot(RTIPlot):
105 '''
105 '''
106 Plot for Spectral Width Data (2nd moment)
106 Plot for Spectral Width Data (2nd moment)
107 '''
107 '''
108
108
109 CODE = 'width'
109 CODE = 'width'
110 colormap = 'jet'
110 colormap = 'jet'
111
111
112 def update(self, dataOut):
112 def update(self, dataOut):
113
113
114 data = {
114 data = {
115 'width': dataOut.data_width
115 'width': dataOut.data_width
116 }
116 }
117
117
118 return data, {}
118 return data, {}
119
119
120 class SkyMapPlot(Plot):
120 class SkyMapPlot(Plot):
121 '''
121 '''
122 Plot for meteors detection data
122 Plot for meteors detection data
123 '''
123 '''
124
124
125 CODE = 'param'
125 CODE = 'param'
126
126
127 def setup(self):
127 def setup(self):
128
128
129 self.ncols = 1
129 self.ncols = 1
130 self.nrows = 1
130 self.nrows = 1
131 self.width = 7.2
131 self.width = 7.2
132 self.height = 7.2
132 self.height = 7.2
133 self.nplots = 1
133 self.nplots = 1
134 self.xlabel = 'Zonal Zenith Angle (deg)'
134 self.xlabel = 'Zonal Zenith Angle (deg)'
135 self.ylabel = 'Meridional Zenith Angle (deg)'
135 self.ylabel = 'Meridional Zenith Angle (deg)'
136 self.polar = True
136 self.polar = True
137 self.ymin = -180
137 self.ymin = -180
138 self.ymax = 180
138 self.ymax = 180
139 self.colorbar = False
139 self.colorbar = False
140
140
141 def plot(self):
141 def plot(self):
142
142
143 arrayParameters = numpy.concatenate(self.data['param'])
143 arrayParameters = numpy.concatenate(self.data['param'])
144 error = arrayParameters[:, -1]
144 error = arrayParameters[:, -1]
145 indValid = numpy.where(error == 0)[0]
145 indValid = numpy.where(error == 0)[0]
146 finalMeteor = arrayParameters[indValid, :]
146 finalMeteor = arrayParameters[indValid, :]
147 finalAzimuth = finalMeteor[:, 3]
147 finalAzimuth = finalMeteor[:, 3]
148 finalZenith = finalMeteor[:, 4]
148 finalZenith = finalMeteor[:, 4]
149
149
150 x = finalAzimuth * numpy.pi / 180
150 x = finalAzimuth * numpy.pi / 180
151 y = finalZenith
151 y = finalZenith
152
152
153 ax = self.axes[0]
153 ax = self.axes[0]
154
154
155 if ax.firsttime:
155 if ax.firsttime:
156 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
156 ax.plot = ax.plot(x, y, 'bo', markersize=5)[0]
157 else:
157 else:
158 ax.plot.set_data(x, y)
158 ax.plot.set_data(x, y)
159
159
160 dt1 = self.getDateTime(self.data.min_time).strftime('%y/%m/%d %H:%M:%S')
160 dt1 = self.getDateTime(self.data.min_time).strftime('%y/%m/%d %H:%M:%S')
161 dt2 = self.getDateTime(self.data.max_time).strftime('%y/%m/%d %H:%M:%S')
161 dt2 = self.getDateTime(self.data.max_time).strftime('%y/%m/%d %H:%M:%S')
162 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
162 title = 'Meteor Detection Sky Map\n %s - %s \n Number of events: %5.0f\n' % (dt1,
163 dt2,
163 dt2,
164 len(x))
164 len(x))
165 self.titles[0] = title
165 self.titles[0] = title
166
166
167
167
168 class GenericRTIPlot(Plot):
168 class GenericRTIPlot(Plot):
169 '''
169 '''
170 Plot for data_xxxx object
170 Plot for data_xxxx object
171 '''
171 '''
172
172
173 CODE = 'param'
173 CODE = 'param'
174 colormap = 'viridis'
174 colormap = 'viridis'
175 plot_type = 'pcolorbuffer'
175 plot_type = 'pcolorbuffer'
176
176
177 def setup(self):
177 def setup(self):
178 self.xaxis = 'time'
178 self.xaxis = 'time'
179 self.ncols = 1
179 self.ncols = 1
180 self.nrows = self.data.shape('param')[0]
180 self.nrows = self.data.shape('param')[0]
181 self.nplots = self.nrows
181 self.nplots = self.nrows
182 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95, 'top': 0.95})
182 self.plots_adjust.update({'hspace':0.8, 'left': 0.1, 'bottom': 0.08, 'right':0.95, 'top': 0.95})
183
183
184 if not self.xlabel:
184 if not self.xlabel:
185 self.xlabel = 'Time'
185 self.xlabel = 'Time'
186
186
187 self.ylabel = 'Range [km]'
187 self.ylabel = 'Range [km]'
188 if not self.titles:
188 if not self.titles:
189 self.titles = ['Param {}'.format(x) for x in range(self.nrows)]
189 self.titles = ['Param {}'.format(x) for x in range(self.nrows)]
190
190
191 def update(self, dataOut):
191 def update(self, dataOut):
192
192
193 data = {
193 data = {
194 'param' : numpy.concatenate([getattr(dataOut, attr) for attr in self.attr_data], axis=0)
194 'param' : numpy.concatenate([getattr(dataOut, attr) for attr in self.attr_data], axis=0)
195 }
195 }
196
196
197 meta = {}
197 meta = {}
198
198
199 return data, meta
199 return data, meta
200
200
201 def plot(self):
201 def plot(self):
202 # self.data.normalize_heights()
202 # self.data.normalize_heights()
203 self.x = self.data.times
203 self.x = self.data.times
204 self.y = self.data.yrange
204 self.y = self.data.yrange
205 self.z = self.data['param']
205 self.z = self.data['param']
206 self.z = 10*numpy.log10(self.z)
206 self.z = 10*numpy.log10(self.z)
207 self.z = numpy.ma.masked_invalid(self.z)
207 self.z = numpy.ma.masked_invalid(self.z)
208
208
209 if self.decimation is None:
209 if self.decimation is None:
210 x, y, z = self.fill_gaps(self.x, self.y, self.z)
210 x, y, z = self.fill_gaps(self.x, self.y, self.z)
211 else:
211 else:
212 x, y, z = self.fill_gaps(*self.decimate())
212 x, y, z = self.fill_gaps(*self.decimate())
213
213
214 for n, ax in enumerate(self.axes):
214 for n, ax in enumerate(self.axes):
215
215
216 self.zmax = self.zmax if self.zmax is not None else numpy.max(
216 self.zmax = self.zmax if self.zmax is not None else numpy.max(
217 self.z[n])
217 self.z[n])
218 self.zmin = self.zmin if self.zmin is not None else numpy.min(
218 self.zmin = self.zmin if self.zmin is not None else numpy.min(
219 self.z[n])
219 self.z[n])
220
220
221 if ax.firsttime:
221 if ax.firsttime:
222 if self.zlimits is not None:
222 if self.zlimits is not None:
223 self.zmin, self.zmax = self.zlimits[n]
223 self.zmin, self.zmax = self.zlimits[n]
224
224
225 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
225 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
226 vmin=self.zmin,
226 vmin=self.zmin,
227 vmax=self.zmax,
227 vmax=self.zmax,
228 cmap=self.cmaps[n]
228 cmap=self.cmaps[n]
229 )
229 )
230 else:
230 else:
231 if self.zlimits is not None:
231 if self.zlimits is not None:
232 self.zmin, self.zmax = self.zlimits[n]
232 self.zmin, self.zmax = self.zlimits[n]
233 ax.collections.remove(ax.collections[0])
233 ax.collections.remove(ax.collections[0])
234 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
234 ax.plt = ax.pcolormesh(x, y, z[n].T * self.factors[n],
235 vmin=self.zmin,
235 vmin=self.zmin,
236 vmax=self.zmax,
236 vmax=self.zmax,
237 cmap=self.cmaps[n]
237 cmap=self.cmaps[n]
238 )
238 )
239
239
240
240
241 class PolarMapPlot(Plot):
241 class PolarMapPlot(Plot):
242 '''
242 '''
243 Plot for weather radar
243 Plot for weather radar
244 '''
244 '''
245
245
246 CODE = 'param'
246 CODE = 'param'
247 colormap = 'seismic'
247 colormap = 'seismic'
248
248
249 def setup(self):
249 def setup(self):
250 self.ncols = 1
250 self.ncols = 1
251 self.nrows = 1
251 self.nrows = 1
252 self.width = 9
252 self.width = 9
253 self.height = 8
253 self.height = 8
254 self.mode = self.data.meta['mode']
254 self.mode = self.data.meta['mode']
255 if self.channels is not None:
255 if self.channels is not None:
256 self.nplots = len(self.channels)
256 self.nplots = len(self.channels)
257 self.nrows = len(self.channels)
257 self.nrows = len(self.channels)
258 else:
258 else:
259 self.nplots = self.data.shape(self.CODE)[0]
259 self.nplots = self.data.shape(self.CODE)[0]
260 self.nrows = self.nplots
260 self.nrows = self.nplots
261 self.channels = list(range(self.nplots))
261 self.channels = list(range(self.nplots))
262 if self.mode == 'E':
262 if self.mode == 'E':
263 self.xlabel = 'Longitude'
263 self.xlabel = 'Longitude'
264 self.ylabel = 'Latitude'
264 self.ylabel = 'Latitude'
265 else:
265 else:
266 self.xlabel = 'Range (km)'
266 self.xlabel = 'Range (km)'
267 self.ylabel = 'Height (km)'
267 self.ylabel = 'Height (km)'
268 self.bgcolor = 'white'
268 self.bgcolor = 'white'
269 self.cb_labels = self.data.meta['units']
269 self.cb_labels = self.data.meta['units']
270 self.lat = self.data.meta['latitude']
270 self.lat = self.data.meta['latitude']
271 self.lon = self.data.meta['longitude']
271 self.lon = self.data.meta['longitude']
272 self.xmin, self.xmax = float(
272 self.xmin, self.xmax = float(
273 km2deg(self.xmin) + self.lon), float(km2deg(self.xmax) + self.lon)
273 km2deg(self.xmin) + self.lon), float(km2deg(self.xmax) + self.lon)
274 self.ymin, self.ymax = float(
274 self.ymin, self.ymax = float(
275 km2deg(self.ymin) + self.lat), float(km2deg(self.ymax) + self.lat)
275 km2deg(self.ymin) + self.lat), float(km2deg(self.ymax) + self.lat)
276 # self.polar = True
276 # self.polar = True
277
277
278 def plot(self):
278 def plot(self):
279
279
280 for n, ax in enumerate(self.axes):
280 for n, ax in enumerate(self.axes):
281 data = self.data['param'][self.channels[n]]
281 data = self.data['param'][self.channels[n]]
282
282
283 zeniths = numpy.linspace(
283 zeniths = numpy.linspace(
284 0, self.data.meta['max_range'], data.shape[1])
284 0, self.data.meta['max_range'], data.shape[1])
285 if self.mode == 'E':
285 if self.mode == 'E':
286 azimuths = -numpy.radians(self.data.yrange)+numpy.pi/2
286 azimuths = -numpy.radians(self.data.yrange)+numpy.pi/2
287 r, theta = numpy.meshgrid(zeniths, azimuths)
287 r, theta = numpy.meshgrid(zeniths, azimuths)
288 x, y = r*numpy.cos(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])), r*numpy.sin(
288 x, y = r*numpy.cos(theta)*numpy.cos(numpy.radians(self.data.meta['elevation'])), r*numpy.sin(
289 theta)*numpy.cos(numpy.radians(self.data.meta['elevation']))
289 theta)*numpy.cos(numpy.radians(self.data.meta['elevation']))
290 x = km2deg(x) + self.lon
290 x = km2deg(x) + self.lon
291 y = km2deg(y) + self.lat
291 y = km2deg(y) + self.lat
292 else:
292 else:
293 azimuths = numpy.radians(self.data.yrange)
293 azimuths = numpy.radians(self.data.yrange)
294 r, theta = numpy.meshgrid(zeniths, azimuths)
294 r, theta = numpy.meshgrid(zeniths, azimuths)
295 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
295 x, y = r*numpy.cos(theta), r*numpy.sin(theta)
296 self.y = zeniths
296 self.y = zeniths
297
297
298 if ax.firsttime:
298 if ax.firsttime:
299 if self.zlimits is not None:
299 if self.zlimits is not None:
300 self.zmin, self.zmax = self.zlimits[n]
300 self.zmin, self.zmax = self.zlimits[n]
301 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
301 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
302 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
302 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
303 vmin=self.zmin,
303 vmin=self.zmin,
304 vmax=self.zmax,
304 vmax=self.zmax,
305 cmap=self.cmaps[n])
305 cmap=self.cmaps[n])
306 else:
306 else:
307 if self.zlimits is not None:
307 if self.zlimits is not None:
308 self.zmin, self.zmax = self.zlimits[n]
308 self.zmin, self.zmax = self.zlimits[n]
309 ax.collections.remove(ax.collections[0])
309 ax.collections.remove(ax.collections[0])
310 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
310 ax.plt = ax.pcolormesh( # r, theta, numpy.ma.array(data, mask=numpy.isnan(data)),
311 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
311 x, y, numpy.ma.array(data, mask=numpy.isnan(data)),
312 vmin=self.zmin,
312 vmin=self.zmin,
313 vmax=self.zmax,
313 vmax=self.zmax,
314 cmap=self.cmaps[n])
314 cmap=self.cmaps[n])
315
315
316 if self.mode == 'A':
316 if self.mode == 'A':
317 continue
317 continue
318
318
319 # plot district names
319 # plot district names
320 f = open('/data/workspace/schain_scripts/distrito.csv')
320 f = open('/data/workspace/schain_scripts/distrito.csv')
321 for line in f:
321 for line in f:
322 label, lon, lat = [s.strip() for s in line.split(',') if s]
322 label, lon, lat = [s.strip() for s in line.split(',') if s]
323 lat = float(lat)
323 lat = float(lat)
324 lon = float(lon)
324 lon = float(lon)
325 # ax.plot(lon, lat, '.b', ms=2)
325 # ax.plot(lon, lat, '.b', ms=2)
326 ax.text(lon, lat, label.decode('utf8'), ha='center',
326 ax.text(lon, lat, label.decode('utf8'), ha='center',
327 va='bottom', size='8', color='black')
327 va='bottom', size='8', color='black')
328
328
329 # plot limites
329 # plot limites
330 limites = []
330 limites = []
331 tmp = []
331 tmp = []
332 for line in open('/data/workspace/schain_scripts/lima.csv'):
332 for line in open('/data/workspace/schain_scripts/lima.csv'):
333 if '#' in line:
333 if '#' in line:
334 if tmp:
334 if tmp:
335 limites.append(tmp)
335 limites.append(tmp)
336 tmp = []
336 tmp = []
337 continue
337 continue
338 values = line.strip().split(',')
338 values = line.strip().split(',')
339 tmp.append((float(values[0]), float(values[1])))
339 tmp.append((float(values[0]), float(values[1])))
340 for points in limites:
340 for points in limites:
341 ax.add_patch(
341 ax.add_patch(
342 Polygon(points, ec='k', fc='none', ls='--', lw=0.5))
342 Polygon(points, ec='k', fc='none', ls='--', lw=0.5))
343
343
344 # plot Cuencas
344 # plot Cuencas
345 for cuenca in ('rimac', 'lurin', 'mala', 'chillon', 'chilca', 'chancay-huaral'):
345 for cuenca in ('rimac', 'lurin', 'mala', 'chillon', 'chilca', 'chancay-huaral'):
346 f = open('/data/workspace/schain_scripts/{}.csv'.format(cuenca))
346 f = open('/data/workspace/schain_scripts/{}.csv'.format(cuenca))
347 values = [line.strip().split(',') for line in f]
347 values = [line.strip().split(',') for line in f]
348 points = [(float(s[0]), float(s[1])) for s in values]
348 points = [(float(s[0]), float(s[1])) for s in values]
349 ax.add_patch(Polygon(points, ec='b', fc='none'))
349 ax.add_patch(Polygon(points, ec='b', fc='none'))
350
350
351 # plot grid
351 # plot grid
352 for r in (15, 30, 45, 60):
352 for r in (15, 30, 45, 60):
353 ax.add_artist(plt.Circle((self.lon, self.lat),
353 ax.add_artist(plt.Circle((self.lon, self.lat),
354 km2deg(r), color='0.6', fill=False, lw=0.2))
354 km2deg(r), color='0.6', fill=False, lw=0.2))
355 ax.text(
355 ax.text(
356 self.lon + (km2deg(r))*numpy.cos(60*numpy.pi/180),
356 self.lon + (km2deg(r))*numpy.cos(60*numpy.pi/180),
357 self.lat + (km2deg(r))*numpy.sin(60*numpy.pi/180),
357 self.lat + (km2deg(r))*numpy.sin(60*numpy.pi/180),
358 '{}km'.format(r),
358 '{}km'.format(r),
359 ha='center', va='bottom', size='8', color='0.6', weight='heavy')
359 ha='center', va='bottom', size='8', color='0.6', weight='heavy')
360
360
361 if self.mode == 'E':
361 if self.mode == 'E':
362 title = 'El={}$^\circ$'.format(self.data.meta['elevation'])
362 title = 'El={}$^\circ$'.format(self.data.meta['elevation'])
363 label = 'E{:02d}'.format(int(self.data.meta['elevation']))
363 label = 'E{:02d}'.format(int(self.data.meta['elevation']))
364 else:
364 else:
365 title = 'Az={}$^\circ$'.format(self.data.meta['azimuth'])
365 title = 'Az={}$^\circ$'.format(self.data.meta['azimuth'])
366 label = 'A{:02d}'.format(int(self.data.meta['azimuth']))
366 label = 'A{:02d}'.format(int(self.data.meta['azimuth']))
367
367
368 self.save_labels = ['{}-{}'.format(lbl, label) for lbl in self.labels]
368 self.save_labels = ['{}-{}'.format(lbl, label) for lbl in self.labels]
369 self.titles = ['{} {}'.format(
369 self.titles = ['{} {}'.format(
370 self.data.parameters[x], title) for x in self.channels]
370 self.data.parameters[x], title) for x in self.channels]
371
371
372 class WeatherParamsPlot(Plot):
372 class WeatherParamsPlot(Plot):
373 #CODE = 'RHI'
373 #CODE = 'RHI'
374 #plot_name = 'RHI'
374 #plot_name = 'RHI'
375 plot_type = 'scattermap'
375 plot_type = 'scattermap'
376 buffering = False
376 buffering = False
377
377
378 def setup(self):
378 def setup(self):
379
379
380 self.ncols = 1
380 self.ncols = 1
381 self.nrows = 1
381 self.nrows = 1
382 self.nplots= 1
382 self.nplots= 1
383 self.ylabel= 'Range [km]'
383 self.ylabel= 'Range [km]'
384 self.xlabel= 'Range [km]'
384 self.xlabel= 'Range [km]'
385 self.polar = True
385 self.polar = True
386 self.grid = True
386 self.grid = True
387 if self.channels is not None:
387 if self.channels is not None:
388 self.nplots = len(self.channels)
388 self.nplots = len(self.channels)
389 self.nrows = len(self.channels)
389 self.nrows = len(self.channels)
390 else:
390 else:
391 self.nplots = self.data.shape(self.CODE)[0]
391 self.nplots = self.data.shape(self.CODE)[0]
392 self.nrows = self.nplots
392 self.nrows = self.nplots
393 self.channels = list(range(self.nplots))
393 self.channels = list(range(self.nplots))
394
394
395 self.colorbar=True
395 self.colorbar=True
396 self.width =8
396 self.width =8
397 self.height =8
397 self.height =8
398 self.ini =0
398 self.ini =0
399 self.len_azi =0
399 self.len_azi =0
400 self.buffer_ini = None
400 self.buffer_ini = None
401 self.buffer_ele = None
401 self.buffer_ele = None
402 self.plots_adjust.update({'wspace': 0.4, 'hspace':0.4, 'left': 0.1, 'right': 0.9, 'bottom': 0.08})
402 self.plots_adjust.update({'wspace': 0.4, 'hspace':0.4, 'left': 0.1, 'right': 0.9, 'bottom': 0.08})
403 self.flag =0
403 self.flag =0
404 self.indicador= 0
404 self.indicador= 0
405 self.last_data_ele = None
405 self.last_data_ele = None
406 self.val_mean = None
406 self.val_mean = None
407
407
408 def update(self, dataOut):
408 def update(self, dataOut):
409
409
410 vars = {
410 vars = {
411 'S' : 0,
411 'S' : 0,
412 'V' : 1,
412 'V' : 1,
413 'W' : 2,
413 'W' : 2,
414 'SNR' : 3,
414 'SNR' : 3,
415 'Z' : 4,
415 'Z' : 4,
416 'D' : 5,
416 'D' : 5,
417 'P' : 6,
417 'P' : 6,
418 'R' : 7,
418 'R' : 7,
419 }
419 }
420
420
421 data = {}
421 data = {}
422 meta = {}
422 meta = {}
423
423
424 if hasattr(dataOut, 'nFFTPoints'):
424 if hasattr(dataOut, 'nFFTPoints'):
425 factor = dataOut.normFactor
425 factor = dataOut.normFactor
426 else:
426 else:
427 factor = 1
427 factor = 1
428
428
429 mask = dataOut.data_param[:,3,:] < self.snr_threshold
429 if 'S' in self.attr_data[0]:
430
430 tmp = 10*numpy.log10(10.0*getattr(dataOut, 'data_param')[:,0,:]/(factor))
431 if 'S' in self.attr_data[0]:
432 # data['data'] = 10*numpy.log10(getattr(dataOut, self.attr_data[0])/(factor))
433 tmp = numpy.ma.masked_array(10*numpy.log10(10.0*getattr(dataOut, 'data_param')[:,0,:]/(factor)), mask=mask)
434 else:
431 else:
435 tmp = numpy.ma.masked_array(getattr(dataOut, 'data_param')[:,vars[self.attr_data[0]],:], mask=mask)
432 tmp = getattr(dataOut, 'data_param')[:,vars[self.attr_data[0]],:]
436 # tmp = getattr(dataOut, self.attr_data[0])
433
434
435 if self.mask:
436 mask = dataOut.data_param[:,3,:] < self.mask
437 tmp = numpy.ma.masked_array(tmp, mask=mask)
437
438
438 r = dataOut.heightList
439 r = dataOut.heightList
439 delta_height = r[1]-r[0]
440 delta_height = r[1]-r[0]
440 valid = numpy.where(r>=0)[0]
441 valid = numpy.where(r>=0)[0]
441 data['r'] = numpy.arange(len(valid))*delta_height
442 data['r'] = numpy.arange(len(valid))*delta_height
442
443
443 try:
444 try:
444 data['data'] = tmp[self.channels[0]][:,valid]
445 data['data'] = tmp[self.channels[0]][:,valid]
445 except:
446 except:
446 data['data'] = tmp[0][:,valid]
447 data['data'] = tmp[0][:,valid]
447
448
448 if dataOut.mode_op == 'PPI':
449 if dataOut.mode_op == 'PPI':
449 self.CODE = 'PPI'
450 self.CODE = 'PPI'
450 self.title = self.CODE
451 self.title = self.CODE
451 elif dataOut.mode_op == 'RHI':
452 elif dataOut.mode_op == 'RHI':
452 self.CODE = 'RHI'
453 self.CODE = 'RHI'
453 self.title = self.CODE
454 self.title = self.CODE
454
455
455 data['azi'] = dataOut.data_azi
456 data['azi'] = dataOut.data_azi
456 data['ele'] = dataOut.data_ele
457 data['ele'] = dataOut.data_ele
457 data['mode_op'] = dataOut.mode_op
458 data['mode_op'] = dataOut.mode_op
458 var = data['data'].flatten()
459 var = data['data'].flatten()
459 r = numpy.tile(data['r'], data['data'].shape[0]).reshape(data['data'].shape)*1000
460 r = numpy.tile(data['r'], data['data'].shape[0]).reshape(data['data'].shape)*1000
460 lla = georef.spherical_to_proj(r, data['azi'], data['ele'], (-75.295893, -12.040436, 3379.2147))
461 lla = georef.spherical_to_proj(r, data['azi'], data['ele'], (-75.295893, -12.040436, 3379.2147))
461 meta['lat'] = lla[:,:,1].flatten()[var.mask==False]
462 if self.mask:
462 meta['lon'] = lla[:,:,0].flatten()[var.mask==False]
463 meta['lat'] = lla[:,:,1].flatten()[var.mask==False]
463 data['var'] = numpy.array([var[var.mask==False]])
464 meta['lon'] = lla[:,:,0].flatten()[var.mask==False]
465 data['var'] = numpy.array([var[var.mask==False]])
466 else:
467 meta['lat'] = lla[:,:,1].flatten()
468 meta['lon'] = lla[:,:,0].flatten()
469 data['var'] = numpy.array([var])
464
470
465 return data, meta
471 return data, meta
466
472
467 def plot(self):
473 def plot(self):
468 data = self.data[-1]
474 data = self.data[-1]
469 z = data['data']
475 z = data['data']
470 r = data['r']
476 r = data['r']
471 self.titles = []
477 self.titles = []
472
478
473 self.ymax = self.ymax if self.ymax else numpy.nanmax(r)
479 self.ymax = self.ymax if self.ymax else numpy.nanmax(r)
474 self.ymin = self.ymin if self.ymin else numpy.nanmin(r)
480 self.ymin = self.ymin if self.ymin else numpy.nanmin(r)
475 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
481 self.zmax = self.zmax if self.zmax else numpy.nanmax(z)
476 self.zmin = self.zmin if self.zmin is not None else numpy.nanmin(z)
482 self.zmin = self.zmin if self.zmin is not None else numpy.nanmin(z)
477
483
478 if data['mode_op'] == 'RHI':
484 if data['mode_op'] == 'RHI':
479 try:
485 try:
480 if self.data['mode_op'][-2] == 'PPI':
486 if self.data['mode_op'][-2] == 'PPI':
481 self.ang_min = None
487 self.ang_min = None
482 self.ang_max = None
488 self.ang_max = None
483 except:
489 except:
484 pass
490 pass
485 self.ang_min = self.ang_min if self.ang_min else 0
491 self.ang_min = self.ang_min if self.ang_min else 0
486 self.ang_max = self.ang_max if self.ang_max else 90
492 self.ang_max = self.ang_max if self.ang_max else 90
487 r, theta = numpy.meshgrid(r, numpy.radians(data['ele']) )
493 r, theta = numpy.meshgrid(r, numpy.radians(data['ele']) )
488 elif data['mode_op'] == 'PPI':
494 elif data['mode_op'] == 'PPI':
489 try:
495 try:
490 if self.data['mode_op'][-2] == 'RHI':
496 if self.data['mode_op'][-2] == 'RHI':
491 self.ang_min = None
497 self.ang_min = None
492 self.ang_max = None
498 self.ang_max = None
493 except:
499 except:
494 pass
500 pass
495 self.ang_min = self.ang_min if self.ang_min else 0
501 self.ang_min = self.ang_min if self.ang_min else 0
496 self.ang_max = self.ang_max if self.ang_max else 360
502 self.ang_max = self.ang_max if self.ang_max else 360
497 r, theta = numpy.meshgrid(r, numpy.radians(data['azi']) )
503 r, theta = numpy.meshgrid(r, numpy.radians(data['azi']) )
498
504
499 self.clear_figures()
505 self.clear_figures()
500
506
501 for i,ax in enumerate(self.axes):
507 for i,ax in enumerate(self.axes):
502
508
503 if ax.firsttime:
509 if ax.firsttime:
504 ax.set_xlim(numpy.radians(self.ang_min),numpy.radians(self.ang_max))
510 ax.set_xlim(numpy.radians(self.ang_min),numpy.radians(self.ang_max))
505 ax.plt = ax.pcolormesh(theta, r, z, cmap=self.colormap, vmin=self.zmin, vmax=self.zmax)
511 ax.plt = ax.pcolormesh(theta, r, z, cmap=self.colormap, vmin=self.zmin, vmax=self.zmax)
506 if data['mode_op'] == 'PPI':
512 if data['mode_op'] == 'PPI':
507 ax.set_theta_direction(-1)
513 ax.set_theta_direction(-1)
508 ax.set_theta_offset(numpy.pi/2)
514 ax.set_theta_offset(numpy.pi/2)
509
515
510 else:
516 else:
511 ax.set_xlim(numpy.radians(self.ang_min),numpy.radians(self.ang_max))
517 ax.set_xlim(numpy.radians(self.ang_min),numpy.radians(self.ang_max))
512 ax.plt = ax.pcolormesh(theta, r, z, cmap=self.colormap, vmin=self.zmin, vmax=self.zmax)
518 ax.plt = ax.pcolormesh(theta, r, z, cmap=self.colormap, vmin=self.zmin, vmax=self.zmax)
513 if data['mode_op'] == 'PPI':
519 if data['mode_op'] == 'PPI':
514 ax.set_theta_direction(-1)
520 ax.set_theta_direction(-1)
515 ax.set_theta_offset(numpy.pi/2)
521 ax.set_theta_offset(numpy.pi/2)
516
522
517 ax.grid(True)
523 ax.grid(True)
518 if data['mode_op'] == 'RHI':
524 if data['mode_op'] == 'RHI':
519 len_aux = int(data['azi'].shape[0]/4)
525 len_aux = int(data['azi'].shape[0]/4)
520 mean = numpy.mean(data['azi'][len_aux:-len_aux])
526 mean = numpy.mean(data['azi'][len_aux:-len_aux])
521 if len(self.channels) !=1:
527 if len(self.channels) !=1:
522 self.titles = ['RHI {} at AZ: {} CH {}'.format(self.labels[x], str(round(mean,1)), x) for x in range(self.nrows)]
528 self.titles = ['RHI {} at AZ: {} CH {}'.format(self.labels[x], str(round(mean,1)), x) for x in range(self.nrows)]
523 else:
529 else:
524 self.titles = ['RHI {} at AZ: {} CH {}'.format(self.labels[0], str(round(mean,1)), self.channels[0])]
530 self.titles = ['RHI {} at AZ: {} CH {}'.format(self.labels[0], str(round(mean,1)), self.channels[0])]
525 elif data['mode_op'] == 'PPI':
531 elif data['mode_op'] == 'PPI':
526 len_aux = int(data['ele'].shape[0]/4)
532 len_aux = int(data['ele'].shape[0]/4)
527 mean = numpy.mean(data['ele'][len_aux:-len_aux])
533 mean = numpy.mean(data['ele'][len_aux:-len_aux])
528 if len(self.channels) !=1:
534 if len(self.channels) !=1:
529 self.titles = ['PPI {} at EL: {} CH {}'.format(self.self.labels[x], str(round(mean,1)), x) for x in range(self.nrows)]
535 self.titles = ['PPI {} at EL: {} CH {}'.format(self.self.labels[x], str(round(mean,1)), x) for x in range(self.nrows)]
530 else:
536 else:
531 self.titles = ['PPI {} at EL: {} CH {}'.format(self.labels[0], str(round(mean,1)), self.channels[0])]
537 self.titles = ['PPI {} at EL: {} CH {}'.format(self.labels[0], str(round(mean,1)), self.channels[0])]
General Comments 0
You need to be logged in to leave comments. Login now