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