##// END OF EJS Templates
Update README
Juan C. Espinoza -
r1289:303db73c0c9d
parent child
Show More
@@ -1,155 +1,158
1 # Signal Chain
1 # Signal Chain
2
2
3 ## Introduction
3 ## Introduction
4
4
5 Signal Chain (SCh) is a radar data processing library developed using [Python](www.python.org) at JRO. SCh provides modules to read, write, process and plot data.
5 Signal Chain (SCh) is a radar data processing library developed using [Python](www.python.org) at JRO. SCh provides modules to read, write, process and plot data.
6
6
7 ## Installation
7 ## Installation
8
8
9 Install system dependencies, clone the latest version from [here](http://jro-dev.igp.gob.pe/rhodecode/schain/) and install it as a normal python package.
9 Install system dependencies, clone the latest version from [here](http://jro-dev.igp.gob.pe/rhodecode/schain/) and install it as a normal python package, we strongly recommend to use Anaconda or a virtual environment for the installation.
10
10
11 ### Linux based system
11 ### Dependencies
12 - GCC (gcc or gfortran)
13 - Python.h (python-dev or python-devel)
14 - Python-TK (python-tk)
15 - HDF5 libraries (libhdf5-dev)
16
17 ### Linux based system (e.g. ubuntu)
12 ```
18 ```
13 $ sudo apt-get install python-pip python-dev gfortran libpng-dev freetype* libblas-dev liblapack-dev libatlas-base-dev python-qt4 python-tk libssl-dev libhdf5-dev
14 $ git clone http://jro-dev.igp.gob.pe/rhodecode/schain/
19 $ git clone http://jro-dev.igp.gob.pe/rhodecode/schain/
15 $ cd schain
20 $ cd schain
21 $ git checkout `schain-branch` (optional)
16 $ sudo pip install ./
22 $ sudo pip install ./
17
18 ```
23 ```
19
24
20 ### MAC Os
25 ### MAC Os
21 ```
26 ```
22 $ brew install python
27 $ brew install python
23 $ brew install cartr/qt4/pyqt
24 $ git clone http://jro-dev.igp.gob.pe/rhodecode/schain/
28 $ git clone http://jro-dev.igp.gob.pe/rhodecode/schain/
25 $ cd schain
29 $ cd schain
26 $ pip install ./
30 $ git checkout `schain-branch` (optional)
27 ```
31 $ sudo pip install ./
28
29 **It is recommended to install schain in a virtual environment**
30 ```
31 $ virtualenv /path/to/virtual
32 $ source /path/to/virtual/bin/activate
33 (virtual) $ cd schain
34 (virtual) $ pip install ./
35 (virtual) $ bash link_PyQt4.sh
36 ```
32 ```
37
33
38 ### Docker
34 ### Docker
39
35
40 Download Dockerfile from the repository, and create a docker image
36 Download Dockerfile from the repository, and create a docker image
41
37
42 ```
38 ```
43 $ docker build -t schain .
39 $ docker build -t schain .
44 ```
40 ```
45
41
46 You can run a container using an xml file or a schain script also you need to mount a volume for the data input and for the output files/plots
42 You can run a container using an xml file or a schain script also you need to mount a volume for the data input and for the output files/plots
47 ```
43 ```
48 $ docker run -it --rm --volume /path/to/host/data:/data schain xml /data/test.xml
44 $ docker run -it --rm --volume /path/to/host/data:/data schain xml /data/test.xml
49 $ docker run -it --rm --volume /path/to/host/data:/data --entrypoint /urs/local/bin/python schain /data/test.py
45 $ docker run -it --rm --volume /path/to/host/data:/data --entrypoint /urs/local/bin/python schain /data/test.py
50 ```
46 ```
51
47
48 ## CLI (command line interface)
49
50 Signal Chain provides the following commands:
51
52 - schainGUI: Open the GUI
53 - schain: Signal chain command line
54
55
52 ## First Script
56 ## First Script
53
57
54 Read Spectra data (.pdata) - remove dc - plot spectra & RTI
58 Here you can find an script to read Spectra data (.pdata), remove dc and plot spectra & RTI
55
59
56 Import SCh and creating a project
60 First import SCh and creating a project
57
61
58 ```python
62 ```python
59 #!/usr/bin/python
63 #!/usr/bin/python
60
64
61 from schainpy.controller import Project
65 from schainpy.controller import Project
62
66
63 controller = Project()
67 prj = Project()
64 controller.setup(id = '100',
68 prj.setup(
65 name='test',
69 id = '100',
66 description='Basic experiment')
70 name='test',
67
71 description='Basic experiment'
68
72 )
69 ```
73 ```
70
74
71 Adding read unit and operations
75 Add read unit and operations
72
76
73 ```python
77 ```python
74 read_unit = controller.addReadUnit(datatype='Spectra',
78 read_unit = prj.addReadUnit(
75 path='/path/to/pdata/',
79 datatype='Spectra',
76 startDate='2014/01/31',
80 path='/path/to/pdata/',
77 endDate='2014/03/31',
81 startDate='2014/01/31',
78 startTime='00:00:00',
82 endDate='2014/03/31',
79 endTime='23:59:59',
83 startTime='00:00:00',
80 online=0,
84 endTime='23:59:59',
81 walk=0)
85 online=0,
82
86 walk=0
83 proc_unit = controller.addProcUnit(datatype='Spectra',
87 )
84 inputId=read_unit.getId())
88
89 proc_unit = prj.addProcUnit(datatype='Spectra', inputId=read_unit.getId())
85
90
86 op = proc_unit.addOperation(name='selectChannels')
91 op = proc_unit.addOperation(name='selectChannels')
87 op.addParameter(name='channelList', value='0,1', format='intlist')
92 op.addParameter(name='channelList', value='0,1')
88
93
89 op = proc_unit.addOperation(name='selectHeights')
94 op = proc_unit.addOperation(name='selectHeights')
90 op.addParameter(name='minHei', value='80', format='float')
95 op.addParameter(name='minHei', value='80')
91 op.addParameter(name='maxHei', value='200', format='float')
96 op.addParameter(name='maxHei', value='200')
92
97
93 op = proc_unit.addOperation(name='removeDC')
98 op = proc_unit.addOperation(name='removeDC')
94
99
95 ```
100 ```
96
101
97 Plotting data & start project
102 Plot data & start project
98
103
99 ```python
104 ```python
100 op = proc_unit.addOperation(name='SpectraPlot', optype='other')
105 op = proc_unit.addOperation(name='SpectraPlot')
101 op.addParameter(name='id', value='1', format='int')
106 op.addParameter(name='id', value='1')
102 op.addParameter(name='wintitle', value='Spectra', format='str')
107 op.addParameter(name='wintitle', value='Spectra')
103
108
104 op = procUnitConfObj1.addOperation(name='RTIPlot', optype='other')
109 op = procUnitConfObj1.addOperation(name='RTIPlot')
105 op.addParameter(name='id', value='2', format='int')
110 op.addParameter(name='id', value='2')
106 op.addParameter(name='wintitle', value='RTI', format='str')
111 op.addParameter(name='wintitle', value='RTI')
107
112
108 controller.start()
113 prj.start()
109
114
110 ```
115 ```
111
116
112 Full script
117 Full script
113
118
114
119
115 ```python
120 ```python
116 #!/usr/bin/python
121 #!/usr/bin/python
117
122
118 from schainpy.controller import Project
123 from schainpy.prj import Project
119
124
120 controller = Project()
125 prj = Project()
121 controller.setup(id = '100',
126 prj.setup(id = '100',
122 name='test',
127 name='test',
123 description='Basic experiment')
128 description='Basic experiment')
124 read_unit = controller.addReadUnit(datatype='Spectra',
129 read_unit = prj.addReadUnit(datatype='Spectra',
125 path='/path/to/pdata/',
130 path='/path/to/pdata/',
126 startDate='2014/01/31',
131 startDate='2014/01/31',
127 endDate='2014/03/31',
132 endDate='2014/03/31',
128 startTime='00:00:00',
133 startTime='00:00:00',
129 endTime='23:59:59',
134 endTime='23:59:59',
130 online=0,
135 online=0,
131 walk=0)
136 walk=0)
132
137
133 proc_unit = controller.addProcUnit(datatype='Spectra',
138 proc_unit = prj.addProcUnit(datatype='Spectra',
134 inputId=read_unit.getId())
139 inputId=read_unit.getId())
135
140
136 op = proc_unit.addOperation(name='selectChannels')
141 op = proc_unit.addOperation(name='selectChannels')
137 op.addParameter(name='channelList', value='0,1', format='intlist')
142 op.addParameter(name='channelList', value='0,1')
138
143
139 op = proc_unit.addOperation(name='selectHeights')
144 op = proc_unit.addOperation(name='selectHeights')
140 op.addParameter(name='minHei', value='80', format='float')
145 op.addParameter(name='minHei', value='80')
141 op.addParameter(name='maxHei', value='200', format='float')
146 op.addParameter(name='maxHei', value='200')
142
147
143 op = proc_unit.addOperation(name='removeDC')
148 op = proc_unit.addOperation(name='removeDC')
144
149
145 op = proc_unit.addOperation(name='SpectraPlot', optype='other')
150 op = proc_unit.addOperation(name='SpectraPlot')
146 op.addParameter(name='id', value='6', format='int')
147 op.addParameter(name='wintitle', value='Spectra', format='str')
151 op.addParameter(name='wintitle', value='Spectra', format='str')
148
152
149 op = procUnitConfObj1.addOperation(name='RTIPlot', optype='other')
153 op = procUnitConfObj1.addOperation(name='RTIPlot')
150 op.addParameter(name='id', value='2', format='int')
151 op.addParameter(name='wintitle', value='RTI', format='str')
154 op.addParameter(name='wintitle', value='RTI', format='str')
152
155
153 controller.start()
156 prj.start()
154
157
155 ``` No newline at end of file
158 ```
@@ -1,700 +1,700
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 numpy
6 import numpy
7 import datetime
7 import datetime
8 from functools import wraps
8 from functools import wraps
9 from threading import Thread
9 from threading import Thread
10 import matplotlib
10 import matplotlib
11
11
12 if 'BACKEND' in os.environ:
12 if 'BACKEND' in os.environ:
13 matplotlib.use(os.environ['BACKEND'])
13 matplotlib.use(os.environ['BACKEND'])
14 elif 'linux' in sys.platform:
14 elif 'linux' in sys.platform:
15 matplotlib.use("TkAgg")
15 matplotlib.use("TkAgg")
16 elif 'darwin' in sys.platform:
16 elif 'darwin' in sys.platform:
17 matplotlib.use('WxAgg')
17 matplotlib.use('WxAgg')
18 else:
18 else:
19 from schainpy.utils import log
19 from schainpy.utils import log
20 log.warning('Using default Backend="Agg"', 'INFO')
20 log.warning('Using default Backend="Agg"', 'INFO')
21 matplotlib.use('Agg')
21 matplotlib.use('Agg')
22
22
23 import matplotlib.pyplot as plt
23 import matplotlib.pyplot as plt
24 from matplotlib.patches import Polygon
24 from matplotlib.patches import Polygon
25 from mpl_toolkits.axes_grid1 import make_axes_locatable
25 from mpl_toolkits.axes_grid1 import make_axes_locatable
26 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
26 from matplotlib.ticker import FuncFormatter, LinearLocator, MultipleLocator
27
27
28 from schainpy.model.data.jrodata import PlotterData
28 from schainpy.model.data.jrodata import PlotterData
29 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
29 from schainpy.model.proc.jroproc_base import ProcessingUnit, Operation, MPDecorator
30 from schainpy.utils import log
30 from schainpy.utils import log
31
31
32 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
32 jet_values = matplotlib.pyplot.get_cmap('jet', 100)(numpy.arange(100))[10:90]
33 blu_values = matplotlib.pyplot.get_cmap(
33 blu_values = matplotlib.pyplot.get_cmap(
34 'seismic_r', 20)(numpy.arange(20))[10:15]
34 'seismic_r', 20)(numpy.arange(20))[10:15]
35 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
35 ncmap = matplotlib.colors.LinearSegmentedColormap.from_list(
36 'jro', numpy.vstack((blu_values, jet_values)))
36 'jro', numpy.vstack((blu_values, jet_values)))
37 matplotlib.pyplot.register_cmap(cmap=ncmap)
37 matplotlib.pyplot.register_cmap(cmap=ncmap)
38
38
39 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
39 CMAPS = [plt.get_cmap(s) for s in ('jro', 'jet', 'viridis',
40 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
40 'plasma', 'inferno', 'Greys', 'seismic', 'bwr', 'coolwarm')]
41
41
42 EARTH_RADIUS = 6.3710e3
42 EARTH_RADIUS = 6.3710e3
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
141
142 @MPDecorator
142 @MPDecorator
143 class Plot(Operation):
143 class Plot(Operation):
144 '''
144 '''
145 Base class for Schain plotting operations
145 Base class for Schain plotting operations
146 '''
146 '''
147
147
148 CODE = 'Figure'
148 CODE = 'Figure'
149 colormap = 'jet'
149 colormap = 'jet'
150 bgcolor = 'white'
150 bgcolor = 'white'
151 buffering = True
151 buffering = True
152 __missing = 1E30
152 __missing = 1E30
153
153
154 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
154 __attrs__ = ['show', 'save', 'ymin', 'ymax', 'zmin', 'zmax', 'title',
155 'showprofile']
155 'showprofile']
156
156
157 def __init__(self):
157 def __init__(self):
158
158
159 Operation.__init__(self)
159 Operation.__init__(self)
160 self.isConfig = False
160 self.isConfig = False
161 self.isPlotConfig = False
161 self.isPlotConfig = False
162 self.save_counter = 1
162 self.save_counter = 1
163 self.sender_counter = 1
163 self.sender_counter = 1
164 self.data = None
164 self.data = None
165 self.firsttime = True
165 self.firsttime = True
166 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
166 self.plots_adjust = {'left': 0.125, 'right': 0.9, 'bottom': 0.15, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2}
167
167
168 def __fmtTime(self, x, pos):
168 def __fmtTime(self, x, pos):
169 '''
169 '''
170 '''
170 '''
171
171
172 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
172 return '{}'.format(self.getDateTime(x).strftime('%H:%M'))
173
173
174 def __setup(self, **kwargs):
174 def __setup(self, **kwargs):
175 '''
175 '''
176 Initialize variables
176 Initialize variables
177 '''
177 '''
178
178
179 self.figures = []
179 self.figures = []
180 self.axes = []
180 self.axes = []
181 self.cb_axes = []
181 self.cb_axes = []
182 self.localtime = kwargs.pop('localtime', True)
182 self.localtime = kwargs.pop('localtime', True)
183 self.show = kwargs.get('show', True)
183 self.show = kwargs.get('show', True)
184 self.save = kwargs.get('save', False)
184 self.save = kwargs.get('save', False)
185 self.save_period = kwargs.get('save_period', 1)
185 self.save_period = kwargs.get('save_period', 1)
186 self.ftp = kwargs.get('ftp', False)
186 self.ftp = kwargs.get('ftp', False)
187 self.colormap = kwargs.get('colormap', self.colormap)
187 self.colormap = kwargs.get('colormap', self.colormap)
188 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
188 self.colormap_coh = kwargs.get('colormap_coh', 'jet')
189 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
189 self.colormap_phase = kwargs.get('colormap_phase', 'RdBu_r')
190 self.colormaps = kwargs.get('colormaps', None)
190 self.colormaps = kwargs.get('colormaps', None)
191 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
191 self.bgcolor = kwargs.get('bgcolor', self.bgcolor)
192 self.showprofile = kwargs.get('showprofile', False)
192 self.showprofile = kwargs.get('showprofile', False)
193 self.title = kwargs.get('wintitle', self.CODE.upper())
193 self.title = kwargs.get('wintitle', self.CODE.upper())
194 self.cb_label = kwargs.get('cb_label', None)
194 self.cb_label = kwargs.get('cb_label', None)
195 self.cb_labels = kwargs.get('cb_labels', None)
195 self.cb_labels = kwargs.get('cb_labels', None)
196 self.labels = kwargs.get('labels', None)
196 self.labels = kwargs.get('labels', None)
197 self.xaxis = kwargs.get('xaxis', 'frequency')
197 self.xaxis = kwargs.get('xaxis', 'frequency')
198 self.zmin = kwargs.get('zmin', None)
198 self.zmin = kwargs.get('zmin', None)
199 self.zmax = kwargs.get('zmax', None)
199 self.zmax = kwargs.get('zmax', None)
200 self.zlimits = kwargs.get('zlimits', None)
200 self.zlimits = kwargs.get('zlimits', None)
201 self.xmin = kwargs.get('xmin', None)
201 self.xmin = kwargs.get('xmin', None)
202 self.xmax = kwargs.get('xmax', None)
202 self.xmax = kwargs.get('xmax', None)
203 self.xrange = kwargs.get('xrange', 24)
203 self.xrange = kwargs.get('xrange', 24)
204 self.xscale = kwargs.get('xscale', None)
204 self.xscale = kwargs.get('xscale', None)
205 self.ymin = kwargs.get('ymin', None)
205 self.ymin = kwargs.get('ymin', None)
206 self.ymax = kwargs.get('ymax', None)
206 self.ymax = kwargs.get('ymax', None)
207 self.yscale = kwargs.get('yscale', None)
207 self.yscale = kwargs.get('yscale', None)
208 self.xlabel = kwargs.get('xlabel', None)
208 self.xlabel = kwargs.get('xlabel', None)
209 self.attr_time = kwargs.get('attr_time', 'utctime')
209 self.attr_time = kwargs.get('attr_time', 'utctime')
210 self.decimation = kwargs.get('decimation', None)
210 self.decimation = kwargs.get('decimation', None)
211 self.showSNR = kwargs.get('showSNR', False)
211 self.showSNR = kwargs.get('showSNR', False)
212 self.oneFigure = kwargs.get('oneFigure', True)
212 self.oneFigure = kwargs.get('oneFigure', True)
213 self.width = kwargs.get('width', None)
213 self.width = kwargs.get('width', None)
214 self.height = kwargs.get('height', None)
214 self.height = kwargs.get('height', None)
215 self.colorbar = kwargs.get('colorbar', True)
215 self.colorbar = kwargs.get('colorbar', True)
216 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
216 self.factors = kwargs.get('factors', [1, 1, 1, 1, 1, 1, 1, 1])
217 self.channels = kwargs.get('channels', None)
217 self.channels = kwargs.get('channels', None)
218 self.titles = kwargs.get('titles', [])
218 self.titles = kwargs.get('titles', [])
219 self.polar = False
219 self.polar = False
220 self.type = kwargs.get('type', 'iq')
220 self.type = kwargs.get('type', 'iq')
221 self.grid = kwargs.get('grid', False)
221 self.grid = kwargs.get('grid', False)
222 self.pause = kwargs.get('pause', False)
222 self.pause = kwargs.get('pause', False)
223 self.save_code = kwargs.get('save_code', None)
223 self.save_code = kwargs.get('save_code', None)
224 self.realtime = kwargs.get('realtime', True)
224 self.realtime = kwargs.get('realtime', True)
225 self.throttle = kwargs.get('throttle', 0)
225 self.throttle = kwargs.get('throttle', 0)
226 self.exp_code = kwargs.get('exp_code', None)
226 self.exp_code = kwargs.get('exp_code', None)
227 self.plot_server = kwargs.get('plot_server', False)
227 self.plot_server = kwargs.get('plot_server', False)
228 self.sender_period = kwargs.get('sender_period', 1)
228 self.sender_period = kwargs.get('sender_period', 1)
229 self.height_index = kwargs.get('height_index', None)
229 self.height_index = kwargs.get('height_index', None)
230 self.__throttle_plot = apply_throttle(self.throttle)
230 self.__throttle_plot = apply_throttle(self.throttle)
231 self.data = PlotterData(
231 self.data = PlotterData(
232 self.CODE, self.throttle, self.exp_code, self.buffering, snr=self.showSNR)
232 self.CODE, self.throttle, self.exp_code, self.buffering, snr=self.showSNR)
233
233
234 if self.plot_server:
234 if self.plot_server:
235 if not self.plot_server.startswith('tcp://'):
235 if not self.plot_server.startswith('tcp://'):
236 self.plot_server = 'tcp://{}'.format(self.plot_server)
236 self.plot_server = 'tcp://{}'.format(self.plot_server)
237 log.success(
237 log.success(
238 'Sending to server: {}'.format(self.plot_server),
238 'Sending to server: {}'.format(self.plot_server),
239 self.name
239 self.name
240 )
240 )
241 if 'plot_name' in kwargs:
241 if 'plot_name' in kwargs:
242 self.plot_name = kwargs['plot_name']
242 self.plot_name = kwargs['plot_name']
243
243
244 def __setup_plot(self):
244 def __setup_plot(self):
245 '''
245 '''
246 Common setup for all figures, here figures and axes are created
246 Common setup for all figures, here figures and axes are created
247 '''
247 '''
248
248
249 self.setup()
249 self.setup()
250
250
251 self.time_label = 'LT' if self.localtime else 'UTC'
251 self.time_label = 'LT' if self.localtime else 'UTC'
252
252
253 if self.width is None:
253 if self.width is None:
254 self.width = 8
254 self.width = 8
255
255
256 self.figures = []
256 self.figures = []
257 self.axes = []
257 self.axes = []
258 self.cb_axes = []
258 self.cb_axes = []
259 self.pf_axes = []
259 self.pf_axes = []
260 self.cmaps = []
260 self.cmaps = []
261
261
262 size = '15%' if self.ncols == 1 else '30%'
262 size = '15%' if self.ncols == 1 else '30%'
263 pad = '4%' if self.ncols == 1 else '8%'
263 pad = '4%' if self.ncols == 1 else '8%'
264
264
265 if self.oneFigure:
265 if self.oneFigure:
266 if self.height is None:
266 if self.height is None:
267 self.height = 1.4 * self.nrows + 1
267 self.height = 1.4 * self.nrows + 1
268 fig = plt.figure(figsize=(self.width, self.height),
268 fig = plt.figure(figsize=(self.width, self.height),
269 edgecolor='k',
269 edgecolor='k',
270 facecolor='w')
270 facecolor='w')
271 self.figures.append(fig)
271 self.figures.append(fig)
272 for n in range(self.nplots):
272 for n in range(self.nplots):
273 ax = fig.add_subplot(self.nrows, self.ncols,
273 ax = fig.add_subplot(self.nrows, self.ncols,
274 n + 1, polar=self.polar)
274 n + 1, polar=self.polar)
275 ax.tick_params(labelsize=8)
275 ax.tick_params(labelsize=8)
276 ax.firsttime = True
276 ax.firsttime = True
277 ax.index = 0
277 ax.index = 0
278 ax.press = None
278 ax.press = None
279 self.axes.append(ax)
279 self.axes.append(ax)
280 if self.showprofile:
280 if self.showprofile:
281 cax = self.__add_axes(ax, size=size, pad=pad)
281 cax = self.__add_axes(ax, size=size, pad=pad)
282 cax.tick_params(labelsize=8)
282 cax.tick_params(labelsize=8)
283 self.pf_axes.append(cax)
283 self.pf_axes.append(cax)
284 else:
284 else:
285 if self.height is None:
285 if self.height is None:
286 self.height = 3
286 self.height = 3
287 for n in range(self.nplots):
287 for n in range(self.nplots):
288 fig = plt.figure(figsize=(self.width, self.height),
288 fig = plt.figure(figsize=(self.width, self.height),
289 edgecolor='k',
289 edgecolor='k',
290 facecolor='w')
290 facecolor='w')
291 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
291 ax = fig.add_subplot(1, 1, 1, polar=self.polar)
292 ax.tick_params(labelsize=8)
292 ax.tick_params(labelsize=8)
293 ax.firsttime = True
293 ax.firsttime = True
294 ax.index = 0
294 ax.index = 0
295 ax.press = None
295 ax.press = None
296 self.figures.append(fig)
296 self.figures.append(fig)
297 self.axes.append(ax)
297 self.axes.append(ax)
298 if self.showprofile:
298 if self.showprofile:
299 cax = self.__add_axes(ax, size=size, pad=pad)
299 cax = self.__add_axes(ax, size=size, pad=pad)
300 cax.tick_params(labelsize=8)
300 cax.tick_params(labelsize=8)
301 self.pf_axes.append(cax)
301 self.pf_axes.append(cax)
302
302
303 for n in range(self.nrows):
303 for n in range(self.nrows):
304 if self.colormaps is not None:
304 if self.colormaps is not None:
305 cmap = plt.get_cmap(self.colormaps[n])
305 cmap = plt.get_cmap(self.colormaps[n])
306 else:
306 else:
307 cmap = plt.get_cmap(self.colormap)
307 cmap = plt.get_cmap(self.colormap)
308 cmap.set_bad(self.bgcolor, 1.)
308 cmap.set_bad(self.bgcolor, 1.)
309 self.cmaps.append(cmap)
309 self.cmaps.append(cmap)
310
310
311 def __add_axes(self, ax, size='30%', pad='8%'):
311 def __add_axes(self, ax, size='30%', pad='8%'):
312 '''
312 '''
313 Add new axes to the given figure
313 Add new axes to the given figure
314 '''
314 '''
315 divider = make_axes_locatable(ax)
315 divider = make_axes_locatable(ax)
316 nax = divider.new_horizontal(size=size, pad=pad)
316 nax = divider.new_horizontal(size=size, pad=pad)
317 ax.figure.add_axes(nax)
317 ax.figure.add_axes(nax)
318 return nax
318 return nax
319
319
320 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
320 def fill_gaps(self, x_buffer, y_buffer, z_buffer):
321 '''
321 '''
322 Create a masked array for missing data
322 Create a masked array for missing data
323 '''
323 '''
324 if x_buffer.shape[0] < 2:
324 if x_buffer.shape[0] < 2:
325 return x_buffer, y_buffer, z_buffer
325 return x_buffer, y_buffer, z_buffer
326
326
327 deltas = x_buffer[1:] - x_buffer[0:-1]
327 deltas = x_buffer[1:] - x_buffer[0:-1]
328 x_median = numpy.median(deltas)
328 x_median = numpy.median(deltas)
329
329
330 index = numpy.where(deltas > 5 * x_median)
330 index = numpy.where(deltas > 5 * x_median)
331
331
332 if len(index[0]) != 0:
332 if len(index[0]) != 0:
333 z_buffer[::, index[0], ::] = self.__missing
333 z_buffer[::, index[0], ::] = self.__missing
334 z_buffer = numpy.ma.masked_inside(z_buffer,
334 z_buffer = numpy.ma.masked_inside(z_buffer,
335 0.99 * self.__missing,
335 0.99 * self.__missing,
336 1.01 * self.__missing)
336 1.01 * self.__missing)
337
337
338 return x_buffer, y_buffer, z_buffer
338 return x_buffer, y_buffer, z_buffer
339
339
340 def decimate(self):
340 def decimate(self):
341
341
342 # dx = int(len(self.x)/self.__MAXNUMX) + 1
342 # dx = int(len(self.x)/self.__MAXNUMX) + 1
343 dy = int(len(self.y) / self.decimation) + 1
343 dy = int(len(self.y) / self.decimation) + 1
344
344
345 # x = self.x[::dx]
345 # x = self.x[::dx]
346 x = self.x
346 x = self.x
347 y = self.y[::dy]
347 y = self.y[::dy]
348 z = self.z[::, ::, ::dy]
348 z = self.z[::, ::, ::dy]
349
349
350 return x, y, z
350 return x, y, z
351
351
352 def format(self):
352 def format(self):
353 '''
353 '''
354 Set min and max values, labels, ticks and titles
354 Set min and max values, labels, ticks and titles
355 '''
355 '''
356
356
357 if self.xmin is None:
357 if self.xmin is None:
358 xmin = self.data.min_time
358 xmin = self.data.min_time
359 else:
359 else:
360 if self.xaxis is 'time':
360 if self.xaxis is 'time':
361 dt = self.getDateTime(self.data.min_time)
361 dt = self.getDateTime(self.data.min_time)
362 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
362 xmin = (dt.replace(hour=int(self.xmin), minute=0, second=0) -
363 datetime.datetime(1970, 1, 1)).total_seconds()
363 datetime.datetime(1970, 1, 1)).total_seconds()
364 if self.data.localtime:
364 if self.data.localtime:
365 xmin += time.timezone
365 xmin += time.timezone
366 else:
366 else:
367 xmin = self.xmin
367 xmin = self.xmin
368
368
369 if self.xmax is None:
369 if self.xmax is None:
370 xmax = xmin + self.xrange * 60 * 60
370 xmax = xmin + self.xrange * 60 * 60
371 else:
371 else:
372 if self.xaxis is 'time':
372 if self.xaxis is 'time':
373 dt = self.getDateTime(self.data.max_time)
373 dt = self.getDateTime(self.data.max_time)
374 xmax = self.xmax - 1
374 xmax = self.xmax - 1
375 xmax = (dt.replace(hour=int(xmax), minute=59, second=59) -
375 xmax = (dt.replace(hour=int(xmax), minute=59, second=59) -
376 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
376 datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=1)).total_seconds()
377 if self.data.localtime:
377 if self.data.localtime:
378 xmax += time.timezone
378 xmax += time.timezone
379 else:
379 else:
380 xmax = self.xmax
380 xmax = self.xmax
381
381
382 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
382 ymin = self.ymin if self.ymin else numpy.nanmin(self.y)
383 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
383 ymax = self.ymax if self.ymax else numpy.nanmax(self.y)
384
384
385 for n, ax in enumerate(self.axes):
385 for n, ax in enumerate(self.axes):
386 if ax.firsttime:
386 if ax.firsttime:
387
387
388 dig = int(numpy.log10(ymax))
388 dig = int(numpy.log10(ymax))
389 if dig == 0:
389 if dig == 0:
390 digD = len(str(ymax)) - 2
390 digD = len(str(ymax)) - 2
391 ydec = ymax*(10**digD)
391 ydec = ymax*(10**digD)
392
392
393 dig = int(numpy.log10(ydec))
393 dig = int(numpy.log10(ydec))
394 ystep = ((ydec + (10**(dig)))//10**(dig))*(10**(dig))
394 ystep = ((ydec + (10**(dig)))//10**(dig))*(10**(dig))
395 ystep = ystep/5
395 ystep = ystep/5
396 ystep = ystep/(10**digD)
396 ystep = ystep/(10**digD)
397
397
398 else:
398 else:
399 ystep = ((ymax + (10**(dig)))//10**(dig))*(10**(dig))
399 ystep = ((ymax + (10**(dig)))//10**(dig))*(10**(dig))
400 ystep = ystep/5
400 ystep = ystep/5
401
401
402 if self.xaxis is not 'time':
402 if self.xaxis is not 'time':
403
403
404 dig = int(numpy.log10(xmax))
404 dig = int(numpy.log10(xmax))
405
405
406 if dig <= 0:
406 if dig <= 0:
407 digD = len(str(xmax)) - 2
407 digD = len(str(xmax)) - 2
408 xdec = xmax*(10**digD)
408 xdec = xmax*(10**digD)
409
409
410 dig = int(numpy.log10(xdec))
410 dig = int(numpy.log10(xdec))
411 xstep = ((xdec + (10**(dig)))//10**(dig))*(10**(dig))
411 xstep = ((xdec + (10**(dig)))//10**(dig))*(10**(dig))
412 xstep = xstep*0.5
412 xstep = xstep*0.5
413 xstep = xstep/(10**digD)
413 xstep = xstep/(10**digD)
414
414
415 else:
415 else:
416 xstep = ((xmax + (10**(dig)))//10**(dig))*(10**(dig))
416 xstep = ((xmax + (10**(dig)))//10**(dig))*(10**(dig))
417 xstep = xstep/5
417 xstep = xstep/5
418
418
419 ax.set_facecolor(self.bgcolor)
419 ax.set_facecolor(self.bgcolor)
420 ax.yaxis.set_major_locator(MultipleLocator(ystep))
420 ax.yaxis.set_major_locator(MultipleLocator(ystep))
421 if self.xscale:
421 if self.xscale:
422 ax.xaxis.set_major_formatter(FuncFormatter(
422 ax.xaxis.set_major_formatter(FuncFormatter(
423 lambda x, pos: '{0:g}'.format(x*self.xscale)))
423 lambda x, pos: '{0:g}'.format(x*self.xscale)))
424 if self.xscale:
424 if self.xscale:
425 ax.yaxis.set_major_formatter(FuncFormatter(
425 ax.yaxis.set_major_formatter(FuncFormatter(
426 lambda x, pos: '{0:g}'.format(x*self.yscale)))
426 lambda x, pos: '{0:g}'.format(x*self.yscale)))
427 if self.xaxis is 'time':
427 if self.xaxis is 'time':
428 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
428 ax.xaxis.set_major_formatter(FuncFormatter(self.__fmtTime))
429 ax.xaxis.set_major_locator(LinearLocator(9))
429 ax.xaxis.set_major_locator(LinearLocator(9))
430 else:
430 else:
431 ax.xaxis.set_major_locator(MultipleLocator(xstep))
431 ax.xaxis.set_major_locator(MultipleLocator(xstep))
432 if self.xlabel is not None:
432 if self.xlabel is not None:
433 ax.set_xlabel(self.xlabel)
433 ax.set_xlabel(self.xlabel)
434 ax.set_ylabel(self.ylabel)
434 ax.set_ylabel(self.ylabel)
435 ax.firsttime = False
435 ax.firsttime = False
436 if self.showprofile:
436 if self.showprofile:
437 self.pf_axes[n].set_ylim(ymin, ymax)
437 self.pf_axes[n].set_ylim(ymin, ymax)
438 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
438 self.pf_axes[n].set_xlim(self.zmin, self.zmax)
439 self.pf_axes[n].set_xlabel('dB')
439 self.pf_axes[n].set_xlabel('dB')
440 self.pf_axes[n].grid(b=True, axis='x')
440 self.pf_axes[n].grid(b=True, axis='x')
441 [tick.set_visible(False)
441 [tick.set_visible(False)
442 for tick in self.pf_axes[n].get_yticklabels()]
442 for tick in self.pf_axes[n].get_yticklabels()]
443 if self.colorbar:
443 if self.colorbar:
444 ax.cbar = plt.colorbar(
444 ax.cbar = plt.colorbar(
445 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
445 ax.plt, ax=ax, fraction=0.05, pad=0.02, aspect=10)
446 ax.cbar.ax.tick_params(labelsize=8)
446 ax.cbar.ax.tick_params(labelsize=8)
447 ax.cbar.ax.press = None
447 ax.cbar.ax.press = None
448 if self.cb_label:
448 if self.cb_label:
449 ax.cbar.set_label(self.cb_label, size=8)
449 ax.cbar.set_label(self.cb_label, size=8)
450 elif self.cb_labels:
450 elif self.cb_labels:
451 ax.cbar.set_label(self.cb_labels[n], size=8)
451 ax.cbar.set_label(self.cb_labels[n], size=8)
452 else:
452 else:
453 ax.cbar = None
453 ax.cbar = None
454 if self.grid:
454 if self.grid:
455 ax.grid(True)
455 ax.grid(True)
456
456
457 if not self.polar:
457 if not self.polar:
458 ax.set_xlim(xmin, xmax)
458 ax.set_xlim(xmin, xmax)
459 ax.set_ylim(ymin, ymax)
459 ax.set_ylim(ymin, ymax)
460 ax.set_title('{} {} {}'.format(
460 ax.set_title('{} {} {}'.format(
461 self.titles[n],
461 self.titles[n],
462 self.getDateTime(self.data.max_time).strftime(
462 self.getDateTime(self.data.max_time).strftime(
463 '%Y-%m-%d %H:%M:%S'),
463 '%Y-%m-%d %H:%M:%S'),
464 self.time_label),
464 self.time_label),
465 size=8)
465 size=8)
466 else:
466 else:
467 ax.set_title('{}'.format(self.titles[n]), size=8)
467 ax.set_title('{}'.format(self.titles[n]), size=8)
468 ax.set_ylim(0, 90)
468 ax.set_ylim(0, 90)
469 ax.set_yticks(numpy.arange(0, 90, 20))
469 ax.set_yticks(numpy.arange(0, 90, 20))
470 ax.yaxis.labelpad = 40
470 ax.yaxis.labelpad = 40
471
471
472 if self.firsttime:
472 if self.firsttime:
473 for n, fig in enumerate(self.figures):
473 for n, fig in enumerate(self.figures):
474 fig.subplots_adjust(**self.plots_adjust)
474 fig.subplots_adjust(**self.plots_adjust)
475 self.firsttime = False
475 self.firsttime = False
476
476
477 def clear_figures(self):
477 def clear_figures(self):
478 '''
478 '''
479 Reset axes for redraw plots
479 Reset axes for redraw plots
480 '''
480 '''
481
481
482 for ax in self.axes+self.pf_axes+self.cb_axes:
482 for ax in self.axes+self.pf_axes+self.cb_axes:
483 ax.clear()
483 ax.clear()
484 ax.firsttime = True
484 ax.firsttime = True
485 if ax.cbar:
485 if ax.cbar:
486 ax.cbar.remove()
486 ax.cbar.remove()
487
487
488 def __plot(self):
488 def __plot(self):
489 '''
489 '''
490 Main function to plot, format and save figures
490 Main function to plot, format and save figures
491 '''
491 '''
492
492
493 self.plot()
493 self.plot()
494 self.format()
494 self.format()
495
495
496 for n, fig in enumerate(self.figures):
496 for n, fig in enumerate(self.figures):
497 if self.nrows == 0 or self.nplots == 0:
497 if self.nrows == 0 or self.nplots == 0:
498 log.warning('No data', self.name)
498 log.warning('No data', self.name)
499 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
499 fig.text(0.5, 0.5, 'No Data', fontsize='large', ha='center')
500 fig.canvas.manager.set_window_title(self.CODE)
500 fig.canvas.manager.set_window_title(self.CODE)
501 continue
501 continue
502
502
503 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
503 fig.canvas.manager.set_window_title('{} - {}'.format(self.title,
504 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
504 self.getDateTime(self.data.max_time).strftime('%Y/%m/%d')))
505 fig.canvas.draw()
505 fig.canvas.draw()
506 if self.show:
506 if self.show:
507 fig.show()
507 fig.show()
508 figpause(0.01)
508 figpause(0.01)
509
509
510 if self.save:
510 if self.save:
511 self.save_figure(n)
511 self.save_figure(n)
512
512
513 if self.plot_server:
513 if self.plot_server:
514 self.send_to_server()
514 self.send_to_server()
515
515
516 def save_figure(self, n):
516 def save_figure(self, n):
517 '''
517 '''
518 '''
518 '''
519
519
520 if self.save_counter < self.save_period:
520 if self.save_counter < self.save_period:
521 self.save_counter += 1
521 self.save_counter += 1
522 return
522 return
523
523
524 self.save_counter = 1
524 self.save_counter = 1
525
525
526 fig = self.figures[n]
526 fig = self.figures[n]
527
527
528 if self.save_code:
528 if self.save_code:
529 if isinstance(self.save_code, str):
529 if isinstance(self.save_code, str):
530 labels = [self.save_code for x in self.figures]
530 labels = [self.save_code for x in self.figures]
531 else:
531 else:
532 labels = self.save_code
532 labels = self.save_code
533 else:
533 else:
534 labels = [self.CODE for x in self.figures]
534 labels = [self.CODE for x in self.figures]
535
535
536 figname = os.path.join(
536 figname = os.path.join(
537 self.save,
537 self.save,
538 labels[n],
538 labels[n],
539 '{}_{}.png'.format(
539 '{}_{}.png'.format(
540 labels[n],
540 labels[n],
541 self.getDateTime(self.data.max_time).strftime(
541 self.getDateTime(self.data.max_time).strftime(
542 '%Y%m%d_%H%M%S'
542 '%Y%m%d_%H%M%S'
543 ),
543 ),
544 )
544 )
545 )
545 )
546 log.log('Saving figure: {}'.format(figname), self.name)
546 log.log('Saving figure: {}'.format(figname), self.name)
547 if not os.path.isdir(os.path.dirname(figname)):
547 if not os.path.isdir(os.path.dirname(figname)):
548 os.makedirs(os.path.dirname(figname))
548 os.makedirs(os.path.dirname(figname))
549 fig.savefig(figname)
549 fig.savefig(figname)
550
550
551 if self.throttle == 0:
551 if self.throttle == 0:
552 figname = os.path.join(
552 figname = os.path.join(
553 self.save,
553 self.save,
554 '{}_{}.png'.format(
554 '{}_{}.png'.format(
555 labels[n],
555 labels[n],
556 self.getDateTime(self.data.min_time).strftime(
556 self.getDateTime(self.data.min_time).strftime(
557 '%Y%m%d'
557 '%Y%m%d'
558 ),
558 ),
559 )
559 )
560 )
560 )
561 fig.savefig(figname)
561 fig.savefig(figname)
562
562
563 def send_to_server(self):
563 def send_to_server(self):
564 '''
564 '''
565 '''
565 '''
566
566
567 if self.sender_counter < self.sender_period:
567 if self.sender_counter < self.sender_period:
568 self.sender_counter += 1
568 self.sender_counter += 1
569 return
569 return
570
570
571 self.sender_counter = 1
571 self.sender_counter = 1
572 self.data.meta['titles'] = self.titles
572 self.data.meta['titles'] = self.titles
573 retries = 2
573 retries = 2
574 while True:
574 while True:
575 self.socket.send_string(self.data.jsonify(self.plot_name, self.plot_type))
575 self.socket.send_string(self.data.jsonify(self.plot_name, self.plot_type))
576 socks = dict(self.poll.poll(5000))
576 socks = dict(self.poll.poll(5000))
577 if socks.get(self.socket) == zmq.POLLIN:
577 if socks.get(self.socket) == zmq.POLLIN:
578 reply = self.socket.recv_string()
578 reply = self.socket.recv_string()
579 if reply == 'ok':
579 if reply == 'ok':
580 log.log("Response from server ok", self.name)
580 log.log("Response from server ok", self.name)
581 break
581 break
582 else:
582 else:
583 log.warning(
583 log.warning(
584 "Malformed reply from server: {}".format(reply), self.name)
584 "Malformed reply from server: {}".format(reply), self.name)
585
585
586 else:
586 else:
587 log.warning(
587 log.warning(
588 "No response from server, retrying...", self.name)
588 "No response from server, retrying...", self.name)
589 self.socket.setsockopt(zmq.LINGER, 0)
589 self.socket.setsockopt(zmq.LINGER, 0)
590 self.socket.close()
590 self.socket.close()
591 self.poll.unregister(self.socket)
591 self.poll.unregister(self.socket)
592 retries -= 1
592 retries -= 1
593 if retries == 0:
593 if retries == 0:
594 log.error(
594 log.error(
595 "Server seems to be offline, abandoning", self.name)
595 "Server seems to be offline, abandoning", self.name)
596 self.socket = self.context.socket(zmq.REQ)
596 self.socket = self.context.socket(zmq.REQ)
597 self.socket.connect(self.plot_server)
597 self.socket.connect(self.plot_server)
598 self.poll.register(self.socket, zmq.POLLIN)
598 self.poll.register(self.socket, zmq.POLLIN)
599 time.sleep(1)
599 time.sleep(1)
600 break
600 break
601 self.socket = self.context.socket(zmq.REQ)
601 self.socket = self.context.socket(zmq.REQ)
602 self.socket.connect(self.plot_server)
602 self.socket.connect(self.plot_server)
603 self.poll.register(self.socket, zmq.POLLIN)
603 self.poll.register(self.socket, zmq.POLLIN)
604 time.sleep(0.5)
604 time.sleep(0.5)
605
605
606 def setup(self):
606 def setup(self):
607 '''
607 '''
608 This method should be implemented in the child class, the following
608 This method should be implemented in the child class, the following
609 attributes should be set:
609 attributes should be set:
610
610
611 self.nrows: number of rows
611 self.nrows: number of rows
612 self.ncols: number of cols
612 self.ncols: number of cols
613 self.nplots: number of plots (channels or pairs)
613 self.nplots: number of plots (channels or pairs)
614 self.ylabel: label for Y axes
614 self.ylabel: label for Y axes
615 self.titles: list of axes title
615 self.titles: list of axes title
616
616
617 '''
617 '''
618 raise NotImplementedError
618 raise NotImplementedError
619
619
620 def plot(self):
620 def plot(self):
621 '''
621 '''
622 Must be defined in the child class
622 Must be defined in the child class
623 '''
623 '''
624 raise NotImplementedError
624 raise NotImplementedError
625
625
626 def run(self, dataOut, **kwargs):
626 def run(self, dataOut, **kwargs):
627 '''
627 '''
628 Main plotting routine
628 Main plotting routine
629 '''
629 '''
630
630
631 if self.isConfig is False:
631 if self.isConfig is False:
632 self.__setup(**kwargs)
632 self.__setup(**kwargs)
633
633
634 t = getattr(dataOut, self.attr_time)
634 t = getattr(dataOut, self.attr_time)
635
635
636 if dataOut.useLocalTime:
636 if dataOut.useLocalTime:
637 self.getDateTime = datetime.datetime.fromtimestamp
637 self.getDateTime = datetime.datetime.fromtimestamp
638 if not self.localtime:
638 if not self.localtime:
639 t += time.timezone
639 t += time.timezone
640 else:
640 else:
641 self.getDateTime = datetime.datetime.utcfromtimestamp
641 self.getDateTime = datetime.datetime.utcfromtimestamp
642 if self.localtime:
642 if self.localtime:
643 t -= time.timezone
643 t -= time.timezone
644
644
645 if 'buffer' in self.plot_type:
645 if 'buffer' in self.plot_type:
646 if self.xmin is None:
646 if self.xmin is None:
647 self.tmin = t
647 self.tmin = t
648 self.xmin = self.getDateTime(t).hour
648 self.xmin = self.getDateTime(t).hour
649 else:
649 else:
650 self.tmin = (
650 self.tmin = (
651 self.getDateTime(t).replace(
651 self.getDateTime(t).replace(
652 hour=int(self.xmin),
652 hour=int(self.xmin),
653 minute=0,
653 minute=0,
654 second=0) - self.getDateTime(0)).total_seconds()
654 second=0) - self.getDateTime(0)).total_seconds()
655
655
656 self.data.setup()
656 self.data.setup()
657 self.isConfig = True
657 self.isConfig = True
658 if self.plot_server:
658 if self.plot_server:
659 self.context = zmq.Context()
659 self.context = zmq.Context()
660 self.socket = self.context.socket(zmq.REQ)
660 self.socket = self.context.socket(zmq.REQ)
661 self.socket.connect(self.plot_server)
661 self.socket.connect(self.plot_server)
662 self.poll = zmq.Poller()
662 self.poll = zmq.Poller()
663 self.poll.register(self.socket, zmq.POLLIN)
663 self.poll.register(self.socket, zmq.POLLIN)
664
664
665 tm = getattr(dataOut, self.attr_time)
665 tm = getattr(dataOut, self.attr_time)
666
666
667 if not dataOut.useLocalTime and self.localtime:
667 if not dataOut.useLocalTime and self.localtime:
668 tm -= time.timezone
668 tm -= time.timezone
669 if dataOut.useLocalTime and not self.localtime:
669 if dataOut.useLocalTime and not self.localtime:
670 tm += time.timezone
670 tm += time.timezone
671
671
672 if self.xaxis is 'time' and self.data and (tm - self.tmin) >= self.xrange*60*60:
672 if self.xaxis is 'time' and self.data and (tm - self.tmin) >= self.xrange*60*60:
673 self.save_counter = self.save_period
673 self.save_counter = self.save_period
674 self.__plot()
674 self.__plot()
675 self.xmin += self.xrange
675 self.xmin += self.xrange
676 if self.xmin >= 24:
676 if self.xmin >= 24:
677 self.xmin -= 24
677 self.xmin -= 24
678 self.tmin += self.xrange*60*60
678 self.tmin += self.xrange*60*60
679 self.data.setup()
679 self.data.setup()
680 self.clear_figures()
680 self.clear_figures()
681
681
682 self.data.update(dataOut, tm)
682 self.data.update(dataOut, tm)
683
683
684 if self.isPlotConfig is False:
684 if self.isPlotConfig is False:
685 self.__setup_plot()
685 self.__setup_plot()
686 self.isPlotConfig = True
686 self.isPlotConfig = True
687
687
688 if self.throttle == 0:
688 if self.throttle == 0:
689 self.__plot()
689 self.__plot()
690 else:
690 else:
691 self.__throttle_plot(self.__plot)#, coerce=coerce)
691 self.__throttle_plot(self.__plot)#, coerce=coerce)
692
692
693 def close(self):
693 def close(self):
694
694
695 if not self.data.flagNoData:
695 if self.data and not self.data.flagNoData:
696 self.save_counter = self.save_period
696 self.save_counter = self.save_period
697 self.__plot()
697 self.__plot()
698 if not self.data.flagNoData and self.pause:
698 if self.data and not self.data.flagNoData and self.pause:
699 figpause(10)
699 figpause(10)
700
700
@@ -1,207 +1,207
1 '''
1 '''
2 Base clases to create Processing units and operations, the MPDecorator
2 Base clases to create Processing units and operations, the MPDecorator
3 must be used in plotting and writing operations to allow to run as an
3 must be used in plotting and writing operations to allow to run as an
4 external process.
4 external process.
5 '''
5 '''
6
6
7 import inspect
7 import inspect
8 import zmq
8 import zmq
9 import time
9 import time
10 import pickle
10 import pickle
11 import traceback
11 import traceback
12 try:
12 try:
13 from queue import Queue
13 from queue import Queue
14 except:
14 except:
15 from Queue import Queue
15 from Queue import Queue
16 from threading import Thread
16 from threading import Thread
17 from multiprocessing import Process, Queue
17 from multiprocessing import Process, Queue
18 from schainpy.utils import log
18 from schainpy.utils import log
19
19
20
20
21 class ProcessingUnit(object):
21 class ProcessingUnit(object):
22 '''
22 '''
23 Base class to create Signal Chain Units
23 Base class to create Signal Chain Units
24 '''
24 '''
25
25
26 proc_type = 'processing'
26 proc_type = 'processing'
27
27
28 def __init__(self):
28 def __init__(self):
29
29
30 self.dataIn = None
30 self.dataIn = None
31 self.dataOut = None
31 self.dataOut = None
32 self.isConfig = False
32 self.isConfig = False
33 self.operations = []
33 self.operations = []
34
34
35 def setInput(self, unit):
35 def setInput(self, unit):
36
36
37 self.dataIn = unit.dataOut
37 self.dataIn = unit.dataOut
38
38
39 def getAllowedArgs(self):
39 def getAllowedArgs(self):
40 if hasattr(self, '__attrs__'):
40 if hasattr(self, '__attrs__'):
41 return self.__attrs__
41 return self.__attrs__
42 else:
42 else:
43 return inspect.getargspec(self.run).args
43 return inspect.getargspec(self.run).args
44
44
45 def addOperation(self, conf, operation):
45 def addOperation(self, conf, operation):
46 '''
46 '''
47 '''
47 '''
48
48
49 self.operations.append((operation, conf.type, conf.getKwargs()))
49 self.operations.append((operation, conf.type, conf.getKwargs()))
50
50
51 def getOperationObj(self, objId):
51 def getOperationObj(self, objId):
52
52
53 if objId not in list(self.operations.keys()):
53 if objId not in list(self.operations.keys()):
54 return None
54 return None
55
55
56 return self.operations[objId]
56 return self.operations[objId]
57
57
58 def call(self, **kwargs):
58 def call(self, **kwargs):
59 '''
59 '''
60 '''
60 '''
61
61
62 try:
62 try:
63 if self.dataIn is not None and self.dataIn.flagNoData and not self.dataIn.error:
63 if self.dataIn is not None and self.dataIn.flagNoData and not self.dataIn.error:
64 return self.dataIn.isReady()
64 return self.dataIn.isReady()
65 elif self.dataIn is None or not self.dataIn.error:
65 elif self.dataIn is None or not self.dataIn.error:
66 self.run(**kwargs)
66 self.run(**kwargs)
67 elif self.dataIn.error:
67 elif self.dataIn.error:
68 self.dataOut.error = self.dataIn.error
68 self.dataOut.error = self.dataIn.error
69 self.dataOut.flagNoData = True
69 self.dataOut.flagNoData = True
70 except:
70 except:
71 err = traceback.format_exc()
71 err = traceback.format_exc()
72 if 'SchainWarning' in err:
72 if 'SchainWarning' in err:
73 log.warning(err.split('SchainWarning:')[-1].split('\n')[0].strip(), self.name)
73 log.warning(err.split('SchainWarning:')[-1].split('\n')[0].strip(), self.name)
74 elif 'SchainError' in err:
74 elif 'SchainError' in err:
75 log.error(err.split('SchainError:')[-1].split('\n')[0].strip(), self.name)
75 log.error(err.split('SchainError:')[-1].split('\n')[0].strip(), self.name)
76 else:
76 else:
77 log.error(err, self.name)
77 log.error(err.split('\n')[-2], self.name)
78 self.dataOut.error = True
78 self.dataOut.error = True
79
79
80 for op, optype, opkwargs in self.operations:
80 for op, optype, opkwargs in self.operations:
81 if optype == 'other' and not self.dataOut.flagNoData:
81 if optype == 'other' and not self.dataOut.flagNoData:
82 self.dataOut = op.run(self.dataOut, **opkwargs)
82 self.dataOut = op.run(self.dataOut, **opkwargs)
83 elif optype == 'external' and not self.dataOut.flagNoData:
83 elif optype == 'external' and not self.dataOut.flagNoData:
84 op.queue.put(self.dataOut)
84 op.queue.put(self.dataOut)
85 elif optype == 'external' and self.dataOut.error:
85 elif optype == 'external' and self.dataOut.error:
86 op.queue.put(self.dataOut)
86 op.queue.put(self.dataOut)
87
87
88 return 'Error' if self.dataOut.error else self.dataOut.isReady()
88 return 'Error' if self.dataOut.error else self.dataOut.isReady()
89
89
90 def setup(self):
90 def setup(self):
91
91
92 raise NotImplementedError
92 raise NotImplementedError
93
93
94 def run(self):
94 def run(self):
95
95
96 raise NotImplementedError
96 raise NotImplementedError
97
97
98 def close(self):
98 def close(self):
99
99
100 return
100 return
101
101
102
102
103 class Operation(object):
103 class Operation(object):
104
104
105 '''
105 '''
106 '''
106 '''
107
107
108 proc_type = 'operation'
108 proc_type = 'operation'
109
109
110 def __init__(self):
110 def __init__(self):
111
111
112 self.id = None
112 self.id = None
113 self.isConfig = False
113 self.isConfig = False
114
114
115 if not hasattr(self, 'name'):
115 if not hasattr(self, 'name'):
116 self.name = self.__class__.__name__
116 self.name = self.__class__.__name__
117
117
118 def getAllowedArgs(self):
118 def getAllowedArgs(self):
119 if hasattr(self, '__attrs__'):
119 if hasattr(self, '__attrs__'):
120 return self.__attrs__
120 return self.__attrs__
121 else:
121 else:
122 return inspect.getargspec(self.run).args
122 return inspect.getargspec(self.run).args
123
123
124 def setup(self):
124 def setup(self):
125
125
126 self.isConfig = True
126 self.isConfig = True
127
127
128 raise NotImplementedError
128 raise NotImplementedError
129
129
130 def run(self, dataIn, **kwargs):
130 def run(self, dataIn, **kwargs):
131 """
131 """
132 Realiza las operaciones necesarias sobre la dataIn.data y actualiza los
132 Realiza las operaciones necesarias sobre la dataIn.data y actualiza los
133 atributos del objeto dataIn.
133 atributos del objeto dataIn.
134
134
135 Input:
135 Input:
136
136
137 dataIn : objeto del tipo JROData
137 dataIn : objeto del tipo JROData
138
138
139 Return:
139 Return:
140
140
141 None
141 None
142
142
143 Affected:
143 Affected:
144 __buffer : buffer de recepcion de datos.
144 __buffer : buffer de recepcion de datos.
145
145
146 """
146 """
147 if not self.isConfig:
147 if not self.isConfig:
148 self.setup(**kwargs)
148 self.setup(**kwargs)
149
149
150 raise NotImplementedError
150 raise NotImplementedError
151
151
152 def close(self):
152 def close(self):
153
153
154 return
154 return
155
155
156
156
157 def MPDecorator(BaseClass):
157 def MPDecorator(BaseClass):
158 """
158 """
159 Multiprocessing class decorator
159 Multiprocessing class decorator
160
160
161 This function add multiprocessing features to a BaseClass.
161 This function add multiprocessing features to a BaseClass.
162 """
162 """
163
163
164 class MPClass(BaseClass, Process):
164 class MPClass(BaseClass, Process):
165
165
166 def __init__(self, *args, **kwargs):
166 def __init__(self, *args, **kwargs):
167 super(MPClass, self).__init__()
167 super(MPClass, self).__init__()
168 Process.__init__(self)
168 Process.__init__(self)
169
169
170 self.args = args
170 self.args = args
171 self.kwargs = kwargs
171 self.kwargs = kwargs
172 self.t = time.time()
172 self.t = time.time()
173 self.op_type = 'external'
173 self.op_type = 'external'
174 self.name = BaseClass.__name__
174 self.name = BaseClass.__name__
175 self.__doc__ = BaseClass.__doc__
175 self.__doc__ = BaseClass.__doc__
176
176
177 if 'plot' in self.name.lower() and not self.name.endswith('_'):
177 if 'plot' in self.name.lower() and not self.name.endswith('_'):
178 self.name = '{}{}'.format(self.CODE.upper(), 'Plot')
178 self.name = '{}{}'.format(self.CODE.upper(), 'Plot')
179
179
180 self.start_time = time.time()
180 self.start_time = time.time()
181 self.err_queue = args[3]
181 self.err_queue = args[3]
182 self.queue = Queue(maxsize=1)
182 self.queue = Queue(maxsize=1)
183 self.myrun = BaseClass.run
183 self.myrun = BaseClass.run
184
184
185 def run(self):
185 def run(self):
186
186
187 while True:
187 while True:
188
188
189 dataOut = self.queue.get()
189 dataOut = self.queue.get()
190
190
191 if not dataOut.error:
191 if not dataOut.error:
192 try:
192 try:
193 BaseClass.run(self, dataOut, **self.kwargs)
193 BaseClass.run(self, dataOut, **self.kwargs)
194 except:
194 except:
195 err = traceback.format_exc()
195 err = traceback.format_exc()
196 log.error(err.split('\n')[-2], self.name)
196 log.error(err.split('\n')[-2], self.name)
197 else:
197 else:
198 break
198 break
199
199
200 self.close()
200 self.close()
201
201
202 def close(self):
202 def close(self):
203
203
204 BaseClass.close(self)
204 BaseClass.close(self)
205 log.success('Done...(Time:{:4.2f} secs)'.format(time.time()-self.start_time), self.name)
205 log.success('Done...(Time:{:4.2f} secs)'.format(time.time()-self.start_time), self.name)
206
206
207 return MPClass
207 return MPClass
General Comments 0
You need to be logged in to leave comments. Login now