##// END OF EJS Templates
Change steps for xticks in plots
Juan C. Espinoza -
r1196:06c60272fd61
parent child
Show More
@@ -1,800 +1,799
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.grid = kwargs.get('grid', False)
348 self.grid = kwargs.get('grid', False)
349 self.pause = kwargs.get('pause', False)
349 self.pause = kwargs.get('pause', False)
350 self.save_labels = kwargs.get('save_labels', None)
350 self.save_labels = kwargs.get('save_labels', None)
351 self.realtime = kwargs.get('realtime', True)
351 self.realtime = kwargs.get('realtime', True)
352 self.buffering = kwargs.get('buffering', True)
352 self.buffering = kwargs.get('buffering', True)
353 self.throttle = kwargs.get('throttle', 2)
353 self.throttle = kwargs.get('throttle', 2)
354 self.exp_code = kwargs.get('exp_code', None)
354 self.exp_code = kwargs.get('exp_code', None)
355 self.__throttle_plot = apply_throttle(self.throttle)
355 self.__throttle_plot = apply_throttle(self.throttle)
356 self.data = PlotterData(
356 self.data = PlotterData(
357 self.CODE, self.throttle, self.exp_code, self.buffering)
357 self.CODE, self.throttle, self.exp_code, self.buffering)
358
358
359 def __setup_plot(self):
359 def __setup_plot(self):
360 '''
360 '''
361 Common setup for all figures, here figures and axes are created
361 Common setup for all figures, here figures and axes are created
362 '''
362 '''
363
363
364 self.setup()
364 self.setup()
365
365
366 self.time_label = 'LT' if self.localtime else 'UTC'
366 self.time_label = 'LT' if self.localtime else 'UTC'
367 if self.data.localtime:
367 if self.data.localtime:
368 self.getDateTime = datetime.datetime.fromtimestamp
368 self.getDateTime = datetime.datetime.fromtimestamp
369 else:
369 else:
370 self.getDateTime = datetime.datetime.utcfromtimestamp
370 self.getDateTime = datetime.datetime.utcfromtimestamp
371
371
372 if self.width is None:
372 if self.width is None:
373 self.width = 8
373 self.width = 8
374
374
375 self.figures = []
375 self.figures = []
376 self.axes = []
376 self.axes = []
377 self.cb_axes = []
377 self.cb_axes = []
378 self.pf_axes = []
378 self.pf_axes = []
379 self.cmaps = []
379 self.cmaps = []
380
380
381 size = '15%' if self.ncols == 1 else '30%'
381 size = '15%' if self.ncols == 1 else '30%'
382 pad = '4%' if self.ncols == 1 else '8%'
382 pad = '4%' if self.ncols == 1 else '8%'
383
383
384 if self.oneFigure:
384 if self.oneFigure:
385 if self.height is None:
385 if self.height is None:
386 self.height = 1.4 * self.nrows + 1
386 self.height = 1.4 * self.nrows + 1
387 fig = plt.figure(figsize=(self.width, self.height),
387 fig = plt.figure(figsize=(self.width, self.height),
388 edgecolor='k',
388 edgecolor='k',
389 facecolor='w')
389 facecolor='w')
390 self.figures.append(fig)
390 self.figures.append(fig)
391 for n in range(self.nplots):
391 for n in range(self.nplots):
392 ax = fig.add_subplot(self.nrows, self.ncols,
392 ax = fig.add_subplot(self.nrows, self.ncols,
393 n + 1, polar=self.polar)
393 n + 1, polar=self.polar)
394 ax.tick_params(labelsize=8)
394 ax.tick_params(labelsize=8)
395 ax.firsttime = True
395 ax.firsttime = True
396 ax.index = 0
396 ax.index = 0
397 ax.press = None
397 ax.press = None
398 self.axes.append(ax)
398 self.axes.append(ax)
399 if self.showprofile:
399 if self.showprofile:
400 cax = self.__add_axes(ax, size=size, pad=pad)
400 cax = self.__add_axes(ax, size=size, pad=pad)
401 cax.tick_params(labelsize=8)
401 cax.tick_params(labelsize=8)
402 self.pf_axes.append(cax)
402 self.pf_axes.append(cax)
403 else:
403 else:
404 if self.height is None:
404 if self.height is None:
405 self.height = 3
405 self.height = 3
406 for n in range(self.nplots):
406 for n in range(self.nplots):
407 fig = plt.figure(figsize=(self.width, self.height),
407 fig = plt.figure(figsize=(self.width, self.height),
408 edgecolor='k',
408 edgecolor='k',
409 facecolor='w')
409 facecolor='w')
410 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
410 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
411 ax.tick_params(labelsize=8)
411 ax.tick_params(labelsize=8)
412 ax.firsttime = True
412 ax.firsttime = True
413 ax.index = 0
413 ax.index = 0
414 ax.press = None
414 ax.press = None
415 self.figures.append(fig)
415 self.figures.append(fig)
416 self.axes.append(ax)
416 self.axes.append(ax)
417 if self.showprofile:
417 if self.showprofile:
418 cax = self.__add_axes(ax, size=size, pad=pad)
418 cax = self.__add_axes(ax, size=size, pad=pad)
419 cax.tick_params(labelsize=8)
419 cax.tick_params(labelsize=8)
420 self.pf_axes.append(cax)
420 self.pf_axes.append(cax)
421
421
422 for n in range(self.nrows):
422 for n in range(self.nrows):
423 if self.colormaps is not None:
423 if self.colormaps is not None:
424 cmap = plt.get_cmap(self.colormaps[n])
424 cmap = plt.get_cmap(self.colormaps[n])
425 else:
425 else:
426 cmap = plt.get_cmap(self.colormap)
426 cmap = plt.get_cmap(self.colormap)
427 cmap.set_bad(self.bgcolor, 1.)
427 cmap.set_bad(self.bgcolor, 1.)
428 self.cmaps.append(cmap)
428 self.cmaps.append(cmap)
429
429
430 for fig in self.figures:
430 for fig in self.figures:
431 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
431 fig.canvas.mpl_connect('key_press_event', self.OnKeyPress)
432 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
432 fig.canvas.mpl_connect('scroll_event', self.OnBtnScroll)
433 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
433 fig.canvas.mpl_connect('button_press_event', self.onBtnPress)
434 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
434 fig.canvas.mpl_connect('motion_notify_event', self.onMotion)
435 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
435 fig.canvas.mpl_connect('button_release_event', self.onBtnRelease)
436 if self.show:
436 if self.show:
437 fig.show()
437 fig.show()
438
438
439 def OnKeyPress(self, event):
439 def OnKeyPress(self, event):
440 '''
440 '''
441 Event for pressing keys (up, down) change colormap
441 Event for pressing keys (up, down) change colormap
442 '''
442 '''
443 ax = event.inaxes
443 ax = event.inaxes
444 if ax in self.axes:
444 if ax in self.axes:
445 if event.key == 'down':
445 if event.key == 'down':
446 ax.index += 1
446 ax.index += 1
447 elif event.key == 'up':
447 elif event.key == 'up':
448 ax.index -= 1
448 ax.index -= 1
449 if ax.index < 0:
449 if ax.index < 0:
450 ax.index = len(CMAPS) - 1
450 ax.index = len(CMAPS) - 1
451 elif ax.index == len(CMAPS):
451 elif ax.index == len(CMAPS):
452 ax.index = 0
452 ax.index = 0
453 cmap = CMAPS[ax.index]
453 cmap = CMAPS[ax.index]
454 ax.cbar.set_cmap(cmap)
454 ax.cbar.set_cmap(cmap)
455 ax.cbar.draw_all()
455 ax.cbar.draw_all()
456 ax.plt.set_cmap(cmap)
456 ax.plt.set_cmap(cmap)
457 ax.cbar.patch.figure.canvas.draw()
457 ax.cbar.patch.figure.canvas.draw()
458 self.colormap = cmap.name
458 self.colormap = cmap.name
459
459
460 def OnBtnScroll(self, event):
460 def OnBtnScroll(self, event):
461 '''
461 '''
462 Event for scrolling, scale figure
462 Event for scrolling, scale figure
463 '''
463 '''
464 cb_ax = event.inaxes
464 cb_ax = event.inaxes
465 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
465 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
466 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
466 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
467 pt = ax.cbar.ax.bbox.get_points()[:, 1]
467 pt = ax.cbar.ax.bbox.get_points()[:, 1]
468 nrm = ax.cbar.norm
468 nrm = ax.cbar.norm
469 vmin, vmax, p0, p1, pS = (
469 vmin, vmax, p0, p1, pS = (
470 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
470 nrm.vmin, nrm.vmax, pt[0], pt[1], event.y)
471 scale = 2 if event.step == 1 else 0.5
471 scale = 2 if event.step == 1 else 0.5
472 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
472 point = vmin + (vmax - vmin) / (p1 - p0) * (pS - p0)
473 ax.cbar.norm.vmin = point - scale * (point - vmin)
473 ax.cbar.norm.vmin = point - scale * (point - vmin)
474 ax.cbar.norm.vmax = point - scale * (point - vmax)
474 ax.cbar.norm.vmax = point - scale * (point - vmax)
475 ax.plt.set_norm(ax.cbar.norm)
475 ax.plt.set_norm(ax.cbar.norm)
476 ax.cbar.draw_all()
476 ax.cbar.draw_all()
477 ax.cbar.patch.figure.canvas.draw()
477 ax.cbar.patch.figure.canvas.draw()
478
478
479 def onBtnPress(self, event):
479 def onBtnPress(self, event):
480 '''
480 '''
481 Event for mouse button press
481 Event for mouse button press
482 '''
482 '''
483 cb_ax = event.inaxes
483 cb_ax = event.inaxes
484 if cb_ax is None:
484 if cb_ax is None:
485 return
485 return
486
486
487 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
487 if cb_ax in [ax.cbar.ax for ax in self.axes if ax.cbar]:
488 cb_ax.press = event.x, event.y
488 cb_ax.press = event.x, event.y
489 else:
489 else:
490 cb_ax.press = None
490 cb_ax.press = None
491
491
492 def onMotion(self, event):
492 def onMotion(self, event):
493 '''
493 '''
494 Event for move inside colorbar
494 Event for move inside colorbar
495 '''
495 '''
496 cb_ax = event.inaxes
496 cb_ax = event.inaxes
497 if cb_ax is None:
497 if cb_ax is None:
498 return
498 return
499 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
499 if cb_ax not in [ax.cbar.ax for ax in self.axes if ax.cbar]:
500 return
500 return
501 if cb_ax.press is None:
501 if cb_ax.press is None:
502 return
502 return
503
503
504 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
504 ax = [ax for ax in self.axes if cb_ax == ax.cbar.ax][0]
505 xprev, yprev = cb_ax.press
505 xprev, yprev = cb_ax.press
506 dx = event.x - xprev
506 dx = event.x - xprev
507 dy = event.y - yprev
507 dy = event.y - yprev
508 cb_ax.press = event.x, event.y
508 cb_ax.press = event.x, event.y
509 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
509 scale = ax.cbar.norm.vmax - ax.cbar.norm.vmin
510 perc = 0.03
510 perc = 0.03
511
511
512 if event.button == 1:
512 if event.button == 1:
513 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
513 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
514 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
514 ax.cbar.norm.vmax -= (perc * scale) * numpy.sign(dy)
515 elif event.button == 3:
515 elif event.button == 3:
516 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
516 ax.cbar.norm.vmin -= (perc * scale) * numpy.sign(dy)
517 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
517 ax.cbar.norm.vmax += (perc * scale) * numpy.sign(dy)
518
518
519 ax.cbar.draw_all()
519 ax.cbar.draw_all()
520 ax.plt.set_norm(ax.cbar.norm)
520 ax.plt.set_norm(ax.cbar.norm)
521 ax.cbar.patch.figure.canvas.draw()
521 ax.cbar.patch.figure.canvas.draw()
522
522
523 def onBtnRelease(self, event):
523 def onBtnRelease(self, event):
524 '''
524 '''
525 Event for mouse button release
525 Event for mouse button release
526 '''
526 '''
527 cb_ax = event.inaxes
527 cb_ax = event.inaxes
528 if cb_ax is not None:
528 if cb_ax is not None:
529 cb_ax.press = None
529 cb_ax.press = None
530
530
531 def __add_axes(self, ax, size='30%', pad='8%'):
531 def __add_axes(self, ax, size='30%', pad='8%'):
532 '''
532 '''
533 Add new axes to the given figure
533 Add new axes to the given figure
534 '''
534 '''
535 divider = make_axes_locatable(ax)
535 divider = make_axes_locatable(ax)
536 nax = divider.new_horizontal(size=size, pad=pad)
536 nax = divider.new_horizontal(size=size, pad=pad)
537 ax.figure.add_axes(nax)
537 ax.figure.add_axes(nax)
538 return nax
538 return nax
539
539
540 def setup(self):
540 def setup(self):
541 '''
541 '''
542 This method should be implemented in the child class, the following
542 This method should be implemented in the child class, the following
543 attributes should be set:
543 attributes should be set:
544
544
545 self.nrows: number of rows
545 self.nrows: number of rows
546 self.ncols: number of cols
546 self.ncols: number of cols
547 self.nplots: number of plots (channels or pairs)
547 self.nplots: number of plots (channels or pairs)
548 self.ylabel: label for Y axes
548 self.ylabel: label for Y axes
549 self.titles: list of axes title
549 self.titles: list of axes title
550
550
551 '''
551 '''
552 raise NotImplementedError
552 raise NotImplementedError
553
553
554 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
554 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
555 '''
555 '''
556 Create a masked array for missing data
556 Create a masked array for missing data
557 '''
557 '''
558 if x_buffer.shape[0] < 2:
558 if x_buffer.shape[0] < 2:
559 return x_buffer, y_buffer, z_buffer
559 return x_buffer, y_buffer, z_buffer
560
560
561 deltas = x_buffer[1:] - x_buffer[0:-1]
561 deltas = x_buffer[1:] - x_buffer[0:-1]
562 x_median = numpy.median(deltas)
562 x_median = numpy.median(deltas)
563
563
564 index = numpy.where(deltas > 5 * x_median)
564 index = numpy.where(deltas > 5 * x_median)
565
565
566 if len(index[0]) != 0:
566 if len(index[0]) != 0:
567 z_buffer[::, index[0], ::] = self.__missing
567 z_buffer[::, index[0], ::] = self.__missing
568 z_buffer = numpy.ma.masked_inside(z_buffer,
568 z_buffer = numpy.ma.masked_inside(z_buffer,
569 0.99 * self.__missing,
569 0.99 * self.__missing,
570 1.01 * self.__missing)
570 1.01 * self.__missing)
571
571
572 return x_buffer, y_buffer, z_buffer
572 return x_buffer, y_buffer, z_buffer
573
573
574 def decimate(self):
574 def decimate(self):
575
575
576 # dx = int(len(self.x)/self.__MAXNUMX) + 1
576 # dx = int(len(self.x)/self.__MAXNUMX) + 1
577 dy = int(len(self.y) / self.decimation) + 1
577 dy = int(len(self.y) / self.decimation) + 1
578
578
579 # x = self.x[::dx]
579 # x = self.x[::dx]
580 x = self.x
580 x = self.x
581 y = self.y[::dy]
581 y = self.y[::dy]
582 z = self.z[::, ::, ::dy]
582 z = self.z[::, ::, ::dy]
583
583
584 return x, y, z
584 return x, y, z
585
585
586 def format(self):
586 def format(self):
587 '''
587 '''
588 Set min and max values, labels, ticks and titles
588 Set min and max values, labels, ticks and titles
589 '''
589 '''
590
590
591 if self.xmin is None:
591 if self.xmin is None:
592 xmin = self.data.min_time
592 xmin = self.data.min_time
593 else:
593 else:
594 if self.xaxis is 'time':
594 if self.xaxis is 'time':
595 dt = self.getDateTime(self.data.min_time)
595 dt = self.getDateTime(self.data.min_time)
596 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
596 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
597 datetime.datetime(1970, 1, 1)).total_seconds()
597 datetime.datetime(1970, 1, 1)).total_seconds()
598 if self.data.localtime:
598 if self.data.localtime:
599 xmin += time.timezone
599 xmin += time.timezone
600 else:
600 else:
601 xmin = self.xmin
601 xmin = self.xmin
602
602
603 if self.xmax is None:
603 if self.xmax is None:
604 xmax = xmin + self.xrange * 60 * 60
604 xmax = xmin + self.xrange * 60 * 60
605 else:
605 else:
606 if self.xaxis is 'time':
606 if self.xaxis is 'time':
607 dt = self.getDateTime(self.data.max_time)
607 dt = self.getDateTime(self.data.max_time)
608 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
608 xmax = (dt.replace(hour=int(self.xmax), minute=59, second=59) -
609 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
609 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
610 if self.data.localtime:
610 if self.data.localtime:
611 xmax += time.timezone
611 xmax += time.timezone
612 else:
612 else:
613 xmax = self.xmax
613 xmax = self.xmax
614
614
615 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
615 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
616 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
616 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
617
618 Y = numpy.array([1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000])
617 Y = numpy.array([1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000])
619 i = 1 if numpy.where(
618 i = 1 if numpy.where(
620 abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
619 abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
621 ystep = Y[i] / 10.
620 ystep = Y[i] / 10.
622
621
623 if self.xaxis is not 'time':
622 if self.xaxis is not 'time':
624 X = numpy.array([1, 2, 5, 10, 20, 50, 100,
623 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])/2.
624 200, 500, 1000, 2000, 5000])/2.
626 i = 1 if numpy.where(
625 i = 1 if numpy.where(
627 abs(xmax-xmin) <= X)[0][0] < 0 else numpy.where(abs(xmax-xmin) <= X)[0][0]
626 abs(xmax-xmin) <= X)[0][0] < 0 else numpy.where(abs(xmax-xmin) <= X)[0][0]
628 xstep = X[i] / 10.
627 xstep = X[i] / 5.
629
628
630 for n, ax in enumerate(self.axes):
629 for n, ax in enumerate(self.axes):
631 if ax.firsttime:
630 if ax.firsttime:
632 ax.set_facecolor(self.bgcolor)
631 ax.set_facecolor(self.bgcolor)
633 ax.yaxis.set_major_locator(MultipleLocator(ystep))
632 ax.yaxis.set_major_locator(MultipleLocator(ystep))
634 if self.xscale:
633 if self.xscale:
635 ax.xaxis.set_major_formatter(FuncFormatter(
634 ax.xaxis.set_major_formatter(FuncFormatter(
636 lambda x, pos: '{0:g}'.format(x*self.xscale)))
635 lambda x, pos: '{0:g}'.format(x*self.xscale)))
637 if self.xscale:
636 if self.xscale:
638 ax.yaxis.set_major_formatter(FuncFormatter(
637 ax.yaxis.set_major_formatter(FuncFormatter(
639 lambda x, pos: '{0:g}'.format(x*self.yscale)))
638 lambda x, pos: '{0:g}'.format(x*self.yscale)))
640 if self.xaxis is 'time':
639 if self.xaxis is 'time':
641 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
640 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
642 ax.xaxis.set_major_locator(LinearLocator(9))
641 ax.xaxis.set_major_locator(LinearLocator(9))
643 else:
642 else:
644 ax.xaxis.set_major_locator(MultipleLocator(xstep))
643 ax.xaxis.set_major_locator(MultipleLocator(xstep))
645 if self.xlabel is not None:
644 if self.xlabel is not None:
646 ax.set_xlabel(self.xlabel)
645 ax.set_xlabel(self.xlabel)
647 ax.set_ylabel(self.ylabel)
646 ax.set_ylabel(self.ylabel)
648 ax.firsttime = False
647 ax.firsttime = False
649 if self.showprofile:
648 if self.showprofile:
650 self.pf_axes[n].set_ylim(ymin, ymax)
649 self.pf_axes[n].set_ylim(ymin, ymax)
651 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
650 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
652 self.pf_axes[n].set_xlabel('dB')
651 self.pf_axes[n].set_xlabel('dB')
653 self.pf_axes[n].grid(b=True, axis='x')
652 self.pf_axes[n].grid(b=True, axis='x')
654 [tick.set_visible(False)
653 [tick.set_visible(False)
655 for tick in self.pf_axes[n].get_yticklabels()]
654 for tick in self.pf_axes[n].get_yticklabels()]
656 if self.colorbar:
655 if self.colorbar:
657 ax.cbar = plt.colorbar(
656 ax.cbar = plt.colorbar(
658 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
657 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
659 ax.cbar.ax.tick_params(labelsize=8)
658 ax.cbar.ax.tick_params(labelsize=8)
660 ax.cbar.ax.press = None
659 ax.cbar.ax.press = None
661 if self.cb_label:
660 if self.cb_label:
662 ax.cbar.set_label(self.cb_label, size=8)
661 ax.cbar.set_label(self.cb_label, size=8)
663 elif self.cb_labels:
662 elif self.cb_labels:
664 ax.cbar.set_label(self.cb_labels[n], size=8)
663 ax.cbar.set_label(self.cb_labels[n], size=8)
665 else:
664 else:
666 ax.cbar = None
665 ax.cbar = None
667 if self.grid:
666 if self.grid:
668 ax.grid(True)
667 ax.grid(True)
669
668
670 if not self.polar:
669 if not self.polar:
671 ax.set_xlim(xmin, xmax)
670 ax.set_xlim(xmin, xmax)
672 ax.set_ylim(ymin, ymax)
671 ax.set_ylim(ymin, ymax)
673 ax.set_title('{} {} {}'.format(
672 ax.set_title('{} {} {}'.format(
674 self.titles[n],
673 self.titles[n],
675 self.getDateTime(self.data.max_time).strftime(
674 self.getDateTime(self.data.max_time).strftime(
676 '%Y-%m-%dT%H:%M:%S'),
675 '%Y-%m-%dT%H:%M:%S'),
677 self.time_label),
676 self.time_label),
678 size=8)
677 size=8)
679 else:
678 else:
680 ax.set_title('{}'.format(self.titles[n]), size=8)
679 ax.set_title('{}'.format(self.titles[n]), size=8)
681 ax.set_ylim(0, 90)
680 ax.set_ylim(0, 90)
682 ax.set_yticks(numpy.arange(0, 90, 20))
681 ax.set_yticks(numpy.arange(0, 90, 20))
683 ax.yaxis.labelpad = 40
682 ax.yaxis.labelpad = 40
684
683
685 def clear_figures(self):
684 def clear_figures(self):
686 '''
685 '''
687 Reset axes for redraw plots
686 Reset axes for redraw plots
688 '''
687 '''
689
688
690 for ax in self.axes:
689 for ax in self.axes:
691 ax.clear()
690 ax.clear()
692 ax.firsttime = True
691 ax.firsttime = True
693 if ax.cbar:
692 if ax.cbar:
694 ax.cbar.remove()
693 ax.cbar.remove()
695
694
696 def __plot(self):
695 def __plot(self):
697 '''
696 '''
698 Main function to plot, format and save figures
697 Main function to plot, format and save figures
699 '''
698 '''
700
699
701 #try:
700 #try:
702 self.plot()
701 self.plot()
703 self.format()
702 self.format()
704 #except Exception as e:
703 #except Exception as e:
705 # log.warning('{} Plot could not be updated... check data'.format(
704 # log.warning('{} Plot could not be updated... check data'.format(
706 # self.CODE), self.name)
705 # self.CODE), self.name)
707 # log.error(str(e), '')
706 # log.error(str(e), '')
708 # return
707 # return
709
708
710 for n, fig in enumerate(self.figures):
709 for n, fig in enumerate(self.figures):
711 if self.nrows == 0 or self.nplots == 0:
710 if self.nrows == 0 or self.nplots == 0:
712 log.warning('No data', self.name)
711 log.warning('No data', self.name)
713 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
712 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
714 fig.canvas.manager.set_window_title(self.CODE)
713 fig.canvas.manager.set_window_title(self.CODE)
715 continue
714 continue
716
715
717 fig.tight_layout()
716 fig.tight_layout()
718 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
717 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
719 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
718 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
720 fig.canvas.draw()
719 fig.canvas.draw()
721
720
722 if self.save:
721 if self.save:
723
722
724 if self.save_labels:
723 if self.save_labels:
725 labels = self.save_labels
724 labels = self.save_labels
726 else:
725 else:
727 labels = list(range(self.nrows))
726 labels = list(range(self.nrows))
728
727
729 if self.oneFigure:
728 if self.oneFigure:
730 label = ''
729 label = ''
731 else:
730 else:
732 label = '-{}'.format(labels[n])
731 label = '-{}'.format(labels[n])
733 figname = os.path.join(
732 figname = os.path.join(
734 self.save,
733 self.save,
735 self.CODE,
734 self.CODE,
736 '{}{}_{}.png'.format(
735 '{}{}_{}.png'.format(
737 self.CODE,
736 self.CODE,
738 label,
737 label,
739 self.getDateTime(self.data.max_time).strftime(
738 self.getDateTime(self.data.max_time).strftime(
740 '%Y%m%d_%H%M%S'),
739 '%Y%m%d_%H%M%S'),
741 )
740 )
742 )
741 )
743 log.log('Saving figure: {}'.format(figname), self.name)
742 log.log('Saving figure: {}'.format(figname), self.name)
744 if not os.path.isdir(os.path.dirname(figname)):
743 if not os.path.isdir(os.path.dirname(figname)):
745 os.makedirs(os.path.dirname(figname))
744 os.makedirs(os.path.dirname(figname))
746 fig.savefig(figname)
745 fig.savefig(figname)
747
746
748 def plot(self):
747 def plot(self):
749 '''
748 '''
750 Must be defined in the child class
749 Must be defined in the child class
751 '''
750 '''
752 raise NotImplementedError
751 raise NotImplementedError
753
752
754 def run(self, dataOut, **kwargs):
753 def run(self, dataOut, **kwargs):
755
754
756 if dataOut.error:
755 if dataOut.error:
757 coerce = True
756 coerce = True
758 else:
757 else:
759 coerce = False
758 coerce = False
760
759
761 if self.isConfig is False:
760 if self.isConfig is False:
762 self.__setup(**kwargs)
761 self.__setup(**kwargs)
763 self.data.setup()
762 self.data.setup()
764 self.isConfig = True
763 self.isConfig = True
765
764
766 if dataOut.type == 'Parameters':
765 if dataOut.type == 'Parameters':
767 tm = dataOut.utctimeInit
766 tm = dataOut.utctimeInit
768 else:
767 else:
769 tm = dataOut.utctime
768 tm = dataOut.utctime
770
769
771 if dataOut.useLocalTime:
770 if dataOut.useLocalTime:
772 if not self.localtime:
771 if not self.localtime:
773 tm += time.timezone
772 tm += time.timezone
774 else:
773 else:
775 if self.localtime:
774 if self.localtime:
776 tm -= time.timezone
775 tm -= time.timezone
777
776
778 if self.data and (tm - self.data.min_time) >= self.xrange*60*60:
777 if self.data and (tm - self.data.min_time) >= self.xrange*60*60:
779 self.__plot()
778 self.__plot()
780 self.data.setup()
779 self.data.setup()
781 self.clear_figures()
780 self.clear_figures()
782
781
783 self.data.update(dataOut, tm)
782 self.data.update(dataOut, tm)
784
783
785 if self.isPlotConfig is False:
784 if self.isPlotConfig is False:
786 self.__setup_plot()
785 self.__setup_plot()
787 self.isPlotConfig = True
786 self.isPlotConfig = True
788
787
789 if self.realtime:
788 if self.realtime:
790 self.__plot()
789 self.__plot()
791 else:
790 else:
792 self.__throttle_plot(self.__plot, coerce=coerce)
791 self.__throttle_plot(self.__plot, coerce=coerce)
793
792
794 figpause(0.001)
793 figpause(0.001)
795
794
796 def close(self):
795 def close(self):
797
796
798 if self.data and self.pause:
797 if self.data and self.pause:
799 figpause(10)
798 figpause(10)
800
799
General Comments 0
You need to be logged in to leave comments. Login now