##// END OF EJS Templates
Fix dynamic 'xstep' for all Plots
George Yong -
r1204:d22cda2f4921
parent child
Show More
@@ -1,803 +1,824
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
619 #i = 1 if numpy.where(
620 #i = 1 if numpy.where(
620 # abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
621 # abs(ymax-ymin) <= Y)[0][0] < 0 else numpy.where(abs(ymax-ymin) <= Y)[0][0]
621 #ystep = Y[i] / 10.
622 #ystep = Y[i] / 10.
622 dig = int(numpy.log10(ymax))
623 dig = int(numpy.log10(ymax))
624 if dig == 0:
625 digD = len(str(ymax)) - 2
626 ydec = ymax*(10**digD)
627
628 dig = int(numpy.log10(ydec))
629 ystep = ((ydec + (10**(dig)))//10**(dig))*(10**(dig))
630 ystep = ystep/5
631 ystep = ystep/(10**digD)
632
633 else:
623 ystep = ((ymax + (10**(dig)))//10**(dig))*(10**(dig))
634 ystep = ((ymax + (10**(dig)))//10**(dig))*(10**(dig))
624 ystep = ystep//10
635 ystep = ystep/5
636
625 if self.xaxis is not 'time':
637 if self.xaxis is not 'time':
626 X = numpy.array([0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 20, 50, 100,
627 200, 500, 1000, 2000, 5000, 10000, 20000, 50000])/2.
628
638
629 i = 1 if numpy.where(
639 dig = int(numpy.log10(xmax))
630 abs(xmax-xmin) <= X)[0][0] < 0 else numpy.where(abs(xmax-xmin) <= X)[0][0]
640
631 xstep = X[i] / 5.
641 if dig <= 0:
642 digD = len(str(xmax)) - 2
643 xdec = xmax*(10**digD)
644
645 dig = int(numpy.log10(xdec))
646 xstep = ((xdec + (10**(dig)))//10**(dig))*(10**(dig))
647 xstep = xstep*0.5
648 xstep = xstep/(10**digD)
649
650 else:
651 xstep = ((xmax + (10**(dig)))//10**(dig))*(10**(dig))
652 xstep = xstep/5
632
653
633 for n, ax in enumerate(self.axes):
654 for n, ax in enumerate(self.axes):
634 if ax.firsttime:
655 if ax.firsttime:
635 ax.set_facecolor(self.bgcolor)
656 ax.set_facecolor(self.bgcolor)
636 ax.yaxis.set_major_locator(MultipleLocator(ystep))
657 ax.yaxis.set_major_locator(MultipleLocator(ystep))
637 if self.xscale:
658 if self.xscale:
638 ax.xaxis.set_major_formatter(FuncFormatter(
659 ax.xaxis.set_major_formatter(FuncFormatter(
639 lambda x, pos: '{0:g}'.format(x*self.xscale)))
660 lambda x, pos: '{0:g}'.format(x*self.xscale)))
640 if self.xscale:
661 if self.xscale:
641 ax.yaxis.set_major_formatter(FuncFormatter(
662 ax.yaxis.set_major_formatter(FuncFormatter(
642 lambda x, pos: '{0:g}'.format(x*self.yscale)))
663 lambda x, pos: '{0:g}'.format(x*self.yscale)))
643 if self.xaxis is 'time':
664 if self.xaxis is 'time':
644 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
665 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
645 ax.xaxis.set_major_locator(LinearLocator(9))
666 ax.xaxis.set_major_locator(LinearLocator(9))
646 else:
667 else:
647 ax.xaxis.set_major_locator(MultipleLocator(xstep))
668 ax.xaxis.set_major_locator(MultipleLocator(xstep))
648 if self.xlabel is not None:
669 if self.xlabel is not None:
649 ax.set_xlabel(self.xlabel)
670 ax.set_xlabel(self.xlabel)
650 ax.set_ylabel(self.ylabel)
671 ax.set_ylabel(self.ylabel)
651 ax.firsttime = False
672 ax.firsttime = False
652 if self.showprofile:
673 if self.showprofile:
653 self.pf_axes[n].set_ylim(ymin, ymax)
674 self.pf_axes[n].set_ylim(ymin, ymax)
654 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
675 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
655 self.pf_axes[n].set_xlabel('dB')
676 self.pf_axes[n].set_xlabel('dB')
656 self.pf_axes[n].grid(b=True, axis='x')
677 self.pf_axes[n].grid(b=True, axis='x')
657 [tick.set_visible(False)
678 [tick.set_visible(False)
658 for tick in self.pf_axes[n].get_yticklabels()]
679 for tick in self.pf_axes[n].get_yticklabels()]
659 if self.colorbar:
680 if self.colorbar:
660 ax.cbar = plt.colorbar(
681 ax.cbar = plt.colorbar(
661 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
682 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
662 ax.cbar.ax.tick_params(labelsize=8)
683 ax.cbar.ax.tick_params(labelsize=8)
663 ax.cbar.ax.press = None
684 ax.cbar.ax.press = None
664 if self.cb_label:
685 if self.cb_label:
665 ax.cbar.set_label(self.cb_label, size=8)
686 ax.cbar.set_label(self.cb_label, size=8)
666 elif self.cb_labels:
687 elif self.cb_labels:
667 ax.cbar.set_label(self.cb_labels[n], size=8)
688 ax.cbar.set_label(self.cb_labels[n], size=8)
668 else:
689 else:
669 ax.cbar = None
690 ax.cbar = None
670 if self.grid:
691 if self.grid:
671 ax.grid(True)
692 ax.grid(True)
672
693
673 if not self.polar:
694 if not self.polar:
674 ax.set_xlim(xmin, xmax)
695 ax.set_xlim(xmin, xmax)
675 ax.set_ylim(ymin, ymax)
696 ax.set_ylim(ymin, ymax)
676 ax.set_title('{} {} {}'.format(
697 ax.set_title('{} {} {}'.format(
677 self.titles[n],
698 self.titles[n],
678 self.getDateTime(self.data.max_time).strftime(
699 self.getDateTime(self.data.max_time).strftime(
679 '%H:%M:%S'),
700 '%H:%M:%S'),
680 self.time_label),
701 self.time_label),
681 size=8)
702 size=8)
682 else:
703 else:
683 ax.set_title('{}'.format(self.titles[n]), size=8)
704 ax.set_title('{}'.format(self.titles[n]), size=8)
684 ax.set_ylim(0, 90)
705 ax.set_ylim(0, 90)
685 ax.set_yticks(numpy.arange(0, 90, 20))
706 ax.set_yticks(numpy.arange(0, 90, 20))
686 ax.yaxis.labelpad = 40
707 ax.yaxis.labelpad = 40
687
708
688 def clear_figures(self):
709 def clear_figures(self):
689 '''
710 '''
690 Reset axes for redraw plots
711 Reset axes for redraw plots
691 '''
712 '''
692
713
693 for ax in self.axes:
714 for ax in self.axes:
694 ax.clear()
715 ax.clear()
695 ax.firsttime = True
716 ax.firsttime = True
696 if ax.cbar:
717 if ax.cbar:
697 ax.cbar.remove()
718 ax.cbar.remove()
698
719
699 def __plot(self):
720 def __plot(self):
700 '''
721 '''
701 Main function to plot, format and save figures
722 Main function to plot, format and save figures
702 '''
723 '''
703
724
704 #try:
725 #try:
705 self.plot()
726 self.plot()
706 self.format()
727 self.format()
707 #except Exception as e:
728 #except Exception as e:
708 # log.warning('{} Plot could not be updated... check data'.format(
729 # log.warning('{} Plot could not be updated... check data'.format(
709 # self.CODE), self.name)
730 # self.CODE), self.name)
710 # log.error(str(e), '')
731 # log.error(str(e), '')
711 # return
732 # return
712
733
713 for n, fig in enumerate(self.figures):
734 for n, fig in enumerate(self.figures):
714 if self.nrows == 0 or self.nplots == 0:
735 if self.nrows == 0 or self.nplots == 0:
715 log.warning('No data', self.name)
736 log.warning('No data', self.name)
716 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
737 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
717 fig.canvas.manager.set_window_title(self.CODE)
738 fig.canvas.manager.set_window_title(self.CODE)
718 continue
739 continue
719
740
720 fig.tight_layout()
741 fig.tight_layout()
721 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
742 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
722 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
743 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
723 fig.canvas.draw()
744 fig.canvas.draw()
724
745
725 if self.save:
746 if self.save:
726
747
727 if self.save_labels:
748 if self.save_labels:
728 labels = self.save_labels
749 labels = self.save_labels
729 else:
750 else:
730 labels = list(range(self.nrows))
751 labels = list(range(self.nrows))
731
752
732 if self.oneFigure:
753 if self.oneFigure:
733 label = ''
754 label = ''
734 else:
755 else:
735 label = '-{}'.format(labels[n])
756 label = '-{}'.format(labels[n])
736 figname = os.path.join(
757 figname = os.path.join(
737 self.save,
758 self.save,
738 self.CODE,
759 self.CODE,
739 '{}{}_{}.png'.format(
760 '{}{}_{}.png'.format(
740 self.CODE,
761 self.CODE,
741 label,
762 label,
742 self.getDateTime(self.data.max_time).strftime(
763 self.getDateTime(self.data.max_time).strftime(
743 '%Y%m%d_%H%M%S'),
764 '%Y%m%d_%H%M%S'),
744 )
765 )
745 )
766 )
746 log.log('Saving figure: {}'.format(figname), self.name)
767 log.log('Saving figure: {}'.format(figname), self.name)
747 if not os.path.isdir(os.path.dirname(figname)):
768 if not os.path.isdir(os.path.dirname(figname)):
748 os.makedirs(os.path.dirname(figname))
769 os.makedirs(os.path.dirname(figname))
749 fig.savefig(figname)
770 fig.savefig(figname)
750
771
751 def plot(self):
772 def plot(self):
752 '''
773 '''
753 Must be defined in the child class
774 Must be defined in the child class
754 '''
775 '''
755 raise NotImplementedError
776 raise NotImplementedError
756
777
757 def run(self, dataOut, **kwargs):
778 def run(self, dataOut, **kwargs):
758
779
759 if dataOut.error:
780 if dataOut.error:
760 coerce = True
781 coerce = True
761 else:
782 else:
762 coerce = False
783 coerce = False
763
784
764 if self.isConfig is False:
785 if self.isConfig is False:
765 self.__setup(**kwargs)
786 self.__setup(**kwargs)
766 self.data.setup()
787 self.data.setup()
767 self.isConfig = True
788 self.isConfig = True
768
789
769 if dataOut.type == 'Parameters':
790 if dataOut.type == 'Parameters':
770 tm = dataOut.utctimeInit
791 tm = dataOut.utctimeInit
771 else:
792 else:
772 tm = dataOut.utctime
793 tm = dataOut.utctime
773
794
774 if dataOut.useLocalTime:
795 if dataOut.useLocalTime:
775 if not self.localtime:
796 if not self.localtime:
776 tm += time.timezone
797 tm += time.timezone
777 else:
798 else:
778 if self.localtime:
799 if self.localtime:
779 tm -= time.timezone
800 tm -= time.timezone
780
801
781 if self.data and (tm - self.data.min_time) >= self.xrange*60*60:
802 if self.data and (tm - self.data.min_time) >= self.xrange*60*60:
782 self.__plot()
803 self.__plot()
783 self.data.setup()
804 self.data.setup()
784 self.clear_figures()
805 self.clear_figures()
785
806
786 self.data.update(dataOut, tm)
807 self.data.update(dataOut, tm)
787
808
788 if self.isPlotConfig is False:
809 if self.isPlotConfig is False:
789 self.__setup_plot()
810 self.__setup_plot()
790 self.isPlotConfig = True
811 self.isPlotConfig = True
791
812
792 if self.realtime:
813 if self.realtime:
793 self.__plot()
814 self.__plot()
794 else:
815 else:
795 self.__throttle_plot(self.__plot, coerce=coerce)
816 self.__throttle_plot(self.__plot, coerce=coerce)
796
817
797 figpause(0.001)
818 figpause(0.001)
798
819
799 def close(self):
820 def close(self):
800
821
801 if self.data and self.pause:
822 if self.data and self.pause:
802 figpause(10)
823 figpause(10)
803
824
General Comments 0
You need to be logged in to leave comments. Login now