##// END OF EJS Templates
Fix dynamic 'ystep' for all plots
George Yong -
r1203:2b0eb59f54ea
parent child
Show More
@@ -1,801 +1,803
1
1
2 import os
2 import os
3 import sys
3 import sys
4 import zmq
4 import zmq
5 import time
5 import time
6 import datetime
6 import datetime
7 from functools import wraps
7 from functools import wraps
8 import numpy
8 import numpy
9 import matplotlib
9 import matplotlib
10
10
11 if 'BACKEND' in os.environ:
11 if 'BACKEND' in os.environ:
12 matplotlib.use(os.environ['BACKEND'])
12 matplotlib.use(os.environ['BACKEND'])
13 elif 'linux' in sys.platform:
13 elif 'linux' in sys.platform:
14 matplotlib.use("TkAgg")
14 matplotlib.use("TkAgg")
15 elif 'darwin' in sys.platform:
15 elif 'darwin' in sys.platform:
16 matplotlib.use('TkAgg')
16 matplotlib.use('TkAgg')
17 else:
17 else:
18 from schainpy.utils import log
18 from schainpy.utils import log
19 log.warning('Using default Backend="Agg"', 'INFO')
19 log.warning('Using default Backend="Agg"', 'INFO')
20 matplotlib.use('Agg')
20 matplotlib.use('Agg')
21
21
22 import matplotlib.pyplot as plt
22 import matplotlib.pyplot as plt
23 from matplotlib.patches import Polygon
23 from matplotlib.patches import Polygon
24 from mpl_toolkits.axes_grid1 import make_axes_locatable
24 from mpl_toolkits.axes_grid1 import make_axes_locatable
25 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
25 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
26
26
27 from schainpy.model.data.jrodata import PlotterData
27 from schainpy.model.data.jrodata import PlotterData
28 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
28 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
29 from schainpy.utils import log
29 from schainpy.utils import log
30
30
31 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
31 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
32 blu_values = matplotlib.pyplot.get_cmap(
32 blu_values = matplotlib.pyplot.get_cmap(
33 'seismic_r', 20)(numpy.arange(20))[10:15]
33 'seismic_r', 20)(numpy.arange(20))[10:15]
34 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
34 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
35 'jro', numpy.vstack((blu_values, jet_values)))
35 'jro', numpy.vstack((blu_values, jet_values)))
36 matplotlib.pyplot.register_cmap(cmap=ncmap)
36 matplotlib.pyplot.register_cmap(cmap=ncmap)
37
37
38 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
38 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
39 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
39 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
40
40
41 EARTH_RADIUS = 6.3710e3
41 EARTH_RADIUS = 6.3710e3
42
42
43
43
44 def ll2xy(lat1, lon1, lat2, lon2):
44 def ll2xy(lat1, lon1, lat2, lon2):
45
45
46 p = 0.017453292519943295
46 p = 0.017453292519943295
47 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
47 a = 0.5 - numpy.cos((lat2 - lat1) * p)/2 + numpy.cos(lat1 * p) * \
48 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
48 numpy.cos(lat2 * p) * (1 - numpy.cos((lon2 - lon1) * p)) / 2
49 r = 12742 * numpy.arcsin(numpy.sqrt(a))
49 r = 12742 * numpy.arcsin(numpy.sqrt(a))
50 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
50 theta = numpy.arctan2(numpy.sin((lon2-lon1)*p)*numpy.cos(lat2*p), numpy.cos(lat1*p)
51 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
51 * numpy.sin(lat2*p)-numpy.sin(lat1*p)*numpy.cos(lat2*p)*numpy.cos((lon2-lon1)*p))
52 theta = -theta + numpy.pi/2
52 theta = -theta + numpy.pi/2
53 return r*numpy.cos(theta), r*numpy.sin(theta)
53 return r*numpy.cos(theta), r*numpy.sin(theta)
54
54
55
55
56 def km2deg(km):
56 def km2deg(km):
57 '''
57 '''
58 Convert distance in km to degrees
58 Convert distance in km to degrees
59 '''
59 '''
60
60
61 return numpy.rad2deg(km/EARTH_RADIUS)
61 return numpy.rad2deg(km/EARTH_RADIUS)
62
62
63
63
64 def figpause(interval):
64 def figpause(interval):
65 backend = plt.rcParams['backend']
65 backend = plt.rcParams['backend']
66 if backend in matplotlib.rcsetup.interactive_bk:
66 if backend in matplotlib.rcsetup.interactive_bk:
67 figManager = matplotlib._pylab_helpers.Gcf.get_active()
67 figManager = matplotlib._pylab_helpers.Gcf.get_active()
68 if figManager is not None:
68 if figManager is not None:
69 canvas = figManager.canvas
69 canvas = figManager.canvas
70 if canvas.figure.stale:
70 if canvas.figure.stale:
71 canvas.draw()
71 canvas.draw()
72 try:
72 try:
73 canvas.start_event_loop(interval)
73 canvas.start_event_loop(interval)
74 except:
74 except:
75 pass
75 pass
76 return
76 return
77
77
78
78
79 def popup(message):
79 def popup(message):
80 '''
80 '''
81 '''
81 '''
82
82
83 fig = plt.figure(figsize=(12, 8), facecolor='r')
83 fig = plt.figure(figsize=(12, 8), facecolor='r')
84 text = '\n'.join([s.strip() for s in message.split(':')])
84 text = '\n'.join([s.strip() for s in message.split(':')])
85 fig.text(0.01, 0.5, text, ha='left', va='center',
85 fig.text(0.01, 0.5, text, ha='left', va='center',
86 size='20', weight='heavy', color='w')
86 size='20', weight='heavy', color='w')
87 fig.show()
87 fig.show()
88 figpause(1000)
88 figpause(1000)
89
89
90
90
91 class Throttle(object):
91 class Throttle(object):
92 '''
92 '''
93 Decorator that prevents a function from being called more than once every
93 Decorator that prevents a function from being called more than once every
94 time period.
94 time period.
95 To create a function that cannot be called more than once a minute, but
95 To create a function that cannot be called more than once a minute, but
96 will sleep until it can be called:
96 will sleep until it can be called:
97 @Throttle(minutes=1)
97 @Throttle(minutes=1)
98 def foo():
98 def foo():
99 pass
99 pass
100
100
101 for i in range(10):
101 for i in range(10):
102 foo()
102 foo()
103 print "This function has run %s times." % i
103 print "This function has run %s times." % i
104 '''
104 '''
105
105
106 def __init__(self, seconds=0, minutes=0, hours=0):
106 def __init__(self, seconds=0, minutes=0, hours=0):
107 self.throttle_period = datetime.timedelta(
107 self.throttle_period = datetime.timedelta(
108 seconds=seconds, minutes=minutes, hours=hours
108 seconds=seconds, minutes=minutes, hours=hours
109 )
109 )
110
110
111 self.time_of_last_call = datetime.datetime.min
111 self.time_of_last_call = datetime.datetime.min
112
112
113 def __call__(self, fn):
113 def __call__(self, fn):
114 @wraps(fn)
114 @wraps(fn)
115 def wrapper(*args, **kwargs):
115 def wrapper(*args, **kwargs):
116 coerce = kwargs.pop('coerce', None)
116 coerce = kwargs.pop('coerce', None)
117 if coerce:
117 if coerce:
118 self.time_of_last_call = datetime.datetime.now()
118 self.time_of_last_call = datetime.datetime.now()
119 return fn(*args, **kwargs)
119 return fn(*args, **kwargs)
120 else:
120 else:
121 now = datetime.datetime.now()
121 now = datetime.datetime.now()
122 time_since_last_call = now - self.time_of_last_call
122 time_since_last_call = now - self.time_of_last_call
123 time_left = self.throttle_period - time_since_last_call
123 time_left = self.throttle_period - time_since_last_call
124
124
125 if time_left > datetime.timedelta(seconds=0):
125 if time_left > datetime.timedelta(seconds=0):
126 return
126 return
127
127
128 self.time_of_last_call = datetime.datetime.now()
128 self.time_of_last_call = datetime.datetime.now()
129 return fn(*args, **kwargs)
129 return fn(*args, **kwargs)
130
130
131 return wrapper
131 return wrapper
132
132
133 def apply_throttle(value):
133 def apply_throttle(value):
134
134
135 @Throttle(seconds=value)
135 @Throttle(seconds=value)
136 def fnThrottled(fn):
136 def fnThrottled(fn):
137 fn()
137 fn()
138
138
139 return fnThrottled
139 return fnThrottled
140
140
141 @MPDecorator
141 @MPDecorator
142 class Plotter(ProcessingUnit):
142 class Plotter(ProcessingUnit):
143 '''
143 '''
144 Proccessing unit to handle plot operations
144 Proccessing unit to handle plot operations
145 '''
145 '''
146
146
147 def __init__(self):
147 def __init__(self):
148
148
149 ProcessingUnit.__init__(self)
149 ProcessingUnit.__init__(self)
150
150
151 def setup(self, **kwargs):
151 def setup(self, **kwargs):
152
152
153 self.connections = 0
153 self.connections = 0
154 self.web_address = kwargs.get('web_server', False)
154 self.web_address = kwargs.get('web_server', False)
155 self.realtime = kwargs.get('realtime', False)
155 self.realtime = kwargs.get('realtime', False)
156 self.localtime = kwargs.get('localtime', True)
156 self.localtime = kwargs.get('localtime', True)
157 self.buffering = kwargs.get('buffering', True)
157 self.buffering = kwargs.get('buffering', True)
158 self.throttle = kwargs.get('throttle', 2)
158 self.throttle = kwargs.get('throttle', 2)
159 self.exp_code = kwargs.get('exp_code', None)
159 self.exp_code = kwargs.get('exp_code', None)
160 self.set_ready = apply_throttle(self.throttle)
160 self.set_ready = apply_throttle(self.throttle)
161 self.dates = []
161 self.dates = []
162 self.data = PlotterData(
162 self.data = PlotterData(
163 self.plots, self.throttle, self.exp_code, self.buffering)
163 self.plots, self.throttle, self.exp_code, self.buffering)
164 self.isConfig = True
164 self.isConfig = True
165
165
166 def ready(self):
166 def ready(self):
167 '''
167 '''
168 Set dataOut ready
168 Set dataOut ready
169 '''
169 '''
170
170
171 self.data.ready = True
171 self.data.ready = True
172 self.dataOut.data_plt = self.data
172 self.dataOut.data_plt = self.data
173
173
174 def run(self, realtime=True, localtime=True, buffering=True,
174 def run(self, realtime=True, localtime=True, buffering=True,
175 throttle=2, exp_code=None, web_server=None):
175 throttle=2, exp_code=None, web_server=None):
176
176
177 if not self.isConfig:
177 if not self.isConfig:
178 self.setup(realtime=realtime, localtime=localtime,
178 self.setup(realtime=realtime, localtime=localtime,
179 buffering=buffering, throttle=throttle, exp_code=exp_code,
179 buffering=buffering, throttle=throttle, exp_code=exp_code,
180 web_server=web_server)
180 web_server=web_server)
181
181
182 if self.web_address:
182 if self.web_address:
183 log.success(
183 log.success(
184 'Sending to web: {}'.format(self.web_address),
184 'Sending to web: {}'.format(self.web_address),
185 self.name
185 self.name
186 )
186 )
187 self.context = zmq.Context()
187 self.context = zmq.Context()
188 self.sender_web = self.context.socket(zmq.REQ)
188 self.sender_web = self.context.socket(zmq.REQ)
189 self.sender_web.connect(self.web_address)
189 self.sender_web.connect(self.web_address)
190 self.poll = zmq.Poller()
190 self.poll = zmq.Poller()
191 self.poll.register(self.sender_web, zmq.POLLIN)
191 self.poll.register(self.sender_web, zmq.POLLIN)
192 time.sleep(1)
192 time.sleep(1)
193
193
194 # t = Thread(target=self.event_monitor, args=(monitor,))
194 # t = Thread(target=self.event_monitor, args=(monitor,))
195 # t.start()
195 # t.start()
196
196
197 self.dataOut = self.dataIn
197 self.dataOut = self.dataIn
198 self.data.ready = False
198 self.data.ready = False
199
199
200 if self.dataOut.flagNoData:
200 if self.dataOut.flagNoData:
201 coerce = True
201 coerce = True
202 else:
202 else:
203 coerce = False
203 coerce = False
204
204
205 if self.dataOut.type == 'Parameters':
205 if self.dataOut.type == 'Parameters':
206 tm = self.dataOut.utctimeInit
206 tm = self.dataOut.utctimeInit
207 else:
207 else:
208 tm = self.dataOut.utctime
208 tm = self.dataOut.utctime
209 if self.dataOut.useLocalTime:
209 if self.dataOut.useLocalTime:
210 if not self.localtime:
210 if not self.localtime:
211 tm += time.timezone
211 tm += time.timezone
212 dt = datetime.datetime.fromtimestamp(tm).date()
212 dt = datetime.datetime.fromtimestamp(tm).date()
213 else:
213 else:
214 if self.localtime:
214 if self.localtime:
215 tm -= time.timezone
215 tm -= time.timezone
216 dt = datetime.datetime.utcfromtimestamp(tm).date()
216 dt = datetime.datetime.utcfromtimestamp(tm).date()
217 if dt not in self.dates:
217 if dt not in self.dates:
218 if self.data:
218 if self.data:
219 self.ready()
219 self.ready()
220 self.data.setup()
220 self.data.setup()
221 self.dates.append(dt)
221 self.dates.append(dt)
222
222
223 self.data.update(self.dataOut, tm)
223 self.data.update(self.dataOut, tm)
224
224
225 if False: # TODO check when publishers ends
225 if False: # TODO check when publishers ends
226 self.connections -= 1
226 self.connections -= 1
227 if self.connections == 0 and dt in self.dates:
227 if self.connections == 0 and dt in self.dates:
228 self.data.ended = True
228 self.data.ended = True
229 self.ready()
229 self.ready()
230 time.sleep(1)
230 time.sleep(1)
231 else:
231 else:
232 if self.realtime:
232 if self.realtime:
233 self.ready()
233 self.ready()
234 if self.web_address:
234 if self.web_address:
235 retries = 5
235 retries = 5
236 while True:
236 while True:
237 self.sender_web.send(self.data.jsonify())
237 self.sender_web.send(self.data.jsonify())
238 socks = dict(self.poll.poll(5000))
238 socks = dict(self.poll.poll(5000))
239 if socks.get(self.sender_web) == zmq.POLLIN:
239 if socks.get(self.sender_web) == zmq.POLLIN:
240 reply = self.sender_web.recv_string()
240 reply = self.sender_web.recv_string()
241 if reply == 'ok':
241 if reply == 'ok':
242 log.log("Response from server ok", self.name)
242 log.log("Response from server ok", self.name)
243 break
243 break
244 else:
244 else:
245 log.warning(
245 log.warning(
246 "Malformed reply from server: {}".format(reply), self.name)
246 "Malformed reply from server: {}".format(reply), self.name)
247
247
248 else:
248 else:
249 log.warning(
249 log.warning(
250 "No response from server, retrying...", self.name)
250 "No response from server, retrying...", self.name)
251 self.sender_web.setsockopt(zmq.LINGER, 0)
251 self.sender_web.setsockopt(zmq.LINGER, 0)
252 self.sender_web.close()
252 self.sender_web.close()
253 self.poll.unregister(self.sender_web)
253 self.poll.unregister(self.sender_web)
254 retries -= 1
254 retries -= 1
255 if retries == 0:
255 if retries == 0:
256 log.error(
256 log.error(
257 "Server seems to be offline, abandoning", self.name)
257 "Server seems to be offline, abandoning", self.name)
258 self.sender_web = self.context.socket(zmq.REQ)
258 self.sender_web = self.context.socket(zmq.REQ)
259 self.sender_web.connect(self.web_address)
259 self.sender_web.connect(self.web_address)
260 self.poll.register(self.sender_web, zmq.POLLIN)
260 self.poll.register(self.sender_web, zmq.POLLIN)
261 time.sleep(1)
261 time.sleep(1)
262 break
262 break
263 self.sender_web = self.context.socket(zmq.REQ)
263 self.sender_web = self.context.socket(zmq.REQ)
264 self.sender_web.connect(self.web_address)
264 self.sender_web.connect(self.web_address)
265 self.poll.register(self.sender_web, zmq.POLLIN)
265 self.poll.register(self.sender_web, zmq.POLLIN)
266 time.sleep(1)
266 time.sleep(1)
267 else:
267 else:
268 self.set_ready(self.ready, coerce=coerce)
268 self.set_ready(self.ready, coerce=coerce)
269
269
270 return
270 return
271
271
272 def close(self):
272 def close(self):
273 pass
273 pass
274
274
275
275
276 @MPDecorator
276 @MPDecorator
277 class Plot(Operation):
277 class Plot(Operation):
278 '''
278 '''
279 Base class for Schain plotting operations
279 Base class for Schain plotting operations
280 '''
280 '''
281
281
282 CODE = 'Figure'
282 CODE = 'Figure'
283 colormap = 'jro'
283 colormap = 'jro'
284 bgcolor = 'white'
284 bgcolor = 'white'
285 __missing = 1E30
285 __missing = 1E30
286
286
287 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
287 __attrs__ = ['show', 'save', 'xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax',
288 'zlimits', 'xlabel', 'ylabel', 'xaxis', 'cb_label', 'title',
288 'zlimits', 'xlabel', 'ylabel', 'xaxis', 'cb_label', 'title',
289 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
289 'colorbar', 'bgcolor', 'width', 'height', 'localtime', 'oneFigure',
290 'showprofile', 'decimation', 'pause']
290 'showprofile', 'decimation', 'pause']
291
291
292 def __init__(self):
292 def __init__(self):
293
293
294 Operation.__init__(self)
294 Operation.__init__(self)
295 self.isConfig = False
295 self.isConfig = False
296 self.isPlotConfig = False
296 self.isPlotConfig = False
297
297
298 def __fmtTime(self, x, pos):
298 def __fmtTime(self, x, pos):
299 '''
299 '''
300 '''
300 '''
301
301
302 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
302 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
303
303
304 def __setup(self, **kwargs):
304 def __setup(self, **kwargs):
305 '''
305 '''
306 Initialize variables
306 Initialize variables
307 '''
307 '''
308
308
309 self.figures = []
309 self.figures = []
310 self.axes = []
310 self.axes = []
311 self.cb_axes = []
311 self.cb_axes = []
312 self.localtime = kwargs.pop('localtime', True)
312 self.localtime = kwargs.pop('localtime', True)
313 self.show = kwargs.get('show', True)
313 self.show = kwargs.get('show', True)
314 self.save = kwargs.get('save', False)
314 self.save = kwargs.get('save', False)
315 self.ftp = kwargs.get('ftp', False)
315 self.ftp = kwargs.get('ftp', False)
316 self.colormap = kwargs.get('colormap', self.colormap)
316 self.colormap = kwargs.get('colormap', self.colormap)
317 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
317 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
318 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
318 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
319 self.colormaps = kwargs.get('colormaps', None)
319 self.colormaps = kwargs.get('colormaps', None)
320 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
320 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
321 self.showprofile = kwargs.get('showprofile', False)
321 self.showprofile = kwargs.get('showprofile', False)
322 self.title = kwargs.get('wintitle', self.CODE.upper())
322 self.title = kwargs.get('wintitle', self.CODE.upper())
323 self.cb_label = kwargs.get('cb_label', None)
323 self.cb_label = kwargs.get('cb_label', None)
324 self.cb_labels = kwargs.get('cb_labels', None)
324 self.cb_labels = kwargs.get('cb_labels', None)
325 self.labels = kwargs.get('labels', None)
325 self.labels = kwargs.get('labels', None)
326 self.xaxis = kwargs.get('xaxis', 'frequency')
326 self.xaxis = kwargs.get('xaxis', 'frequency')
327 self.zmin = kwargs.get('zmin', None)
327 self.zmin = kwargs.get('zmin', None)
328 self.zmax = kwargs.get('zmax', None)
328 self.zmax = kwargs.get('zmax', None)
329 self.zlimits = kwargs.get('zlimits', None)
329 self.zlimits = kwargs.get('zlimits', None)
330 self.xmin = kwargs.get('xmin', None)
330 self.xmin = kwargs.get('xmin', None)
331 self.xmax = kwargs.get('xmax', None)
331 self.xmax = kwargs.get('xmax', None)
332 self.xrange = kwargs.get('xrange', 12)
332 self.xrange = kwargs.get('xrange', 12)
333 self.xscale = kwargs.get('xscale', None)
333 self.xscale = kwargs.get('xscale', None)
334 self.ymin = kwargs.get('ymin', None)
334 self.ymin = kwargs.get('ymin', None)
335 self.ymax = kwargs.get('ymax', None)
335 self.ymax = kwargs.get('ymax', None)
336 self.yscale = kwargs.get('yscale', None)
336 self.yscale = kwargs.get('yscale', None)
337 self.xlabel = kwargs.get('xlabel', None)
337 self.xlabel = kwargs.get('xlabel', None)
338 self.decimation = kwargs.get('decimation', None)
338 self.decimation = kwargs.get('decimation', None)
339 self.showSNR = kwargs.get('showSNR', False)
339 self.showSNR = kwargs.get('showSNR', False)
340 self.oneFigure = kwargs.get('oneFigure', True)
340 self.oneFigure = kwargs.get('oneFigure', True)
341 self.width = kwargs.get('width', None)
341 self.width = kwargs.get('width', None)
342 self.height = kwargs.get('height', None)
342 self.height = kwargs.get('height', None)
343 self.colorbar = kwargs.get('colorbar', True)
343 self.colorbar = kwargs.get('colorbar', True)
344 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
344 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
345 self.channels = kwargs.get('channels', None)
345 self.channels = kwargs.get('channels', None)
346 self.titles = kwargs.get('titles', [])
346 self.titles = kwargs.get('titles', [])
347 self.polar = False
347 self.polar = False
348 self.type = kwargs.get('type', 'iq')
348 self.type = kwargs.get('type', 'iq')
349 self.grid = kwargs.get('grid', False)
349 self.grid = kwargs.get('grid', False)
350 self.pause = kwargs.get('pause', False)
350 self.pause = kwargs.get('pause', False)
351 self.save_labels = kwargs.get('save_labels', None)
351 self.save_labels = kwargs.get('save_labels', None)
352 self.realtime = kwargs.get('realtime', True)
352 self.realtime = kwargs.get('realtime', True)
353 self.buffering = kwargs.get('buffering', True)
353 self.buffering = kwargs.get('buffering', True)
354 self.throttle = kwargs.get('throttle', 2)
354 self.throttle = kwargs.get('throttle', 2)
355 self.exp_code = kwargs.get('exp_code', None)
355 self.exp_code = kwargs.get('exp_code', None)
356 self.__throttle_plot = apply_throttle(self.throttle)
356 self.__throttle_plot = apply_throttle(self.throttle)
357 self.data = PlotterData(
357 self.data = PlotterData(
358 self.CODE, self.throttle, self.exp_code, self.buffering)
358 self.CODE, self.throttle, self.exp_code, self.buffering)
359
359
360 def __setup_plot(self):
360 def __setup_plot(self):
361 '''
361 '''
362 Common setup for all figures, here figures and axes are created
362 Common setup for all figures, here figures and axes are created
363 '''
363 '''
364
364
365 self.setup()
365 self.setup()
366
366
367 self.time_label = 'LT' if self.localtime else 'UTC'
367 self.time_label = 'LT' if self.localtime else 'UTC'
368 if self.data.localtime:
368 if self.data.localtime:
369 self.getDateTime = datetime.datetime.fromtimestamp
369 self.getDateTime = datetime.datetime.fromtimestamp
370 else:
370 else:
371 self.getDateTime = datetime.datetime.utcfromtimestamp
371 self.getDateTime = datetime.datetime.utcfromtimestamp
372
372
373 if self.width is None:
373 if self.width is None:
374 self.width = 8
374 self.width = 8
375
375
376 self.figures = []
376 self.figures = []
377 self.axes = []
377 self.axes = []
378 self.cb_axes = []
378 self.cb_axes = []
379 self.pf_axes = []
379 self.pf_axes = []
380 self.cmaps = []
380 self.cmaps = []
381
381
382 size = '15%' if self.ncols == 1 else '30%'
382 size = '15%' if self.ncols == 1 else '30%'
383 pad = '4%' if self.ncols == 1 else '8%'
383 pad = '4%' if self.ncols == 1 else '8%'
384
384
385 if self.oneFigure:
385 if self.oneFigure:
386 if self.height is None:
386 if self.height is None:
387 self.height = 1.4 * self.nrows + 1
387 self.height = 1.4 * self.nrows + 1
388 fig = plt.figure(figsize=(self.width, self.height),
388 fig = plt.figure(figsize=(self.width, self.height),
389 edgecolor='k',
389 edgecolor='k',
390 facecolor='w')
390 facecolor='w')
391 self.figures.append(fig)
391 self.figures.append(fig)
392 for n in range(self.nplots):
392 for n in range(self.nplots):
393 ax = fig.add_subplot(self.nrows, self.ncols,
393 ax = fig.add_subplot(self.nrows, self.ncols,
394 n + 1, polar=self.polar)
394 n + 1, polar=self.polar)
395 ax.tick_params(labelsize=8)
395 ax.tick_params(labelsize=8)
396 ax.firsttime = True
396 ax.firsttime = True
397 ax.index = 0
397 ax.index = 0
398 ax.press = None
398 ax.press = None
399 self.axes.append(ax)
399 self.axes.append(ax)
400 if self.showprofile:
400 if self.showprofile:
401 cax = self.__add_axes(ax, size=size, pad=pad)
401 cax = self.__add_axes(ax, size=size, pad=pad)
402 cax.tick_params(labelsize=8)
402 cax.tick_params(labelsize=8)
403 self.pf_axes.append(cax)
403 self.pf_axes.append(cax)
404 else:
404 else:
405 if self.height is None:
405 if self.height is None:
406 self.height = 3
406 self.height = 3
407 for n in range(self.nplots):
407 for n in range(self.nplots):
408 fig = plt.figure(figsize=(self.width, self.height),
408 fig = plt.figure(figsize=(self.width, self.height),
409 edgecolor='k',
409 edgecolor='k',
410 facecolor='w')
410 facecolor='w')
411 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
411 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
412 ax.tick_params(labelsize=8)
412 ax.tick_params(labelsize=8)
413 ax.firsttime = True
413 ax.firsttime = True
414 ax.index = 0
414 ax.index = 0
415 ax.press = None
415 ax.press = None
416 self.figures.append(fig)
416 self.figures.append(fig)
417 self.axes.append(ax)
417 self.axes.append(ax)
418 if self.showprofile:
418 if self.showprofile:
419 cax = self.__add_axes(ax, size=size, pad=pad)
419 cax = self.__add_axes(ax, size=size, pad=pad)
420 cax.tick_params(labelsize=8)
420 cax.tick_params(labelsize=8)
421 self.pf_axes.append(cax)
421 self.pf_axes.append(cax)
422
422
423 for n in range(self.nrows):
423 for n in range(self.nrows):
424 if self.colormaps is not None:
424 if self.colormaps is not None:
425 cmap = plt.get_cmap(self.colormaps[n])
425 cmap = plt.get_cmap(self.colormaps[n])
426 else:
426 else:
427 cmap = plt.get_cmap(self.colormap)
427 cmap = plt.get_cmap(self.colormap)
428 cmap.set_bad(self.bgcolor, 1.)
428 cmap.set_bad(self.bgcolor, 1.)
429 self.cmaps.append(cmap)
429 self.cmaps.append(cmap)
430
430
431 for fig in self.figures:
431 for fig in self.figures:
432 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
432 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
433 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
433 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
434 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
434 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
435 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
435 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
436 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
436 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
437 if self.show:
437 if self.show:
438 fig.show()
438 fig.show()
439
439
440 def OnKeyPress(self, event):
440 def OnKeyPress(self, event):
441 '''
441 '''
442 Event for pressing keys (up, down) change colormap
442 Event for pressing keys (up, down) change colormap
443 '''
443 '''
444 ax = event.inaxes
444 ax = event.inaxes
445 if ax in self.axes:
445 if ax in self.axes:
446 if event.key == 'down':
446 if event.key == 'down':
447 ax.index += 1
447 ax.index += 1
448 elif event.key == 'up':
448 elif event.key == 'up':
449 ax.index -= 1
449 ax.index -= 1
450 if ax.index < 0:
450 if ax.index < 0:
451 ax.index = len(CMAPS) - 1
451 ax.index = len(CMAPS) - 1
452 elif ax.index == len(CMAPS):
452 elif ax.index == len(CMAPS):
453 ax.index = 0
453 ax.index = 0
454 cmap = CMAPS[ax.index]
454 cmap = CMAPS[ax.index]
455 ax.cbar.set_cmap(cmap)
455 ax.cbar.set_cmap(cmap)
456 ax.cbar.draw_all()
456 ax.cbar.draw_all()
457 ax.plt.set_cmap(cmap)
457 ax.plt.set_cmap(cmap)
458 ax.cbar.patch.figure.canvas.draw()
458 ax.cbar.patch.figure.canvas.draw()
459 self.colormap = cmap.name
459 self.colormap = cmap.name
460
460
461 def OnBtnScroll(self, event):
461 def OnBtnScroll(self, event):
462 '''
462 '''
463 Event for scrolling, scale figure
463 Event for scrolling, scale figure
464 '''
464 '''
465 cb_ax = event.inaxes
465 cb_ax = event.inaxes
466 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
466 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
467 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
467 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
468 pt = ax.cbar.ax.bbox.get_points()[:, 1]
468 pt = ax.cbar.ax.bbox.get_points()[:, 1]
469 nrm = ax.cbar.norm
469 nrm = ax.cbar.norm
470 vmin, vmax, p0, p1, pS = (
470 vmin, vmax, p0, p1, pS = (
471 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
471 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
472 scale = 2 if event.step == 1 else 0.5
472 scale = 2 if event.step == 1 else 0.5
473 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
473 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
474 ax.cbar.norm.vmin = point - scale * (point - vmin)
474 ax.cbar.norm.vmin = point - scale * (point - vmin)
475 ax.cbar.norm.vmax = point - scale * (point - vmax)
475 ax.cbar.norm.vmax = point - scale * (point - vmax)
476 ax.plt.set_norm(ax.cbar.norm)
476 ax.plt.set_norm(ax.cbar.norm)
477 ax.cbar.draw_all()
477 ax.cbar.draw_all()
478 ax.cbar.patch.figure.canvas.draw()
478 ax.cbar.patch.figure.canvas.draw()
479
479
480 def onBtnPress(self, event):
480 def onBtnPress(self, event):
481 '''
481 '''
482 Event for mouse button press
482 Event for mouse button press
483 '''
483 '''
484 cb_ax = event.inaxes
484 cb_ax = event.inaxes
485 if cb_ax is None:
485 if cb_ax is None:
486 return
486 return
487
487
488 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
488 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
489 cb_ax.press = event.x, event.y
489 cb_ax.press = event.x, event.y
490 else:
490 else:
491 cb_ax.press = None
491 cb_ax.press = None
492
492
493 def onMotion(self, event):
493 def onMotion(self, event):
494 '''
494 '''
495 Event for move inside colorbar
495 Event for move inside colorbar
496 '''
496 '''
497 cb_ax = event.inaxes
497 cb_ax = event.inaxes
498 if cb_ax is None:
498 if cb_ax is None:
499 return
499 return
500 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
500 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
501 return
501 return
502 if cb_ax.press is None:
502 if cb_ax.press is None:
503 return
503 return
504
504
505 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
505 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
506 xprev, yprev = cb_ax.press
506 xprev, yprev = cb_ax.press
507 dx = event.x - xprev
507 dx = event.x - xprev
508 dy = event.y - yprev
508 dy = event.y - yprev
509 cb_ax.press = event.x, event.y
509 cb_ax.press = event.x, event.y
510 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
510 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
511 perc = 0.03
511 perc = 0.03
512
512
513 if event.button == 1:
513 if event.button == 1:
514 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
514 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
515 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
515 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
516 elif event.button == 3:
516 elif event.button == 3:
517 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
517 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
518 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
518 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
519
519
520 ax.cbar.draw_all()
520 ax.cbar.draw_all()
521 ax.plt.set_norm(ax.cbar.norm)
521 ax.plt.set_norm(ax.cbar.norm)
522 ax.cbar.patch.figure.canvas.draw()
522 ax.cbar.patch.figure.canvas.draw()
523
523
524 def onBtnRelease(self, event):
524 def onBtnRelease(self, event):
525 '''
525 '''
526 Event for mouse button release
526 Event for mouse button release
527 '''
527 '''
528 cb_ax = event.inaxes
528 cb_ax = event.inaxes
529 if cb_ax is not None:
529 if cb_ax is not None:
530 cb_ax.press = None
530 cb_ax.press = None
531
531
532 def __add_axes(self, ax, size='30%', pad='8%'):
532 def __add_axes(self, ax, size='30%', pad='8%'):
533 '''
533 '''
534 Add new axes to the given figure
534 Add new axes to the given figure
535 '''
535 '''
536 divider = make_axes_locatable(ax)
536 divider = make_axes_locatable(ax)
537 nax = divider.new_horizontal(size=size, pad=pad)
537 nax = divider.new_horizontal(size=size, pad=pad)
538 ax.figure.add_axes(nax)
538 ax.figure.add_axes(nax)
539 return nax
539 return nax
540
540
541 def setup(self):
541 def setup(self):
542 '''
542 '''
543 This method should be implemented in the child class, the following
543 This method should be implemented in the child class, the following
544 attributes should be set:
544 attributes should be set:
545
545
546 self.nrows: number of rows
546 self.nrows: number of rows
547 self.ncols: number of cols
547 self.ncols: number of cols
548 self.nplots: number of plots (channels or pairs)
548 self.nplots: number of plots (channels or pairs)
549 self.ylabel: label for Y axes
549 self.ylabel: label for Y axes
550 self.titles: list of axes title
550 self.titles: list of axes title
551
551
552 '''
552 '''
553 raise NotImplementedError
553 raise NotImplementedError
554
554
555 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
555 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
556 '''
556 '''
557 Create a masked array for missing data
557 Create a masked array for missing data
558 '''
558 '''
559 if x_buffer.shape[0] < 2:
559 if x_buffer.shape[0] < 2:
560 return x_buffer, y_buffer, z_buffer
560 return x_buffer, y_buffer, z_buffer
561
561
562 deltas = x_buffer[1:] - x_buffer[0:-1]
562 deltas = x_buffer[1:] - x_buffer[0:-1]
563 x_median = numpy.median(deltas)
563 x_median = numpy.median(deltas)
564
564
565 index = numpy.where(deltas > 5 * x_median)
565 index = numpy.where(deltas > 5 * x_median)
566
566
567 if len(index[0]) != 0:
567 if len(index[0]) != 0:
568 z_buffer[::, index[0], ::] = self.__missing
568 z_buffer[::, index[0], ::] = self.__missing
569 z_buffer = numpy.ma.masked_inside(z_buffer,
569 z_buffer = numpy.ma.masked_inside(z_buffer,
570 0.99 * self.__missing,
570 0.99 * self.__missing,
571 1.01 * self.__missing)
571 1.01 * self.__missing)
572
572
573 return x_buffer, y_buffer, z_buffer
573 return x_buffer, y_buffer, z_buffer
574
574
575 def decimate(self):
575 def decimate(self):
576
576
577 # dx = int(len(self.x)/self.__MAXNUMX) + 1
577 # dx = int(len(self.x)/self.__MAXNUMX) + 1
578 dy = int(len(self.y) / self.decimation) + 1
578 dy = int(len(self.y) / self.decimation) + 1
579
579
580 # x = self.x[::dx]
580 # x = self.x[::dx]
581 x = self.x
581 x = self.x
582 y = self.y[::dy]
582 y = self.y[::dy]
583 z = self.z[::, ::, ::dy]
583 z = self.z[::, ::, ::dy]
584
584
585 return x, y, z
585 return x, y, z
586
586
587 def format(self):
587 def format(self):
588 '''
588 '''
589 Set min and max values, labels, ticks and titles
589 Set min and max values, labels, ticks and titles
590 '''
590 '''
591
591
592 if self.xmin is None:
592 if self.xmin is None:
593 xmin = self.data.min_time
593 xmin = self.data.min_time
594 else:
594 else:
595 if self.xaxis is 'time':
595 if self.xaxis is 'time':
596 dt = self.getDateTime(self.data.min_time)
596 dt = self.getDateTime(self.data.min_time)
597 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
597 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
598 datetime.datetime(1970, 1, 1)).total_seconds()
598 datetime.datetime(1970, 1, 1)).total_seconds()
599 if self.data.localtime:
599 if self.data.localtime:
600 xmin += time.timezone
600 xmin += time.timezone
601 else:
601 else:
602 xmin = self.xmin
602 xmin = self.xmin
603
603
604 if self.xmax is None:
604 if self.xmax is None:
605 xmax = xmin + self.xrange * 60 * 60
605 xmax = xmin + self.xrange * 60 * 60
606 else:
606 else:
607 if self.xaxis is 'time':
607 if self.xaxis is 'time':
608 dt = self.getDateTime(self.data.max_time)
608 dt = self.getDateTime(self.data.max_time)
609 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
609 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
610 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
610 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
611 if self.data.localtime:
611 if self.data.localtime:
612 xmax += time.timezone
612 xmax += time.timezone
613 else:
613 else:
614 xmax = self.xmax
614 xmax = self.xmax
615
615
616 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
616 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
617 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
617 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
618 Y = numpy.array([1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000])
618 Y = numpy.array([1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000])
619 #i = 1 if numpy.where(
619 #i = 1 if numpy.where(
620 # abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
620 # abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
621 #ystep = Y[i] / 10.
621 #ystep = Y[i] / 10.
622 ystep = round(ymax,-1)//5
622 dig = int(numpy.log10(ymax))
623 ystep = ((ymax + (10**(dig)))//10**(dig))*(10**(dig))
624 ystep = ystep//10
623 if self.xaxis is not 'time':
625 if self.xaxis is not 'time':
624 X = numpy.array([0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100,
626 X = numpy.array([0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100,
625 200, 500, 1000, 2000, 5000, 10000, 20000, 50000])/2.
627 200, 500, 1000, 2000, 5000, 10000, 20000, 50000])/2.
626
628
627 i = 1 if numpy.where(
629 i = 1 if numpy.where(
628 abs(xmax-xmin) <= X)[0][0] < 0 else numpy.where(abs(xmax-xmin) <= X)[0][0]
630 abs(xmax-xmin) <= X)[0][0] < 0 else numpy.where(abs(xmax-xmin) <= X)[0][0]
629 xstep = X[i] / 5.
631 xstep = X[i] / 5.
630
632
631 for n, ax in enumerate(self.axes):
633 for n, ax in enumerate(self.axes):
632 if ax.firsttime:
634 if ax.firsttime:
633 ax.set_facecolor(self.bgcolor)
635 ax.set_facecolor(self.bgcolor)
634 ax.yaxis.set_major_locator(MultipleLocator(ystep))
636 ax.yaxis.set_major_locator(MultipleLocator(ystep))
635 if self.xscale:
637 if self.xscale:
636 ax.xaxis.set_major_formatter(FuncFormatter(
638 ax.xaxis.set_major_formatter(FuncFormatter(
637 lambda x, pos: '{0:g}'.format(x*self.xscale)))
639 lambda x, pos: '{0:g}'.format(x*self.xscale)))
638 if self.xscale:
640 if self.xscale:
639 ax.yaxis.set_major_formatter(FuncFormatter(
641 ax.yaxis.set_major_formatter(FuncFormatter(
640 lambda x, pos: '{0:g}'.format(x*self.yscale)))
642 lambda x, pos: '{0:g}'.format(x*self.yscale)))
641 if self.xaxis is 'time':
643 if self.xaxis is 'time':
642 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
644 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
643 ax.xaxis.set_major_locator(LinearLocator(9))
645 ax.xaxis.set_major_locator(LinearLocator(9))
644 else:
646 else:
645 ax.xaxis.set_major_locator(MultipleLocator(xstep))
647 ax.xaxis.set_major_locator(MultipleLocator(xstep))
646 if self.xlabel is not None:
648 if self.xlabel is not None:
647 ax.set_xlabel(self.xlabel)
649 ax.set_xlabel(self.xlabel)
648 ax.set_ylabel(self.ylabel)
650 ax.set_ylabel(self.ylabel)
649 ax.firsttime = False
651 ax.firsttime = False
650 if self.showprofile:
652 if self.showprofile:
651 self.pf_axes[n].set_ylim(ymin, ymax)
653 self.pf_axes[n].set_ylim(ymin, ymax)
652 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
654 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
653 self.pf_axes[n].set_xlabel('dB')
655 self.pf_axes[n].set_xlabel('dB')
654 self.pf_axes[n].grid(b=True, axis='x')
656 self.pf_axes[n].grid(b=True, axis='x')
655 [tick.set_visible(False)
657 [tick.set_visible(False)
656 for tick in self.pf_axes[n].get_yticklabels()]
658 for tick in self.pf_axes[n].get_yticklabels()]
657 if self.colorbar:
659 if self.colorbar:
658 ax.cbar = plt.colorbar(
660 ax.cbar = plt.colorbar(
659 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
661 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
660 ax.cbar.ax.tick_params(labelsize=8)
662 ax.cbar.ax.tick_params(labelsize=8)
661 ax.cbar.ax.press = None
663 ax.cbar.ax.press = None
662 if self.cb_label:
664 if self.cb_label:
663 ax.cbar.set_label(self.cb_label, size=8)
665 ax.cbar.set_label(self.cb_label, size=8)
664 elif self.cb_labels:
666 elif self.cb_labels:
665 ax.cbar.set_label(self.cb_labels[n], size=8)
667 ax.cbar.set_label(self.cb_labels[n], size=8)
666 else:
668 else:
667 ax.cbar = None
669 ax.cbar = None
668 if self.grid:
670 if self.grid:
669 ax.grid(True)
671 ax.grid(True)
670
672
671 if not self.polar:
673 if not self.polar:
672 ax.set_xlim(xmin, xmax)
674 ax.set_xlim(xmin, xmax)
673 ax.set_ylim(ymin, ymax)
675 ax.set_ylim(ymin, ymax)
674 ax.set_title('{} {} {}'.format(
676 ax.set_title('{} {} {}'.format(
675 self.titles[n],
677 self.titles[n],
676 self.getDateTime(self.data.max_time).strftime(
678 self.getDateTime(self.data.max_time).strftime(
677 '%H:%M:%S'),
679 '%H:%M:%S'),
678 self.time_label),
680 self.time_label),
679 size=8)
681 size=8)
680 else:
682 else:
681 ax.set_title('{}'.format(self.titles[n]), size=8)
683 ax.set_title('{}'.format(self.titles[n]), size=8)
682 ax.set_ylim(0, 90)
684 ax.set_ylim(0, 90)
683 ax.set_yticks(numpy.arange(0, 90, 20))
685 ax.set_yticks(numpy.arange(0, 90, 20))
684 ax.yaxis.labelpad = 40
686 ax.yaxis.labelpad = 40
685
687
686 def clear_figures(self):
688 def clear_figures(self):
687 '''
689 '''
688 Reset axes for redraw plots
690 Reset axes for redraw plots
689 '''
691 '''
690
692
691 for ax in self.axes:
693 for ax in self.axes:
692 ax.clear()
694 ax.clear()
693 ax.firsttime = True
695 ax.firsttime = True
694 if ax.cbar:
696 if ax.cbar:
695 ax.cbar.remove()
697 ax.cbar.remove()
696
698
697 def __plot(self):
699 def __plot(self):
698 '''
700 '''
699 Main function to plot, format and save figures
701 Main function to plot, format and save figures
700 '''
702 '''
701
703
702 #try:
704 #try:
703 self.plot()
705 self.plot()
704 self.format()
706 self.format()
705 #except Exception as e:
707 #except Exception as e:
706 # log.warning('{} Plot could not be updated... check data'.format(
708 # log.warning('{} Plot could not be updated... check data'.format(
707 # self.CODE), self.name)
709 # self.CODE), self.name)
708 # log.error(str(e), '')
710 # log.error(str(e), '')
709 # return
711 # return
710
712
711 for n, fig in enumerate(self.figures):
713 for n, fig in enumerate(self.figures):
712 if self.nrows == 0 or self.nplots == 0:
714 if self.nrows == 0 or self.nplots == 0:
713 log.warning('No data', self.name)
715 log.warning('No data', self.name)
714 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
716 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
715 fig.canvas.manager.set_window_title(self.CODE)
717 fig.canvas.manager.set_window_title(self.CODE)
716 continue
718 continue
717
719
718 fig.tight_layout()
720 fig.tight_layout()
719 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
721 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
720 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
722 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
721 fig.canvas.draw()
723 fig.canvas.draw()
722
724
723 if self.save:
725 if self.save:
724
726
725 if self.save_labels:
727 if self.save_labels:
726 labels = self.save_labels
728 labels = self.save_labels
727 else:
729 else:
728 labels = list(range(self.nrows))
730 labels = list(range(self.nrows))
729
731
730 if self.oneFigure:
732 if self.oneFigure:
731 label = ''
733 label = ''
732 else:
734 else:
733 label = '-{}'.format(labels[n])
735 label = '-{}'.format(labels[n])
734 figname = os.path.join(
736 figname = os.path.join(
735 self.save,
737 self.save,
736 self.CODE,
738 self.CODE,
737 '{}{}_{}.png'.format(
739 '{}{}_{}.png'.format(
738 self.CODE,
740 self.CODE,
739 label,
741 label,
740 self.getDateTime(self.data.max_time).strftime(
742 self.getDateTime(self.data.max_time).strftime(
741 '%Y%m%d_%H%M%S'),
743 '%Y%m%d_%H%M%S'),
742 )
744 )
743 )
745 )
744 log.log('Saving figure: {}'.format(figname), self.name)
746 log.log('Saving figure: {}'.format(figname), self.name)
745 if not os.path.isdir(os.path.dirname(figname)):
747 if not os.path.isdir(os.path.dirname(figname)):
746 os.makedirs(os.path.dirname(figname))
748 os.makedirs(os.path.dirname(figname))
747 fig.savefig(figname)
749 fig.savefig(figname)
748
750
749 def plot(self):
751 def plot(self):
750 '''
752 '''
751 Must be defined in the child class
753 Must be defined in the child class
752 '''
754 '''
753 raise NotImplementedError
755 raise NotImplementedError
754
756
755 def run(self, dataOut, **kwargs):
757 def run(self, dataOut, **kwargs):
756
758
757 if dataOut.error:
759 if dataOut.error:
758 coerce = True
760 coerce = True
759 else:
761 else:
760 coerce = False
762 coerce = False
761
763
762 if self.isConfig is False:
764 if self.isConfig is False:
763 self.__setup(**kwargs)
765 self.__setup(**kwargs)
764 self.data.setup()
766 self.data.setup()
765 self.isConfig = True
767 self.isConfig = True
766
768
767 if dataOut.type == 'Parameters':
769 if dataOut.type == 'Parameters':
768 tm = dataOut.utctimeInit
770 tm = dataOut.utctimeInit
769 else:
771 else:
770 tm = dataOut.utctime
772 tm = dataOut.utctime
771
773
772 if dataOut.useLocalTime:
774 if dataOut.useLocalTime:
773 if not self.localtime:
775 if not self.localtime:
774 tm += time.timezone
776 tm += time.timezone
775 else:
777 else:
776 if self.localtime:
778 if self.localtime:
777 tm -= time.timezone
779 tm -= time.timezone
778
780
779 if self.data and (tm - self.data.min_time) >= self.xrange*60*60:
781 if self.data and (tm - self.data.min_time) >= self.xrange*60*60:
780 self.__plot()
782 self.__plot()
781 self.data.setup()
783 self.data.setup()
782 self.clear_figures()
784 self.clear_figures()
783
785
784 self.data.update(dataOut, tm)
786 self.data.update(dataOut, tm)
785
787
786 if self.isPlotConfig is False:
788 if self.isPlotConfig is False:
787 self.__setup_plot()
789 self.__setup_plot()
788 self.isPlotConfig = True
790 self.isPlotConfig = True
789
791
790 if self.realtime:
792 if self.realtime:
791 self.__plot()
793 self.__plot()
792 else:
794 else:
793 self.__throttle_plot(self.__plot, coerce=coerce)
795 self.__throttle_plot(self.__plot, coerce=coerce)
794
796
795 figpause(0.001)
797 figpause(0.001)
796
798
797 def close(self):
799 def close(self):
798
800
799 if self.data and self.pause:
801 if self.data and self.pause:
800 figpause(10)
802 figpause(10)
801
803
General Comments 0
You need to be logged in to leave comments. Login now