##// END OF EJS Templates
upgrade filterbyHeights, fix initial parameters. removeProfileSats2 improved debug
joabAM -
r1655:13a9a26f11d7
parent child
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,705 +1,707
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 if self.t_units == "h_m":
194 if self.t_units == "h_m":
195 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
195 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
196 if self.t_units == "h":
196 if self.t_units == "h":
197 return '{}'.format(self.getDateTime(x).strftime('%H'))
197 return '{}'.format(self.getDateTime(x).strftime('%H'))
198
198
199 def __setup(self, **kwargs):
199 def __setup(self, **kwargs):
200 '''
200 '''
201 Initialize variables
201 Initialize variables
202 '''
202 '''
203
203
204 self.figures = []
204 self.figures = []
205 self.axes = []
205 self.axes = []
206 self.cb_axes = []
206 self.cb_axes = []
207 self.pf_axes = []
207 self.pf_axes = []
208 self.localtime = kwargs.pop('localtime', True)
208 self.localtime = kwargs.pop('localtime', True)
209 self.show = kwargs.get('show', True)
209 self.show = kwargs.get('show', True)
210 self.save = kwargs.get('save', False)
210 self.save = kwargs.get('save', False)
211 self.save_period = kwargs.get('save_period', 0)
211 self.save_period = kwargs.get('save_period', 0)
212 self.colormap = kwargs.get('colormap', self.colormap)
212 self.colormap = kwargs.get('colormap', self.colormap)
213 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
213 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
214 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
214 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
215 self.colormaps = kwargs.get('colormaps', None)
215 self.colormaps = kwargs.get('colormaps', None)
216 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
216 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
217 self.showprofile = kwargs.get('showprofile', False)
217 self.showprofile = kwargs.get('showprofile', False)
218 self.title = kwargs.get('wintitle', self.CODE.upper())
218 self.title = kwargs.get('wintitle', self.CODE.upper())
219 self.cb_label = kwargs.get('cb_label', None)
219 self.cb_label = kwargs.get('cb_label', None)
220 self.cb_labels = kwargs.get('cb_labels', None)
220 self.cb_labels = kwargs.get('cb_labels', None)
221 self.labels = kwargs.get('labels', None)
221 self.labels = kwargs.get('labels', None)
222 self.xaxis = kwargs.get('xaxis', 'frequency')
222 self.xaxis = kwargs.get('xaxis', 'frequency')
223 self.zmin = kwargs.get('zmin', None)
223 self.zmin = kwargs.get('zmin', None)
224 self.zmax = kwargs.get('zmax', None)
224 self.zmax = kwargs.get('zmax', None)
225 self.zlimits = kwargs.get('zlimits', None)
225 self.zlimits = kwargs.get('zlimits', None)
226 self.xmin = kwargs.get('xmin', None)
226 self.xmin = kwargs.get('xmin', None)
227 self.xmax = kwargs.get('xmax', None)
227 self.xmax = kwargs.get('xmax', None)
228 self.xrange = kwargs.get('xrange', 12)
228 self.xrange = kwargs.get('xrange', 12)
229 self.xscale = kwargs.get('xscale', None)
229 self.xscale = kwargs.get('xscale', None)
230 self.ymin = kwargs.get('ymin', None)
230 self.ymin = kwargs.get('ymin', None)
231 self.ymax = kwargs.get('ymax', None)
231 self.ymax = kwargs.get('ymax', None)
232 self.yscale = kwargs.get('yscale', None)
232 self.yscale = kwargs.get('yscale', None)
233 self.xlabel = kwargs.get('xlabel', None)
233 self.xlabel = kwargs.get('xlabel', None)
234 self.attr_time = kwargs.get('attr_time', 'utctime')
234 self.attr_time = kwargs.get('attr_time', 'utctime')
235 self.attr_data = kwargs.get('attr_data', 'data_param')
235 self.attr_data = kwargs.get('attr_data', 'data_param')
236 self.decimation = kwargs.get('decimation', None)
236 self.decimation = kwargs.get('decimation', None)
237 self.oneFigure = kwargs.get('oneFigure', True)
237 self.oneFigure = kwargs.get('oneFigure', True)
238 self.width = kwargs.get('width', None)
238 self.width = kwargs.get('width', None)
239 self.height = kwargs.get('height', None)
239 self.height = kwargs.get('height', None)
240 self.colorbar = kwargs.get('colorbar', True)
240 self.colorbar = kwargs.get('colorbar', True)
241 self.factors = kwargs.get('factors', range(18))
241 self.factors = kwargs.get('factors', range(18))
242 self.channels = kwargs.get('channels', None)
242 self.channels = kwargs.get('channels', None)
243 self.titles = kwargs.get('titles', [])
243 self.titles = kwargs.get('titles', [])
244 self.polar = False
244 self.polar = False
245 self.type = kwargs.get('type', 'iq')
245 self.type = kwargs.get('type', 'iq')
246 self.grid = kwargs.get('grid', False)
246 self.grid = kwargs.get('grid', False)
247 self.pause = kwargs.get('pause', False)
247 self.pause = kwargs.get('pause', False)
248 self.save_code = kwargs.get('save_code', self.CODE)
248 self.save_code = kwargs.get('save_code', self.CODE)
249 self.throttle = kwargs.get('throttle', 0)
249 self.throttle = kwargs.get('throttle', 0)
250 self.exp_code = kwargs.get('exp_code', None)
250 self.exp_code = kwargs.get('exp_code', None)
251 self.server = kwargs.get('server', False)
251 self.server = kwargs.get('server', False)
252 self.sender_period = kwargs.get('sender_period', 60)
252 self.sender_period = kwargs.get('sender_period', 60)
253 self.tag = kwargs.get('tag', '')
253 self.tag = kwargs.get('tag', '')
254 self.height_index = kwargs.get('height_index', [])
254 self.height_index = kwargs.get('height_index', [])
255 self.__throttle_plot = apply_throttle(self.throttle)
255 self.__throttle_plot = apply_throttle(self.throttle)
256 code = self.attr_data if self.attr_data else self.CODE
256 code = self.attr_data if self.attr_data else self.CODE
257 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
257 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
258 self.tmin = kwargs.get('tmin', None)
258 self.tmin = kwargs.get('tmin', None)
259 self.t_units = kwargs.get('t_units', "h_m")
259 self.t_units = kwargs.get('t_units', "h_m")
260 self.selectedHeightsList = kwargs.get('selectedHeightsList', [])
260 self.selectedHeightsList = kwargs.get('selectedHeightsList', [])
261 if isinstance(self.selectedHeightsList, int):
261 if isinstance(self.selectedHeightsList, int):
262 self.selectedHeightsList = [self.selectedHeightsList]
262 self.selectedHeightsList = [self.selectedHeightsList]
263
263
264 if self.server:
264 if self.server:
265 if not self.server.startswith('tcp://'):
265 if not self.server.startswith('tcp://'):
266 self.server = 'tcp://{}'.format(self.server)
266 self.server = 'tcp://{}'.format(self.server)
267 log.success(
267 log.success(
268 'Sending to server: {}'.format(self.server),
268 'Sending to server: {}'.format(self.server),
269 self.name
269 self.name
270 )
270 )
271
271
272 if isinstance(self.attr_data, str):
272 if isinstance(self.attr_data, str):
273 self.attr_data = [self.attr_data]
273 self.attr_data = [self.attr_data]
274
274
275 def __setup_plot(self):
275 def __setup_plot(self):
276 '''
276 '''
277 Common setup for all figures, here figures and axes are created
277 Common setup for all figures, here figures and axes are created
278 '''
278 '''
279
279
280 self.setup()
280 self.setup()
281
281
282 self.time_label = 'LT' if self.localtime else 'UTC'
282 self.time_label = 'LT' if self.localtime else 'UTC'
283
283
284 if self.width is None:
284 if self.width is None:
285 self.width = 8
285 self.width = 8
286
286
287 self.figures = []
287 self.figures = []
288 self.axes = []
288 self.axes = []
289 self.cb_axes = []
289 self.cb_axes = []
290 self.pf_axes = []
290 self.pf_axes = []
291 self.cmaps = []
291 self.cmaps = []
292
292
293 size = '15%' if self.ncols == 1 else '30%'
293 size = '15%' if self.ncols == 1 else '30%'
294 pad = '4%' if self.ncols == 1 else '8%'
294 pad = '4%' if self.ncols == 1 else '8%'
295
295
296 if self.oneFigure:
296 if self.oneFigure:
297 if self.height is None:
297 if self.height is None:
298 self.height = 1.4 * self.nrows + 1
298 self.height = 1.4 * self.nrows + 1
299 fig = plt.figure(figsize=(self.width, self.height),
299 fig = plt.figure(figsize=(self.width, self.height),
300 edgecolor='k',
300 edgecolor='k',
301 facecolor='w')
301 facecolor='w')
302 self.figures.append(fig)
302 self.figures.append(fig)
303 for n in range(self.nplots):
303 for n in range(self.nplots):
304 ax = fig.add_subplot(self.nrows, self.ncols,
304 ax = fig.add_subplot(self.nrows, self.ncols,
305 n + 1, polar=self.polar)
305 n + 1, polar=self.polar)
306 ax.tick_params(labelsize=8)
306 ax.tick_params(labelsize=8)
307 ax.firsttime = True
307 ax.firsttime = True
308 ax.index = 0
308 ax.index = 0
309 ax.press = None
309 ax.press = None
310 self.axes.append(ax)
310 self.axes.append(ax)
311 if self.showprofile:
311 if self.showprofile:
312 cax = self.__add_axes(ax, size=size, pad=pad)
312 cax = self.__add_axes(ax, size=size, pad=pad)
313 cax.tick_params(labelsize=8)
313 cax.tick_params(labelsize=8)
314 self.pf_axes.append(cax)
314 self.pf_axes.append(cax)
315 else:
315 else:
316 if self.height is None:
316 if self.height is None:
317 self.height = 3
317 self.height = 3
318 for n in range(self.nplots):
318 for n in range(self.nplots):
319 fig = plt.figure(figsize=(self.width, self.height),
319 fig = plt.figure(figsize=(self.width, self.height),
320 edgecolor='k',
320 edgecolor='k',
321 facecolor='w')
321 facecolor='w')
322 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
322 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
323 ax.tick_params(labelsize=8)
323 ax.tick_params(labelsize=8)
324 ax.firsttime = True
324 ax.firsttime = True
325 ax.index = 0
325 ax.index = 0
326 ax.press = None
326 ax.press = None
327 self.figures.append(fig)
327 self.figures.append(fig)
328 self.axes.append(ax)
328 self.axes.append(ax)
329 if self.showprofile:
329 if self.showprofile:
330 cax = self.__add_axes(ax, size=size, pad=pad)
330 cax = self.__add_axes(ax, size=size, pad=pad)
331 cax.tick_params(labelsize=8)
331 cax.tick_params(labelsize=8)
332 self.pf_axes.append(cax)
332 self.pf_axes.append(cax)
333
333
334 for n in range(self.nrows):
334 for n in range(self.nrows):
335 if self.colormaps is not None:
335 if self.colormaps is not None:
336 cmap = plt.get_cmap(self.colormaps[n])
336 cmap = plt.get_cmap(self.colormaps[n])
337 else:
337 else:
338 cmap = plt.get_cmap(self.colormap)
338 cmap = plt.get_cmap(self.colormap)
339 cmap.set_bad(self.bgcolor, 1.)
339 cmap.set_bad(self.bgcolor, 1.)
340 self.cmaps.append(cmap)
340 self.cmaps.append(cmap)
341
341
342 def __add_axes(self, ax, size='30%', pad='8%'):
342 def __add_axes(self, ax, size='30%', pad='8%'):
343 '''
343 '''
344 Add new axes to the given figure
344 Add new axes to the given figure
345 '''
345 '''
346 divider = make_axes_locatable(ax)
346 divider = make_axes_locatable(ax)
347 nax = divider.new_horizontal(size=size, pad=pad)
347 nax = divider.new_horizontal(size=size, pad=pad)
348 ax.figure.add_axes(nax)
348 ax.figure.add_axes(nax)
349 return nax
349 return nax
350
350
351 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
351 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
352 '''
352 '''
353 Create a masked array for missing data
353 Create a masked array for missing data
354 '''
354 '''
355 if x_buffer.shape[0] < 2:
355 if x_buffer.shape[0] < 2:
356 return x_buffer, y_buffer, z_buffer
356 return x_buffer, y_buffer, z_buffer
357
357
358 deltas = x_buffer[1:] - x_buffer[0:-1]
358 deltas = x_buffer[1:] - x_buffer[0:-1]
359 x_median = numpy.median(deltas)
359 x_median = numpy.median(deltas)
360
360
361 index = numpy.where(deltas > 5 * x_median)
361 index = numpy.where(deltas > 5 * x_median)
362
362
363 if len(index[0]) != 0:
363 if len(index[0]) != 0:
364 z_buffer[::, index[0], ::] = self.__missing
364 z_buffer[::, index[0], ::] = self.__missing
365 z_buffer = numpy.ma.masked_inside(z_buffer,
365 z_buffer = numpy.ma.masked_inside(z_buffer,
366 0.99 * self.__missing,
366 0.99 * self.__missing,
367 1.01 * self.__missing)
367 1.01 * self.__missing)
368
368
369 return x_buffer, y_buffer, z_buffer
369 return x_buffer, y_buffer, z_buffer
370
370
371 def decimate(self):
371 def decimate(self):
372
372
373 # dx = int(len(self.x)/self.__MAXNUMX) + 1
373 # dx = int(len(self.x)/self.__MAXNUMX) + 1
374 dy = int(len(self.y) / self.decimation) + 1
374 dy = int(len(self.y) / self.decimation) + 1
375
375
376 # x = self.x[::dx]
376 # x = self.x[::dx]
377 x = self.x
377 x = self.x
378 y = self.y[::dy]
378 y = self.y[::dy]
379 z = self.z[::, ::, ::dy]
379 z = self.z[::, ::, ::dy]
380
380
381 return x, y, z
381 return x, y, z
382
382
383 def format(self):
383 def format(self):
384 '''
384 '''
385 Set min and max values, labels, ticks and titles
385 Set min and max values, labels, ticks and titles
386 '''
386 '''
387
387
388 for n, ax in enumerate(self.axes):
388 for n, ax in enumerate(self.axes):
389 if ax.firsttime:
389 if ax.firsttime:
390 if self.xaxis != 'time':
390 if self.xaxis != 'time':
391 xmin = self.xmin
391 xmin = self.xmin
392 xmax = self.xmax
392 xmax = self.xmax
393 else:
393 else:
394 xmin = self.tmin
394 xmin = self.tmin
395 xmax = self.tmin + self.xrange*60*60
395 xmax = self.tmin + self.xrange*60*60
396 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
396 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
397 if self.t_units == "h_m":
397 if self.t_units == "h_m":
398 ax.xaxis.set_major_locator(LinearLocator(9))
398 ax.xaxis.set_major_locator(LinearLocator(9))
399 if self.t_units == "h":
399 if self.t_units == "h":
400 ax.xaxis.set_major_locator(LinearLocator(int((xmax-xmin)/3600)+1))
400 ax.xaxis.set_major_locator(LinearLocator(int((xmax-xmin)/3600)+1))
401 ymin = self.ymin if self.ymin is not None else numpy.nanmin(self.y[numpy.isfinite(self.y)])
401 ymin = self.ymin if self.ymin is not None else numpy.nanmin(self.y[numpy.isfinite(self.y)])
402 ymax = self.ymax if self.ymax is not None else numpy.nanmax(self.y[numpy.isfinite(self.y)])
402 ymax = self.ymax if self.ymax is not None else numpy.nanmax(self.y[numpy.isfinite(self.y)])
403 ax.set_facecolor(self.bgcolor)
403 ax.set_facecolor(self.bgcolor)
404 if self.xscale:
404 if self.xscale:
405 ax.xaxis.set_major_formatter(FuncFormatter(
405 ax.xaxis.set_major_formatter(FuncFormatter(
406 lambda x, pos: '{0:g}'.format(x*self.xscale)))
406 lambda x, pos: '{0:g}'.format(x*self.xscale)))
407 if self.yscale:
407 if self.yscale:
408 ax.yaxis.set_major_formatter(FuncFormatter(
408 ax.yaxis.set_major_formatter(FuncFormatter(
409 lambda x, pos: '{0:g}'.format(x*self.yscale)))
409 lambda x, pos: '{0:g}'.format(x*self.yscale)))
410 if self.xlabel is not None:
410 if self.xlabel is not None:
411 ax.set_xlabel(self.xlabel)
411 ax.set_xlabel(self.xlabel)
412 if self.ylabel is not None:
412 if self.ylabel is not None:
413 ax.set_ylabel(self.ylabel)
413 ax.set_ylabel(self.ylabel)
414 if self.showprofile:
414 if self.showprofile:
415 self.pf_axes[n].set_ylim(ymin, ymax)
415 self.pf_axes[n].set_ylim(ymin, ymax)
416 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
416 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
417 self.pf_axes[n].set_xlabel('dB')
417 self.pf_axes[n].set_xlabel('dB')
418 self.pf_axes[n].grid(b=True, axis='x')
418 self.pf_axes[n].grid(b=True, axis='x')
419 [tick.set_visible(False)
419 [tick.set_visible(False)
420 for tick in self.pf_axes[n].get_yticklabels()]
420 for tick in self.pf_axes[n].get_yticklabels()]
421 if self.colorbar:
421 if self.colorbar:
422 ax.cbar = plt.colorbar(
422 ax.cbar = plt.colorbar(
423 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
423 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
424 ax.cbar.ax.tick_params(labelsize=8)
424 ax.cbar.ax.tick_params(labelsize=8)
425 ax.cbar.ax.press = None
425 ax.cbar.ax.press = None
426 if self.cb_label:
426 if self.cb_label:
427 ax.cbar.set_label(self.cb_label, size=8)
427 ax.cbar.set_label(self.cb_label, size=8)
428 elif self.cb_labels:
428 elif self.cb_labels:
429 ax.cbar.set_label(self.cb_labels[n], size=8)
429 ax.cbar.set_label(self.cb_labels[n], size=8)
430 else:
430 else:
431 ax.cbar = None
431 ax.cbar = None
432 ax.set_xlim(xmin, xmax)
432 ax.set_xlim(xmin, xmax)
433 ax.set_ylim(ymin, ymax)
433 ax.set_ylim(ymin, ymax)
434 ax.firsttime = False
434 ax.firsttime = False
435 if self.grid:
435 if self.grid:
436 ax.grid(True)
436 ax.grid(True)
437
437
438 if not self.polar:
438 if not self.polar:
439 ax.set_title('{} {} {}'.format(
439 ax.set_title('{} {} {}'.format(
440 self.titles[n],
440 self.titles[n],
441 self.getDateTime(self.data.max_time).strftime(
441 self.getDateTime(self.data.max_time).strftime(
442 '%Y-%m-%d %H:%M:%S'),
442 '%Y-%m-%d %H:%M:%S'),
443 self.time_label),
443 self.time_label),
444 size=8)
444 size=8)
445 else:
445 else:
446
446
447 ax.set_title('{}'.format(self.titles[n]), size=8)
447 ax.set_title('{}'.format(self.titles[n]), size=8)
448 ax.set_ylim(0, 90)
448 ax.set_ylim(0, 90)
449 ax.set_yticks(numpy.arange(0, 90, 20))
449 ax.set_yticks(numpy.arange(0, 90, 20))
450 ax.yaxis.labelpad = 40
450 ax.yaxis.labelpad = 40
451
451
452 if self.firsttime:
452 if self.firsttime:
453 for n, fig in enumerate(self.figures):
453 for n, fig in enumerate(self.figures):
454 fig.subplots_adjust(**self.plots_adjust)
454 fig.subplots_adjust(**self.plots_adjust)
455 self.firsttime = False
455 self.firsttime = False
456
456
457 def clear_figures(self):
457 def clear_figures(self):
458 '''
458 '''
459 Reset axes for redraw plots
459 Reset axes for redraw plots
460 '''
460 '''
461
461
462 for ax in self.axes+self.pf_axes+self.cb_axes:
462 for ax in self.axes+self.pf_axes+self.cb_axes:
463 ax.clear()
463 ax.clear()
464 ax.firsttime = True
464 ax.firsttime = True
465 if hasattr(ax, 'cbar') and ax.cbar:
465 if hasattr(ax, 'cbar') and ax.cbar:
466 ax.cbar.remove()
466 ax.cbar.remove()
467
467
468 def __plot(self):
468 def __plot(self):
469 '''
469 '''
470 Main function to plot, format and save figures
470 Main function to plot, format and save figures
471 '''
471 '''
472
472
473 self.plot()
473 self.plot()
474 self.format()
474 self.format()
475
475
476 for n, fig in enumerate(self.figures):
476 for n, fig in enumerate(self.figures):
477 if self.nrows == 0 or self.nplots == 0:
477 if self.nrows == 0 or self.nplots == 0:
478 log.warning('No data', self.name)
478 log.warning('No data', self.name)
479 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
479 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
480 fig.canvas.manager.set_window_title(self.CODE)
480 fig.canvas.manager.set_window_title(self.CODE)
481 continue
481 continue
482
482
483 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
483 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
484 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
484 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
485
485
486 fig.canvas.draw()
486 fig.canvas.draw()
487 if self.show:
487 if self.show:
488 fig.show()
488 fig.show()
489 figpause(0.01)
489 figpause(0.01)
490
490
491 if self.save:
491 if self.save:
492 self.save_figure(n)
492 self.save_figure(n)
493
493
494 if self.server:
494 if self.server:
495 self.send_to_server()
495 self.send_to_server()
496
496
497 def __update(self, dataOut, timestamp):
497 def __update(self, dataOut, timestamp):
498 '''
498 '''
499 '''
499 '''
500
500
501 metadata = {
501 metadata = {
502 'yrange': dataOut.heightList,
502 'yrange': dataOut.heightList,
503 'interval': dataOut.timeInterval,
503 'interval': dataOut.timeInterval,
504 'channels': dataOut.channelList
504 'channels': dataOut.channelList
505 }
505 }
506 data, meta = self.update(dataOut)
506 data, meta = self.update(dataOut)
507 metadata.update(meta)
507 metadata.update(meta)
508 self.data.update(data, timestamp, metadata)
508 self.data.update(data, timestamp, metadata)
509
509
510 def save_figure(self, n):
510 def save_figure(self, n):
511 '''
511 '''
512 '''
512 '''
513
513
514 if (self.data.max_time - self.save_time) <= self.save_period:
514 if (self.data.max_time - self.save_time) <= self.save_period:
515 return
515 return
516
516
517 self.save_time = self.data.max_time
517 self.save_time = self.data.max_time
518
518
519 fig = self.figures[n]
519 fig = self.figures[n]
520
520
521 if self.throttle == 0:
521 if self.throttle == 0:
522 figname = os.path.join(
522 figname = os.path.join(
523 self.save,
523 self.save,
524 self.save_code,
524 self.save_code,
525 '{}_{}.png'.format(
525 '{}_{}.png'.format(
526 self.save_code,
526 self.save_code,
527 self.getDateTime(self.data.max_time).strftime(
527 self.getDateTime(self.data.max_time).strftime(
528 '%Y%m%d_%H%M%S'
528 '%Y%m%d_%H%M%S'
529 ),
529 ),
530 )
530 )
531 )
531 )
532 log.log('Saving figure: {}'.format(figname), self.name)
532 log.log('Saving figure: {}'.format(figname), self.name)
533 if not os.path.isdir(os.path.dirname(figname)):
533 if not os.path.isdir(os.path.dirname(figname)):
534 os.makedirs(os.path.dirname(figname))
534 os.makedirs(os.path.dirname(figname))
535 fig.savefig(figname)
535 fig.savefig(figname)
536
536
537 figname = os.path.join(
537 figname = os.path.join(
538 self.save,
538 self.save,
539 '{}_{}.png'.format(
539 '{}_{}.png'.format(
540 self.save_code,
540 self.save_code,
541 self.getDateTime(self.data.min_time).strftime(
541 self.getDateTime(self.data.min_time).strftime(
542 '%Y%m%d'
542 '%Y%m%d'
543 ),
543 ),
544 )
544 )
545 )
545 )
546
546
547 log.log('Saving figure: {}'.format(figname), self.name)
547 log.log('Saving figure: {}'.format(figname), self.name)
548 if not os.path.isdir(os.path.dirname(figname)):
548 if not os.path.isdir(os.path.dirname(figname)):
549 os.makedirs(os.path.dirname(figname))
549 os.makedirs(os.path.dirname(figname))
550 fig.savefig(figname)
550 fig.savefig(figname)
551
551
552 def send_to_server(self):
552 def send_to_server(self):
553 '''
553 '''
554 '''
554 '''
555
555
556 if self.exp_code == None:
556 if self.exp_code == None:
557 log.warning('Missing `exp_code` skipping sending to server...')
557 log.warning('Missing `exp_code` skipping sending to server...')
558
558
559 last_time = self.data.max_time
559 last_time = self.data.max_time
560 interval = last_time - self.sender_time
560 interval = last_time - self.sender_time
561 if interval < self.sender_period:
561 if interval < self.sender_period:
562 return
562 return
563
563
564 self.sender_time = last_time
564 self.sender_time = last_time
565
565
566 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
566 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax']
567 for attr in attrs:
567 for attr in attrs:
568 value = getattr(self, attr)
568 value = getattr(self, attr)
569 if value:
569 if value:
570 if isinstance(value, (numpy.float32, numpy.float64)):
570 if isinstance(value, (numpy.float32, numpy.float64)):
571 value = round(float(value), 2)
571 value = round(float(value), 2)
572 self.data.meta[attr] = value
572 self.data.meta[attr] = value
573 if self.colormap == 'jet':
573 if self.colormap == 'jet':
574 self.data.meta['colormap'] = 'Jet'
574 self.data.meta['colormap'] = 'Jet'
575 elif 'RdBu' in self.colormap:
575 elif 'RdBu' in self.colormap:
576 self.data.meta['colormap'] = 'RdBu'
576 self.data.meta['colormap'] = 'RdBu'
577 else:
577 else:
578 self.data.meta['colormap'] = 'Viridis'
578 self.data.meta['colormap'] = 'Viridis'
579 self.data.meta['interval'] = int(interval)
579 self.data.meta['interval'] = int(interval)
580
580
581 self.sender_queue.append(last_time)
581 self.sender_queue.append(last_time)
582
582
583 while 1:
583 while 1:
584 try:
584 try:
585 tm = self.sender_queue.popleft()
585 tm = self.sender_queue.popleft()
586 except IndexError:
586 except IndexError:
587 break
587 break
588 msg = self.data.jsonify(tm, self.save_code, self.plot_type)
588 msg = self.data.jsonify(tm, self.save_code, self.plot_type)
589 self.socket.send_string(msg)
589 self.socket.send_string(msg)
590 socks = dict(self.poll.poll(2000))
590 socks = dict(self.poll.poll(2000))
591 if socks.get(self.socket) == zmq.POLLIN:
591 if socks.get(self.socket) == zmq.POLLIN:
592 reply = self.socket.recv_string()
592 reply = self.socket.recv_string()
593 if reply == 'ok':
593 if reply == 'ok':
594 log.log("Response from server ok", self.name)
594 log.log("Response from server ok", self.name)
595 time.sleep(0.1)
595 time.sleep(0.1)
596 continue
596 continue
597 else:
597 else:
598 log.warning(
598 log.warning(
599 "Malformed reply from server: {}".format(reply), self.name)
599 "Malformed reply from server: {}".format(reply), self.name)
600 else:
600 else:
601 log.warning(
601 log.warning(
602 "No response from server, retrying...", self.name)
602 "No response from server, retrying...", self.name)
603 self.sender_queue.appendleft(tm)
603 self.sender_queue.appendleft(tm)
604 self.socket.setsockopt(zmq.LINGER, 0)
604 self.socket.setsockopt(zmq.LINGER, 0)
605 self.socket.close()
605 self.socket.close()
606 self.poll.unregister(self.socket)
606 self.poll.unregister(self.socket)
607 self.socket = self.context.socket(zmq.REQ)
607 self.socket = self.context.socket(zmq.REQ)
608 self.socket.connect(self.server)
608 self.socket.connect(self.server)
609 self.poll.register(self.socket, zmq.POLLIN)
609 self.poll.register(self.socket, zmq.POLLIN)
610 break
610 break
611
611
612 def setup(self):
612 def setup(self):
613 '''
613 '''
614 This method should be implemented in the child class, the following
614 This method should be implemented in the child class, the following
615 attributes should be set:
615 attributes should be set:
616
616
617 self.nrows: number of rows
617 self.nrows: number of rows
618 self.ncols: number of cols
618 self.ncols: number of cols
619 self.nplots: number of plots (channels or pairs)
619 self.nplots: number of plots (channels or pairs)
620 self.ylabel: label for Y axes
620 self.ylabel: label for Y axes
621 self.titles: list of axes title
621 self.titles: list of axes title
622
622
623 '''
623 '''
624 raise NotImplementedError
624 raise NotImplementedError
625
625
626 def plot(self):
626 def plot(self):
627 '''
627 '''
628 Must be defined in the child class, the actual plotting method
628 Must be defined in the child class, the actual plotting method
629 '''
629 '''
630 raise NotImplementedError
630 raise NotImplementedError
631
631
632 def update(self, dataOut):
632 def update(self, dataOut):
633 '''
633 '''
634 Must be defined in the child class, update self.data with new data
634 Must be defined in the child class, update self.data with new data
635 '''
635 '''
636
636
637 data = {
637 data = {
638 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
638 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
639 }
639 }
640 meta = {}
640 meta = {}
641
641
642 return data, meta
642 return data, meta
643
643
644 def run(self, dataOut, **kwargs):
644 def run(self, dataOut, **kwargs):
645 '''
645 '''
646 Main plotting routine
646 Main plotting routine
647 '''
647 '''
648 if self.isConfig is False:
648 if self.isConfig is False:
649 self.__setup(**kwargs)
649 self.__setup(**kwargs)
650
650
651 if self.localtime:
651 if self.localtime:
652 self.getDateTime = datetime.datetime.fromtimestamp
652 self.getDateTime = datetime.datetime.fromtimestamp
653 else:
653 else:
654 self.getDateTime = datetime.datetime.utcfromtimestamp
654 self.getDateTime = datetime.datetime.utcfromtimestamp
655
655
656 self.data.setup()
656 self.data.setup()
657 self.isConfig = True
657 self.isConfig = True
658 if self.server:
658 if self.server:
659 self.context = zmq.Context()
659 self.context = zmq.Context()
660 self.socket = self.context.socket(zmq.REQ)
660 self.socket = self.context.socket(zmq.REQ)
661 self.socket.connect(self.server)
661 self.socket.connect(self.server)
662 self.poll = zmq.Poller()
662 self.poll = zmq.Poller()
663 self.poll.register(self.socket, zmq.POLLIN)
663 self.poll.register(self.socket, zmq.POLLIN)
664
664
665 tm = getattr(dataOut, self.attr_time)
665 tm = getattr(dataOut, self.attr_time)
666
666
667 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
667 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
668 self.clear_figures()
668 self.save_time = tm
669 self.save_time = tm
670 self.__plot()
669 self.tmin += self.xrange*60*60
671 self.tmin += self.xrange*60*60
670 self.data.setup()
672 self.data.setup()
671 self.clear_figures()
673 #self.clear_figures()
672 self.__plot()
674
673
675
674 self.__update(dataOut, tm)
676 self.__update(dataOut, tm)
675
677
676 if self.isPlotConfig is False:
678 if self.isPlotConfig is False:
677 self.__setup_plot()
679 self.__setup_plot()
678 self.isPlotConfig = True
680 self.isPlotConfig = True
679 if self.xaxis == 'time':
681 if self.xaxis == 'time':
680 dt = self.getDateTime(tm)
682 dt = self.getDateTime(tm)
681 if self.xmin is None:
683 if self.xmin is None:
682 self.tmin = tm
684 self.tmin = tm
683 self.xmin = dt.hour
685 self.xmin = dt.hour
684 minutes = (self.xmin-int(self.xmin)) * 60
686 minutes = (self.xmin-int(self.xmin)) * 60
685 seconds = (minutes - int(minutes)) * 60
687 seconds = (minutes - int(minutes)) * 60
686 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
688 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
687 datetime.datetime(1970, 1, 1)).total_seconds()
689 datetime.datetime(1970, 1, 1)).total_seconds()
688 if self.localtime:
690 if self.localtime:
689 self.tmin += time.timezone
691 self.tmin += time.timezone
690
692
691 if self.xmin is not None and self.xmax is not None:
693 if self.xmin is not None and self.xmax is not None:
692 self.xrange = self.xmax - self.xmin
694 self.xrange = self.xmax - self.xmin
693
695
694 if self.throttle == 0:
696 if self.throttle == 0:
695 self.__plot()
697 self.__plot()
696 else:
698 else:
697 self.__throttle_plot(self.__plot)#, coerce=coerce)
699 self.__throttle_plot(self.__plot)#, coerce=coerce)
698
700
699 def close(self):
701 def close(self):
700
702
701 if self.data and not self.data.flagNoData:
703 if self.data and not self.data.flagNoData:
702 self.save_time = 0
704 self.save_time = 0
703 self.__plot()
705 self.__plot()
704 if self.data and not self.data.flagNoData and self.pause:
706 if self.data and not self.data.flagNoData and self.pause:
705 figpause(10)
707 figpause(10)
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now