##// END OF EJS Templates
update jroplot_base.py
avaldez -
r1792:800f91ef3d84 isr
parent child
Show More
@@ -1,705 +1,705
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
45
46 matplotlib.pyplot.register_cmap(cmap=ncmap)
46 matplotlib.pyplot.register_cmap(cmap=ncmap)
47 #matplotlib.register_cmap(cmap=ncmap)
47 #matplotlib.register_cmap(cmap=ncmap)
48 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
48 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
49 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
49 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
50
50
51 EARTH_RADIUS = 6.3710e3
51 EARTH_RADIUS = 6.3710e3
52
52
53 def ll2xy(lat1, lon1, lat2, lon2):
53 def ll2xy(lat1, lon1, lat2, lon2):
54
54
55 p = 0.017453292519943295
55 p = 0.017453292519943295
56 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
56 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
57 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
57 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
58 r = 12742 * numpy.arcsin(numpy.sqrt(a))
58 r = 12742 * numpy.arcsin(numpy.sqrt(a))
59 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
59 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
60 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
60 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
61 theta = -theta + numpy.pi/2
61 theta = -theta + numpy.pi/2
62 return r*numpy.cos(theta), r*numpy.sin(theta)
62 return r*numpy.cos(theta), r*numpy.sin(theta)
63
63
64
64
65 def km2deg(km):
65 def km2deg(km):
66 '''
66 '''
67 Convert distance in km to degrees
67 Convert distance in km to degrees
68 '''
68 '''
69
69
70 return numpy.rad2deg(km/EARTH_RADIUS)
70 return numpy.rad2deg(km/EARTH_RADIUS)
71
71
72
72
73 def figpause(interval):
73 def figpause(interval):
74 backend = plt.rcParams['backend']
74 backend = plt.rcParams['backend']
75 if backend in matplotlib.rcsetup.interactive_bk:
75 if backend in matplotlib.rcsetup.interactive_bk:
76 figManager = matplotlib._pylab_helpers.Gcf.get_active()
76 figManager = matplotlib._pylab_helpers.Gcf.get_active()
77 if figManager is not None:
77 if figManager is not None:
78 canvas = figManager.canvas
78 canvas = figManager.canvas
79 if canvas.figure.stale:
79 if canvas.figure.stale:
80 canvas.draw()
80 canvas.draw()
81 try:
81 try:
82 canvas.start_event_loop(interval)
82 canvas.start_event_loop(interval)
83 except:
83 except:
84 pass
84 pass
85 return
85 return
86
86
87 def popup(message):
87 def popup(message):
88 '''
88 '''
89 '''
89 '''
90
90
91 fig = plt.figure(figsize=(12, 8), facecolor='r')
91 fig = plt.figure(figsize=(12, 8), facecolor='r')
92 text = '\n'.join([s.strip() for s in message.split(':')])
92 text = '\n'.join([s.strip() for s in message.split(':')])
93 fig.text(0.01, 0.5, text, ha='left', va='center',
93 fig.text(0.01, 0.5, text, ha='left', va='center',
94 size='20', weight='heavy', color='w')
94 size='20', weight='heavy', color='w')
95 fig.show()
95 fig.show()
96 figpause(1000)
96 figpause(1000)
97
97
98
98
99 class Throttle(object):
99 class Throttle(object):
100 '''
100 '''
101 Decorator that prevents a function from being called more than once every
101 Decorator that prevents a function from being called more than once every
102 time period.
102 time period.
103 To create a function that cannot be called more than once a minute, but
103 To create a function that cannot be called more than once a minute, but
104 will sleep until it can be called:
104 will sleep until it can be called:
105 @Throttle(minutes=1)
105 @Throttle(minutes=1)
106 def foo():
106 def foo():
107 pass
107 pass
108
108
109 for i in range(10):
109 for i in range(10):
110 foo()
110 foo()
111 print "This function has run %s times." % i
111 print "This function has run %s times." % i
112 '''
112 '''
113
113
114 def __init__(self, seconds=0, minutes=0, hours=0):
114 def __init__(self, seconds=0, minutes=0, hours=0):
115 self.throttle_period = datetime.timedelta(
115 self.throttle_period = datetime.timedelta(
116 seconds=seconds, minutes=minutes, hours=hours
116 seconds=seconds, minutes=minutes, hours=hours
117 )
117 )
118
118
119 self.time_of_last_call = datetime.datetime.min
119 self.time_of_last_call = datetime.datetime.min
120
120
121 def __call__(self, fn):
121 def __call__(self, fn):
122 @wraps(fn)
122 @wraps(fn)
123 def wrapper(*args, **kwargs):
123 def wrapper(*args, **kwargs):
124 coerce = kwargs.pop('coerce', None)
124 coerce = kwargs.pop('coerce', None)
125 if coerce:
125 if coerce:
126 self.time_of_last_call = datetime.datetime.now()
126 self.time_of_last_call = datetime.datetime.now()
127 return fn(*args, **kwargs)
127 return fn(*args, **kwargs)
128 else:
128 else:
129 now = datetime.datetime.now()
129 now = datetime.datetime.now()
130 time_since_last_call = now - self.time_of_last_call
130 time_since_last_call = now - self.time_of_last_call
131 time_left = self.throttle_period - time_since_last_call
131 time_left = self.throttle_period - time_since_last_call
132
132
133 if time_left > datetime.timedelta(seconds=0):
133 if time_left > datetime.timedelta(seconds=0):
134 return
134 return
135
135
136 self.time_of_last_call = datetime.datetime.now()
136 self.time_of_last_call = datetime.datetime.now()
137 return fn(*args, **kwargs)
137 return fn(*args, **kwargs)
138
138
139 return wrapper
139 return wrapper
140
140
141 def apply_throttle(value):
141 def apply_throttle(value):
142
142
143 @Throttle(seconds=value)
143 @Throttle(seconds=value)
144 def fnThrottled(fn):
144 def fnThrottled(fn):
145 fn()
145 fn()
146
146
147 return fnThrottled
147 return fnThrottled
148
148
149
149
150 @MPDecorator
150 @MPDecorator
151 class Plot(Operation):
151 class Plot(Operation):
152 """Base class for Schain plotting operations
152 """Base class for Schain plotting operations
153
153
154 This class should never be use directtly you must subclass a new operation,
154 This class should never be use directtly you must subclass a new operation,
155 children classes must be defined as follow:
155 children classes must be defined as follow:
156
156
157 ExamplePlot(Plot):
157 ExamplePlot(Plot):
158
158
159 CODE = 'code'
159 CODE = 'code'
160 colormap = 'jet'
160 colormap = 'jet'
161 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
161 plot_type = 'pcolor' # options are ('pcolor', 'pcolorbuffer', 'scatter', 'scatterbuffer')
162
162
163 def setup(self):
163 def setup(self):
164 pass
164 pass
165
165
166 def plot(self):
166 def plot(self):
167 pass
167 pass
168
168
169 """
169 """
170
170
171 CODE = 'Figure'
171 CODE = 'Figure'
172 colormap = 'jet'
172 colormap = 'jet'
173 bgcolor = 'white'
173 bgcolor = 'white'
174 buffering = True
174 buffering = True
175 __missing = 1E30
175 __missing = 1E30
176
176
177 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
177 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
178 'showprofile']
178 'showprofile']
179
179
180 def __init__(self):
180 def __init__(self):
181
181
182 Operation.__init__(self)
182 Operation.__init__(self)
183 self.isConfig = False
183 self.isConfig = False
184 self.isPlotConfig = False
184 self.isPlotConfig = False
185 self.save_time = 0
185 self.save_time = 0
186 self.sender_time = 0
186 self.sender_time = 0
187 self.data = None
187 self.data = None
188 self.firsttime = True
188 self.firsttime = True
189 self.sender_queue = deque(maxlen=10)
189 self.sender_queue = deque(maxlen=10)
190 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
190 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
191
191
192 def __fmtTime(self, x, pos):
192 def __fmtTime(self, x, pos):
193 '''
193 '''
194 '''
194 '''
195
195
196 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
196 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
197
197
198 def __setup(self, **kwargs):
198 def __setup(self, **kwargs):
199 '''
199 '''
200 Initialize variables
200 Initialize variables
201 '''
201 '''
202
202
203 self.figures = []
203 self.figures = []
204 self.axes = []
204 self.axes = []
205 self.cb_axes = []
205 self.cb_axes = []
206 self.localtime = kwargs.pop('localtime', True)
206 self.localtime = kwargs.pop('localtime', True)
207 self.show = kwargs.get('show', True)
207 self.show = kwargs.get('show', True)
208 self.save = kwargs.get('save', False)
208 self.save = kwargs.get('save', False)
209 self.save_period = kwargs.get('save_period', 0)
209 self.save_period = kwargs.get('save_period', 0)
210 self.colormap = kwargs.get('colormap', self.colormap)
210 self.colormap = kwargs.get('colormap', self.colormap)
211 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
211 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
212 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
212 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
213 self.colormaps = kwargs.get('colormaps', None)
213 self.colormaps = kwargs.get('colormaps', None)
214 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
214 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
215 self.showprofile = kwargs.get('showprofile', False)
215 self.showprofile = kwargs.get('showprofile', False)
216 self.title = kwargs.get('wintitle', self.CODE.upper())
216 self.title = kwargs.get('wintitle', self.CODE.upper())
217 self.cb_label = kwargs.get('cb_label', None)
217 self.cb_label = kwargs.get('cb_label', None)
218 self.cb_labels = kwargs.get('cb_labels', None)
218 self.cb_labels = kwargs.get('cb_labels', None)
219 self.labels = kwargs.get('labels', None)
219 self.labels = kwargs.get('labels', None)
220 self.xaxis = kwargs.get('xaxis', 'frequency')
220 self.xaxis = kwargs.get('xaxis', 'frequency')
221 self.zmin = kwargs.get('zmin', None)
221 self.zmin = kwargs.get('zmin', None)
222 self.zmax = kwargs.get('zmax', None)
222 self.zmax = kwargs.get('zmax', None)
223 self.zlimits = kwargs.get('zlimits', None)
223 self.zlimits = kwargs.get('zlimits', None)
224 self.xlimits = kwargs.get('xlimits', None)
224 self.xlimits = kwargs.get('xlimits', None)
225 self.xstep_given = kwargs.get('xstep_given', None)
225 self.xstep_given = kwargs.get('xstep_given', None)
226 self.ystep_given = kwargs.get('ystep_given', None)
226 self.ystep_given = kwargs.get('ystep_given', None)
227 self.autoxticks = kwargs.get('autoxticks', True)
227 self.autoxticks = kwargs.get('autoxticks', True)
228 self.xmin = kwargs.get('xmin', None)
228 self.xmin = kwargs.get('xmin', None)
229 self.xmax = kwargs.get('xmax', None)
229 self.xmax = kwargs.get('xmax', None)
230 self.xrange = kwargs.get('xrange', 12)
230 self.xrange = kwargs.get('xrange', 12)
231 self.xscale = kwargs.get('xscale', None)
231 self.xscale = kwargs.get('xscale', None)
232 self.ymin = kwargs.get('ymin', None)
232 self.ymin = kwargs.get('ymin', None)
233 self.ymax = kwargs.get('ymax', None)
233 self.ymax = kwargs.get('ymax', None)
234 self.yscale = kwargs.get('yscale', None)
234 self.yscale = kwargs.get('yscale', None)
235 self.xlabel = kwargs.get('xlabel', None)
235 self.xlabel = kwargs.get('xlabel', None)
236 self.attr_time = kwargs.get('attr_time', 'utctime')
236 self.attr_time = kwargs.get('attr_time', 'utctime')
237 self.attr_data = kwargs.get('attr_data', 'data_param')
237 self.attr_data = kwargs.get('attr_data', 'data_param')
238 self.decimation = kwargs.get('decimation', None)
238 self.decimation = kwargs.get('decimation', None)
239 self.oneFigure = kwargs.get('oneFigure', True)
239 self.oneFigure = kwargs.get('oneFigure', True)
240 self.width = kwargs.get('width', None)
240 self.width = kwargs.get('width', None)
241 self.height = kwargs.get('height', None)
241 self.height = kwargs.get('height', None)
242 self.colorbar = kwargs.get('colorbar', True)
242 self.colorbar = kwargs.get('colorbar', True)
243 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
243 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
244 self.channels = kwargs.get('channels', None)
244 self.channels = kwargs.get('channels', None)
245 self.titles = kwargs.get('titles', [])
245 self.titles = kwargs.get('titles', [])
246 self.polar = False
246 self.polar = False
247 self.type = kwargs.get('type', 'iq')
247 self.type = kwargs.get('type', 'iq')
248 self.grid = kwargs.get('grid', False)
248 self.grid = kwargs.get('grid', False)
249 self.pause = kwargs.get('pause', False)
249 self.pause = kwargs.get('pause', False)
250 self.save_code = kwargs.get('save_code', self.CODE)
250 self.save_code = kwargs.get('save_code', self.CODE)
251 self.throttle = kwargs.get('throttle', 0)
251 self.throttle = kwargs.get('throttle', 0)
252 self.exp_code = kwargs.get('exp_code', None)
252 self.exp_code = kwargs.get('exp_code', None)
253 self.server = kwargs.get('server', False)
253 self.server = kwargs.get('server', False)
254 self.sender_period = kwargs.get('sender_period', 60)
254 self.sender_period = kwargs.get('sender_period', 60)
255 self.tag = kwargs.get('tag', '')
255 self.tag = kwargs.get('tag', '')
256 self.height_index = kwargs.get('height_index', None)
256 self.height_index = kwargs.get('height_index', None)
257 self.__throttle_plot = apply_throttle(self.throttle)
257 self.__throttle_plot = apply_throttle(self.throttle)
258 code = self.attr_data if self.attr_data else self.CODE
258 code = self.attr_data if self.attr_data else self.CODE
259 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
259 self.data = PlotterData(self.CODE, self.exp_code, self.localtime)
260 #self.EEJtype = kwargs.get('EEJtype', 2)
260 #self.EEJtype = kwargs.get('EEJtype', 2)
261
261
262 if self.server:
262 if self.server:
263 if not self.server.startswith('tcp://'):
263 if not self.server.startswith('tcp://'):
264 self.server = 'tcp://{}'.format(self.server)
264 self.server = 'tcp://{}'.format(self.server)
265 log.success(
265 log.success(
266 'Sending to server: {}'.format(self.server),
266 'Sending to server: {}'.format(self.server),
267 self.name
267 self.name
268 )
268 )
269
269
270 if isinstance(self.attr_data, str):
270 if isinstance(self.attr_data, str):
271 self.attr_data = [self.attr_data]
271 self.attr_data = [self.attr_data]
272
272
273 def __setup_plot(self):
273 def __setup_plot(self):
274 '''
274 '''
275 Common setup for all figures, here figures and axes are created
275 Common setup for all figures, here figures and axes are created
276 '''
276 '''
277
277
278 self.setup()
278 self.setup()
279
279
280 self.time_label = 'LT' if self.localtime else 'UTC'
280 self.time_label = 'LT' if self.localtime else 'UTC'
281
281
282 if self.width is None:
282 if self.width is None:
283 self.width = 8
283 self.width = 8
284
284
285 self.figures = []
285 self.figures = []
286 self.axes = []
286 self.axes = []
287 self.cb_axes = []
287 self.cb_axes = []
288 self.pf_axes = []
288 self.pf_axes = []
289 self.cmaps = []
289 self.cmaps = []
290
290
291 size = '15%' if self.ncols == 1 else '30%'
291 size = '15%' if self.ncols == 1 else '30%'
292 pad = '4%' if self.ncols == 1 else '8%'
292 pad = '4%' if self.ncols == 1 else '8%'
293
293
294 if self.oneFigure:
294 if self.oneFigure:
295 if self.height is None:
295 if self.height is None:
296 self.height = 1.4 * self.nrows + 1
296 self.height = 1.4 * self.nrows + 1
297 fig = plt.figure(figsize=(self.width, self.height),
297 fig = plt.figure(figsize=(self.width, self.height),
298 edgecolor='k',
298 edgecolor='k',
299 facecolor='w')
299 facecolor='w')
300 self.figures.append(fig)
300 self.figures.append(fig)
301 for n in range(self.nplots):
301 for n in range(self.nplots):
302 ax = fig.add_subplot(self.nrows, self.ncols,
302 ax = fig.add_subplot(self.nrows, self.ncols,
303 n + 1, polar=self.polar)
303 n + 1, polar=self.polar)
304 ax.tick_params(labelsize=8)
304 ax.tick_params(labelsize=8)
305 ax.firsttime = True
305 ax.firsttime = True
306 ax.index = 0
306 ax.index = 0
307 ax.press = None
307 ax.press = None
308 ax.cbar = None
308 #ax.cbar = None
309 self.axes.append(ax)
309 self.axes.append(ax)
310 if self.showprofile:
310 if self.showprofile:
311 cax = self.__add_axes(ax, size=size, pad=pad)
311 cax = self.__add_axes(ax, size=size, pad=pad)
312 cax.tick_params(labelsize=8)
312 cax.tick_params(labelsize=8)
313 self.pf_axes.append(cax)
313 self.pf_axes.append(cax)
314 else:
314 else:
315 if self.height is None:
315 if self.height is None:
316 self.height = 3
316 self.height = 3
317 for n in range(self.nplots):
317 for n in range(self.nplots):
318 fig = plt.figure(figsize=(self.width, self.height),
318 fig = plt.figure(figsize=(self.width, self.height),
319 edgecolor='k',
319 edgecolor='k',
320 facecolor='w')
320 facecolor='w')
321 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
321 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
322 ax.tick_params(labelsize=8)
322 ax.tick_params(labelsize=8)
323 ax.firsttime = True
323 ax.firsttime = True
324 ax.index = 0
324 ax.index = 0
325 ax.press = None
325 ax.press = None
326 self.figures.append(fig)
326 self.figures.append(fig)
327 self.axes.append(ax)
327 self.axes.append(ax)
328 if self.showprofile:
328 if self.showprofile:
329 cax = self.__add_axes(ax, size=size, pad=pad)
329 cax = self.__add_axes(ax, size=size, pad=pad)
330 cax.tick_params(labelsize=8)
330 cax.tick_params(labelsize=8)
331 self.pf_axes.append(cax)
331 self.pf_axes.append(cax)
332
332
333 for n in range(self.nrows):
333 for n in range(self.nrows):
334 if self.colormaps is not None:
334 if self.colormaps is not None:
335 cmap = plt.get_cmap(self.colormaps[n])
335 cmap = plt.get_cmap(self.colormaps[n])
336 else:
336 else:
337 cmap = plt.get_cmap(self.colormap)
337 cmap = plt.get_cmap(self.colormap)
338 cmap.set_bad(self.bgcolor, 1.)
338 cmap.set_bad(self.bgcolor, 1.)
339 self.cmaps.append(cmap)
339 self.cmaps.append(cmap)
340
340
341 def __add_axes(self, ax, size='30%', pad='8%'):
341 def __add_axes(self, ax, size='30%', pad='8%'):
342 '''
342 '''
343 Add new axes to the given figure
343 Add new axes to the given figure
344 '''
344 '''
345 divider = make_axes_locatable(ax)
345 divider = make_axes_locatable(ax)
346 nax = divider.new_horizontal(size=size, pad=pad)
346 nax = divider.new_horizontal(size=size, pad=pad)
347 ax.figure.add_axes(nax)
347 ax.figure.add_axes(nax)
348 return nax
348 return nax
349
349
350 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
350 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
351 '''
351 '''
352 Create a masked array for missing data
352 Create a masked array for missing data
353 '''
353 '''
354 if x_buffer.shape[0] < 2:
354 if x_buffer.shape[0] < 2:
355 return x_buffer, y_buffer, z_buffer
355 return x_buffer, y_buffer, z_buffer
356
356
357 deltas = x_buffer[1:] - x_buffer[0:-1]
357 deltas = x_buffer[1:] - x_buffer[0:-1]
358 x_median = numpy.median(deltas)
358 x_median = numpy.median(deltas)
359
359
360 index = numpy.where(deltas > 5 * x_median)
360 index = numpy.where(deltas > 5 * x_median)
361
361
362 if len(index[0]) != 0:
362 if len(index[0]) != 0:
363 z_buffer[::, index[0], ::] = self.__missing
363 z_buffer[::, index[0], ::] = self.__missing
364 z_buffer = numpy.ma.masked_inside(z_buffer,
364 z_buffer = numpy.ma.masked_inside(z_buffer,
365 0.99 * self.__missing,
365 0.99 * self.__missing,
366 1.01 * self.__missing)
366 1.01 * self.__missing)
367
367
368 return x_buffer, y_buffer, z_buffer
368 return x_buffer, y_buffer, z_buffer
369
369
370 def decimate(self):
370 def decimate(self):
371
371
372 # dx = int(len(self.x)/self.__MAXNUMX) + 1
372 # dx = int(len(self.x)/self.__MAXNUMX) + 1
373 dy = int(len(self.y) / self.decimation) + 1
373 dy = int(len(self.y) / self.decimation) + 1
374
374
375 # x = self.x[::dx]
375 # x = self.x[::dx]
376 x = self.x
376 x = self.x
377 y = self.y[::dy]
377 y = self.y[::dy]
378 z = self.z[::, ::, ::dy]
378 z = self.z[::, ::, ::dy]
379
379
380 return x, y, z
380 return x, y, z
381
381
382 def format(self):
382 def format(self):
383 '''
383 '''
384 Set min and max values, labels, ticks and titles
384 Set min and max values, labels, ticks and titles
385 '''
385 '''
386
386
387 for n, ax in enumerate(self.axes):
387 for n, ax in enumerate(self.axes):
388 if ax.firsttime:
388 if ax.firsttime:
389 if self.xaxis != 'time':
389 if self.xaxis != 'time':
390 xmin = self.xmin
390 xmin = self.xmin
391 xmax = self.xmax
391 xmax = self.xmax
392 else:
392 else:
393 xmin = self.tmin
393 xmin = self.tmin
394 xmax = self.tmin + self.xrange*60*60
394 xmax = self.tmin + self.xrange*60*60
395 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
395 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
396 ax.xaxis.set_major_locator(LinearLocator(9))
396 ax.xaxis.set_major_locator(LinearLocator(9))
397 ymin = self.ymin if self.ymin is not None else numpy.nanmin(self.y[numpy.isfinite(self.y)])
397 ymin = self.ymin if self.ymin is not None else numpy.nanmin(self.y[numpy.isfinite(self.y)])
398 ymax = self.ymax if self.ymax is not None else numpy.nanmax(self.y[numpy.isfinite(self.y)])
398 ymax = self.ymax if self.ymax is not None else numpy.nanmax(self.y[numpy.isfinite(self.y)])
399 ax.set_facecolor(self.bgcolor)
399 ax.set_facecolor(self.bgcolor)
400 if self.xscale:
400 if self.xscale:
401 ax.xaxis.set_major_formatter(FuncFormatter(
401 ax.xaxis.set_major_formatter(FuncFormatter(
402 lambda x, pos: '{0:g}'.format(x*self.xscale)))
402 lambda x, pos: '{0:g}'.format(x*self.xscale)))
403 if self.yscale:
403 if self.yscale:
404 ax.yaxis.set_major_formatter(FuncFormatter(
404 ax.yaxis.set_major_formatter(FuncFormatter(
405 lambda x, pos: '{0:g}'.format(x*self.yscale)))
405 lambda x, pos: '{0:g}'.format(x*self.yscale)))
406 if self.xlabel is not None:
406 if self.xlabel is not None:
407 ax.set_xlabel(self.xlabel)
407 ax.set_xlabel(self.xlabel)
408 if self.ylabel is not None:
408 if self.ylabel is not None:
409 ax.set_ylabel(self.ylabel)
409 ax.set_ylabel(self.ylabel)
410 if self.showprofile:
410 if self.showprofile:
411 if self.zlimits is not None:
411 #if self.zlimits is not None:
412 self.zmin, self.zmax = self.zlimits[n]
412 # self.zmin, self.zmax = self.zlimits[n]
413 self.pf_axes[n].set_ylim(ymin, ymax)
413 self.pf_axes[n].set_ylim(ymin, ymax)
414 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
414 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
415 self.pf_axes[n].set_xlabel('dB')
415 self.pf_axes[n].set_xlabel('dB')
416 self.pf_axes[n].grid(b=True, axis='x')
416 self.pf_axes[n].grid(b=True, axis='x')
417 [tick.set_visible(False)
417 [tick.set_visible(False)
418 for tick in self.pf_axes[n].get_yticklabels()]
418 for tick in self.pf_axes[n].get_yticklabels()]
419 if self.colorbar and ax.cbar == None:
419 if self.colorbar and not(hasattr(ax,'cbar')):
420 ax.cbar = plt.colorbar(
420 ax.cbar = plt.colorbar(
421 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
421 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
422 ax.cbar.ax.tick_params(labelsize=8)
422 ax.cbar.ax.tick_params(labelsize=8)
423 ax.cbar.ax.press = None
423 ax.cbar.ax.press = None
424 if self.cb_label:
424 if self.cb_label:
425 ax.cbar.set_label(self.cb_label, size=8)
425 ax.cbar.set_label(self.cb_label, size=8)
426 elif self.cb_labels:
426 elif self.cb_labels:
427 ax.cbar.set_label(self.cb_labels[n], size=8)
427 ax.cbar.set_label(self.cb_labels[n], size=8)
428 else:
428 else:
429 ax.cbar = None
429 ax.cbar = None
430 ax.set_xlim(xmin, xmax)
430 ax.set_xlim(xmin, xmax)
431 ax.set_ylim(ymin, ymax)
431 ax.set_ylim(ymin, ymax)
432 ax.firsttime = False
432 ax.firsttime = False
433 if self.grid:
433 if self.grid:
434 ax.grid(True)
434 ax.grid(True)
435 if not self.polar:
435 if not self.polar:
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 else:
442 else:
443 ax.set_title('{}'.format(self.titles[n]), size=8)
443 ax.set_title('{}'.format(self.titles[n]), size=8)
444 ax.set_ylim(0, 90)
444 ax.set_ylim(0, 90)
445 ax.set_yticks(numpy.arange(0, 90, 20))
445 ax.set_yticks(numpy.arange(0, 90, 20))
446 ax.yaxis.labelpad = 40
446 ax.yaxis.labelpad = 40
447
447
448 if self.firsttime:
448 if self.firsttime:
449 for n, fig in enumerate(self.figures):
449 for n, fig in enumerate(self.figures):
450 fig.subplots_adjust(**self.plots_adjust)
450 fig.subplots_adjust(**self.plots_adjust)
451 self.firsttime = False
451 self.firsttime = False
452
452
453 def clear_figures(self):
453 def clear_figures(self):
454 '''
454 '''
455 Reset axes for redraw plots
455 Reset axes for redraw plots
456 '''
456 '''
457
457
458 for ax in self.axes+self.pf_axes+self.cb_axes:
458 for ax in self.axes+self.pf_axes+self.cb_axes:
459 ax.clear()
459 ax.clear()
460 ax.firsttime = True
460 ax.firsttime = True
461 #if hasattr(ax, 'cbar') and ax.cbar:
461 #if hasattr(ax, 'cbar') and ax.cbar:
462 # ax.cbar.remove()
462 # ax.cbar.remove()
463
463
464 def __plot(self):
464 def __plot(self):
465 '''
465 '''
466 Main function to plot, format and save figures
466 Main function to plot, format and save figures
467 '''
467 '''
468
468
469 self.plot()
469 self.plot()
470 self.format()
470 self.format()
471
471
472 for n, fig in enumerate(self.figures):
472 for n, fig in enumerate(self.figures):
473 if self.nrows == 0 or self.nplots == 0:
473 if self.nrows == 0 or self.nplots == 0:
474 log.warning('No data', self.name)
474 log.warning('No data', self.name)
475 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
475 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
476 fig.canvas.manager.set_window_title(self.CODE)
476 fig.canvas.manager.set_window_title(self.CODE)
477 continue
477 continue
478
478
479 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
479 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
480 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
480 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
481 fig.canvas.draw()
481 fig.canvas.draw()
482 if self.show:
482 if self.show:
483 fig.show()
483 fig.show()
484 figpause(0.01)
484 figpause(0.01)
485
485
486 if self.save:
486 if self.save:
487 self.save_figure(n)
487 self.save_figure(n)
488
488
489 if self.server:
489 if self.server:
490 self.send_to_server()
490 self.send_to_server()
491
491
492 def __update(self, dataOut, timestamp):
492 def __update(self, dataOut, timestamp):
493 '''
493 '''
494 '''
494 '''
495
495
496 metadata = {
496 metadata = {
497 'yrange': dataOut.heightList,
497 'yrange': dataOut.heightList,
498 'interval': dataOut.timeInterval,
498 'interval': dataOut.timeInterval,
499 'channels': dataOut.channelList
499 'channels': dataOut.channelList
500 }
500 }
501
501
502 data, meta = self.update(dataOut)
502 data, meta = self.update(dataOut)
503 metadata.update(meta)
503 metadata.update(meta)
504 self.data.update(data, timestamp, metadata)
504 self.data.update(data, timestamp, metadata)
505
505
506 def save_figure(self, n):
506 def save_figure(self, n):
507 '''
507 '''
508 '''
508 '''
509
509
510 if (self.data.max_time - self.save_time) <= self.save_period:
510 if (self.data.max_time - self.save_time) <= self.save_period:
511 return
511 return
512
512
513 self.save_time = self.data.max_time
513 self.save_time = self.data.max_time
514
514
515 fig = self.figures[n]
515 fig = self.figures[n]
516
516
517 if self.throttle == 0:
517 if self.throttle == 0:
518 figname = os.path.join(
518 figname = os.path.join(
519 self.save,
519 self.save,
520 self.save_code,
520 self.save_code,
521 '{}_{}.png'.format(
521 '{}_{}.png'.format(
522 self.save_code,
522 self.save_code,
523 self.getDateTime(self.data.max_time).strftime(
523 self.getDateTime(self.data.max_time).strftime(
524 '%Y%m%d_%H%M%S'
524 '%Y%m%d_%H%M%S'
525 ),
525 ),
526 )
526 )
527 )
527 )
528 log.log('Saving figure: {}'.format(figname), self.name)
528 log.log('Saving figure: {}'.format(figname), self.name)
529 if not os.path.isdir(os.path.dirname(figname)):
529 if not os.path.isdir(os.path.dirname(figname)):
530 os.makedirs(os.path.dirname(figname))
530 os.makedirs(os.path.dirname(figname))
531 fig.savefig(figname)
531 fig.savefig(figname)
532
532
533 figname = os.path.join(
533 figname = os.path.join(
534 self.save,
534 self.save,
535 #self.save_code,
535 self.save_code,
536 '{}_{}.png'.format(
536 '{}_{}.png'.format(
537 self.save_code,
537 self.save_code,
538 self.getDateTime(self.data.min_time).strftime(
538 self.getDateTime(self.data.min_time).strftime(
539 '%Y%m%d'
539 '%Y%m%d'
540 ),
540 ),
541 )
541 )
542 )
542 )
543 log.log('Saving figure: {}'.format(figname), self.name)
543 log.log('Saving figure: {}'.format(figname), self.name)
544 if not os.path.isdir(os.path.dirname(figname)):
544 if not os.path.isdir(os.path.dirname(figname)):
545 os.makedirs(os.path.dirname(figname))
545 os.makedirs(os.path.dirname(figname))
546 fig.savefig(figname)
546 fig.savefig(figname)
547
547
548 def send_to_server(self):
548 def send_to_server(self):
549 '''
549 '''
550 '''
550 '''
551
551
552 if self.exp_code == None:
552 if self.exp_code == None:
553 log.warning('Missing `exp_code` skipping sending to server...')
553 log.warning('Missing `exp_code` skipping sending to server...')
554
554
555 last_time = self.data.max_time
555 last_time = self.data.max_time
556 interval = last_time - self.sender_time
556 interval = last_time - self.sender_time
557 if interval < self.sender_period:
557 if interval < self.sender_period:
558 return
558 return
559
559
560 self.sender_time = last_time
560 self.sender_time = last_time
561
561
562 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax', 'zlimits']
562 attrs = ['titles', 'zmin', 'zmax', 'tag', 'ymin', 'ymax', 'zlimits']
563 for attr in attrs:
563 for attr in attrs:
564 value = getattr(self, attr)
564 value = getattr(self, attr)
565 if value:
565 if value:
566 if isinstance(value, (numpy.float32, numpy.float64)):
566 if isinstance(value, (numpy.float32, numpy.float64)):
567 value = round(float(value), 2)
567 value = round(float(value), 2)
568 self.data.meta[attr] = value
568 self.data.meta[attr] = value
569 if self.colormap == 'jet':
569 if self.colormap == 'jet':
570 self.data.meta['colormap'] = 'Jet'
570 self.data.meta['colormap'] = 'Jet'
571 elif 'RdBu' in self.colormap:
571 elif 'RdBu' in self.colormap:
572 self.data.meta['colormap'] = 'RdBu'
572 self.data.meta['colormap'] = 'RdBu'
573 else:
573 else:
574 self.data.meta['colormap'] = 'Viridis'
574 self.data.meta['colormap'] = 'Viridis'
575 self.data.meta['interval'] = int(interval)
575 self.data.meta['interval'] = int(interval)
576 #print(last_time)
576 #print(last_time)
577 #print(time.time())
577 #print(time.time())
578 #exit(1)
578 #exit(1)
579 self.sender_queue.append(last_time)
579 self.sender_queue.append(last_time)
580
580
581 while True:
581 while True:
582 try:
582 try:
583 tm = self.sender_queue.popleft()
583 tm = self.sender_queue.popleft()
584 except IndexError:
584 except IndexError:
585 break
585 break
586 msg = self.data.jsonify(tm, self.save_code, self.plot_type)
586 msg = self.data.jsonify(tm, self.save_code, self.plot_type)
587 self.socket.send_string(msg)
587 self.socket.send_string(msg)
588 socks = dict(self.poll.poll(2000))
588 socks = dict(self.poll.poll(2000))
589 if socks.get(self.socket) == zmq.POLLIN:
589 if socks.get(self.socket) == zmq.POLLIN:
590 reply = self.socket.recv_string()
590 reply = self.socket.recv_string()
591 if reply == 'ok':
591 if reply == 'ok':
592 log.log("Response from server ok", self.name)
592 log.log("Response from server ok", self.name)
593 time.sleep(0.1)
593 time.sleep(0.1)
594 continue
594 continue
595 else:
595 else:
596 log.warning(
596 log.warning(
597 "Malformed reply from server: {}".format(reply), self.name)
597 "Malformed reply from server: {}".format(reply), self.name)
598 else:
598 else:
599 log.warning(
599 log.warning(
600 "No response from server, retrying...", self.name)
600 "No response from server, retrying...", self.name)
601 self.sender_queue.appendleft(tm)
601 self.sender_queue.appendleft(tm)
602 self.socket.setsockopt(zmq.LINGER, 0)
602 self.socket.setsockopt(zmq.LINGER, 0)
603 self.socket.close()
603 self.socket.close()
604 self.poll.unregister(self.socket)
604 self.poll.unregister(self.socket)
605 self.socket = self.context.socket(zmq.REQ)
605 self.socket = self.context.socket(zmq.REQ)
606 self.socket.connect(self.server)
606 self.socket.connect(self.server)
607 self.poll.register(self.socket, zmq.POLLIN)
607 self.poll.register(self.socket, zmq.POLLIN)
608 break
608 break
609
609
610 def setup(self):
610 def setup(self):
611 '''
611 '''
612 This method should be implemented in the child class, the following
612 This method should be implemented in the child class, the following
613 attributes should be set:
613 attributes should be set:
614
614
615 self.nrows: number of rows
615 self.nrows: number of rows
616 self.ncols: number of cols
616 self.ncols: number of cols
617 self.nplots: number of plots (channels or pairs)
617 self.nplots: number of plots (channels or pairs)
618 self.ylabel: label for Y axes
618 self.ylabel: label for Y axes
619 self.titles: list of axes title
619 self.titles: list of axes title
620
620
621 '''
621 '''
622 raise NotImplementedError
622 raise NotImplementedError
623
623
624 def plot(self):
624 def plot(self):
625 '''
625 '''
626 Must be defined in the child class, the actual plotting method
626 Must be defined in the child class, the actual plotting method
627 '''
627 '''
628 raise NotImplementedError
628 raise NotImplementedError
629
629
630 def update(self, dataOut):
630 def update(self, dataOut):
631 '''
631 '''
632 Must be defined in the child class, update self.data with new data
632 Must be defined in the child class, update self.data with new data
633 '''
633 '''
634
634
635 data = {
635 data = {
636 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
636 self.CODE: getattr(dataOut, 'data_{}'.format(self.CODE))
637 }
637 }
638 meta = {}
638 meta = {}
639
639
640 return data, meta
640 return data, meta
641
641
642 def run(self, dataOut, **kwargs):
642 def run(self, dataOut, **kwargs):
643 '''
643 '''
644 Main plotting routine
644 Main plotting routine
645 '''
645 '''
646
646
647 if self.isConfig is False:
647 if self.isConfig is False:
648 self.__setup(**kwargs)
648 self.__setup(**kwargs)
649
649
650 if self.localtime:
650 if self.localtime:
651 self.getDateTime = datetime.datetime.fromtimestamp
651 self.getDateTime = datetime.datetime.fromtimestamp
652 else:
652 else:
653 self.getDateTime = datetime.datetime.utcfromtimestamp
653 self.getDateTime = datetime.datetime.utcfromtimestamp
654
654
655 self.data.setup()
655 self.data.setup()
656 self.isConfig = True
656 self.isConfig = True
657 if self.server:
657 if self.server:
658 self.context = zmq.Context()
658 self.context = zmq.Context()
659 self.socket = self.context.socket(zmq.REQ)
659 self.socket = self.context.socket(zmq.REQ)
660 self.socket.connect(self.server)
660 self.socket.connect(self.server)
661 self.poll = zmq.Poller()
661 self.poll = zmq.Poller()
662 self.poll.register(self.socket, zmq.POLLIN)
662 self.poll.register(self.socket, zmq.POLLIN)
663
663
664 tm = getattr(dataOut, self.attr_time)
664 tm = getattr(dataOut, self.attr_time)
665 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
665 if self.data and 'time' in self.xaxis and (tm - self.tmin) >= self.xrange*60*60:
666 self.save_time = tm
666 self.save_time = tm
667 self.tmin += self.xrange*60*60 #Modified by R. Flores
667 self.tmin += self.xrange*60*60 #Modified by R. Flores
668 #self.tmin += 24*60*60 #Modified by R. Flores
668 #self.tmin += 24*60*60 #Modified by R. Flores
669 self.__plot()
669 self.__plot()
670 self.data.setup()
670 self.data.setup()
671 self.clear_figures()
671 self.clear_figures()
672
672
673 self.__update(dataOut, tm)
673 self.__update(dataOut, tm)
674
674
675 if self.isPlotConfig is False:
675 if self.isPlotConfig is False:
676 self.__setup_plot()
676 self.__setup_plot()
677 self.isPlotConfig = True
677 self.isPlotConfig = True
678 if self.xaxis == 'time':
678 if self.xaxis == 'time':
679 dt = self.getDateTime(tm)
679 dt = self.getDateTime(tm)
680
680
681 if self.xmin is None:
681 if self.xmin is None:
682 self.tmin = tm
682 self.tmin = tm
683 self.xmin = dt.hour
683 self.xmin = dt.hour
684 minutes = (self.xmin-int(self.xmin)) * 60
684 minutes = (self.xmin-int(self.xmin)) * 60
685 seconds = (minutes - int(minutes)) * 60
685 seconds = (minutes - int(minutes)) * 60
686 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
686 self.tmin = (dt.replace(hour=int(self.xmin), minute=int(minutes), second=int(seconds)) -
687 datetime.datetime(1970, 1, 1)).total_seconds()
687 datetime.datetime(1970, 1, 1)).total_seconds()
688 if self.localtime:
688 if self.localtime:
689 self.tmin += time.timezone
689 self.tmin += time.timezone
690
690
691 if self.xmin is not None and self.xmax is not None:
691 if self.xmin is not None and self.xmax is not None:
692 self.xrange = self.xmax - self.xmin
692 self.xrange = self.xmax - self.xmin
693
693
694 if self.throttle == 0:
694 if self.throttle == 0:
695 self.__plot()
695 self.__plot()
696 else:
696 else:
697 self.__throttle_plot(self.__plot)#, coerce=coerce)
697 self.__throttle_plot(self.__plot)#, coerce=coerce)
698
698
699 def close(self):
699 def close(self):
700
700
701 if self.data and not self.data.flagNoData:
701 if self.data and not self.data.flagNoData:
702 self.save_time = 0
702 self.save_time = 0
703 self.__plot()
703 self.__plot()
704 if self.data and not self.data.flagNoData and self.pause:
704 if self.data and not self.data.flagNoData and self.pause:
705 figpause(10)
705 figpause(10)
General Comments 0
You need to be logged in to leave comments. Login now