source: trunk/python/edgemarker.py@ 2829

Last change on this file since 2829 was 2635, checked in by Takeshi Nakazato, 12 years ago

New Development: No

JIRA Issue: Yes CAS-2825

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Added optional plot method.


File size: 7.7 KB
Line 
1from asap.scantable import scantable
2from asap._asap import _edgemarker
3import numpy
4import math
5
6class edgemarker:
7 """
8 The edgemarker is a helper tool to calibrate OTF observation
9 without explicit OFF scans. According to a few user-specified
10 options, the class automatically detects an edge region of the
11 map and mark integrations within this region as OFF.
12
13 The edgemarker supports raster pattern as well as other generic
14 ones (e.g. lissajous, double circle). The constructor takes
15 one boolean parameter to specify whether scan pattern is raster
16 or not. This is because that edge detection algorithms for raster
17 and others are different.
18
19 Current limitation of this class is that it cannot handle some
20 complicated observed area. Typical case is that the area has
21 clear 'dent' (e.g. a composite area consisting of two diamond-
22 shaped areas that slightly overlap). In such case, the class
23 will fail to detect such feature.
24
25 Note that the class takes a copy of input data so that input
26 data will not be overwritten. Result will be provided as a
27 separate data whose contents are essentially the same as input
28 except for that some integrations are marked as OFF.
29
30 Here is typical usage:
31
32 s = scantable( 'otf.asap', average=False )
33 marker = edgemarker( israster=False )
34 marker.setdata( s )
35 marker.setoption( fraction='15%', width=0.5 )
36 marker.mark()
37
38 # get result as scantable instance
39 s2 = marker.getresult()
40
41 # save result on disk
42 marker.save( 'otfwithoff.asap', overwrite=True )
43 """
44 def __init__( self, israster=False ):
45 """
46 Constructor.
47
48 israster -- Whether scan pattern is raster or not. Set True
49 if scan pattern is raster. Default is False.
50 """
51 self.israster = israster
52 self.marker = _edgemarker( self.israster )
53 self.st = None
54
55 def setdata( self, st ):
56 """
57 Set data to be processed.
58
59 st -- Data as scantable instance.
60 """
61 self.st = st
62 self.marker._setdata( self.st, False )
63 self.marker._examine()
64
65 def setoption( self, *args, **kwargs ):
66 """
67 Set options for edge detection. Valid options depend on
68 whether scan pattern is raster or not (i.e. constructor
69 is called with israster=True or False).
70
71 === for raster (israster=True) ===
72 fraction -- Fraction of OFF integration in each raster
73 row. Either numerical value (<1.0) or string
74 is accepted. For string, its value should be
75 'auto' or format 'xx%'. For example, '10%'
76 is same as 0.1. The 'auto' option estimates
77 number of OFFs based on t_OFF = sqrt(N) t_ON.
78 Default is 0.1.
79 npts -- Number of OFF integration in each raster row.
80 Default is -1 (use fraction).
81
82 Note that number of integrations specified by the above
83 parameters will be marked as OFF from both ends. So, twice
84 of specified number/fraction will be marked as OFF. For
85 example, if you specify fraction='10%', resultant fraction
86 of OFF integrations will be 20%.
87
88 Note also that, if both fraction and npts are specified,
89 specification by npts will come before.
90
91 === for non-raster (israster=False) ===
92 fraction -- Fraction of edge area with respect to whole
93 observed area. Either numerical value (<1.0)
94 or string is accepted. For string, its value
95 should be in 'xx%' format. For example, '10%'
96 is same as 0.1. Default is 0.1.
97 width -- Pixel width for edge detection. It should be given
98 as a fraction of the median spatial separation
99 between neighboring integrations in time. Default
100 is 0.5. In the most case, default value will be fine.
101 Larger value will cause worse result. Smaller value
102 may improve result. However, if too small value is
103 set (e.g. 1.0e-5), the algorithm may not work.
104 elongated -- Set True only if observed area is extremely
105 elongated in one direction. Default is False.
106 In most cases, default value will be fine.
107 """
108 option = {}
109 if self.israster:
110 keys = [ 'fraction', 'npts' ]
111 else:
112 keys = [ 'fraction', 'width', 'elongated' ]
113 for key in keys:
114 if kwargs.has_key( key ):
115 option[key] = kwargs[key]
116
117 if len(option) > 0:
118 self.marker._setoption( option )
119
120 def mark( self ):
121 """
122 Process data. Edge region is detected according to detection
123 parameters given by setoption(). Then, integrations within
124 edge region will be marked as OFF.
125 """
126 self.marker._detect()
127 self.marker._mark()
128
129 def getresult( self ):
130 """
131 Get result as scantable instance. Returned scantable is
132 copy of input scantable except for that some data are
133 marked as OFF as a result of edge detection and marking.
134 """
135 return scantable( self.marker._get() )
136
137 def save( self, name, overwrite=False ):
138 """
139 Save result as scantable.
140
141 name -- Name of the scantable.
142 overwrite -- Overwrite existing data if True. Default is
143 False.
144 """
145 s = self.getresult()
146 s.save( name, overwrite=overwrite )
147
148 def plot( self ):
149 """
150 """
151 from matplotlib import pylab as pl
152 from asap import selector
153 from asap._asap import srctype as st
154 pl.clf()
155
156 # result as a scantable
157 s = self.getresult()
158
159 # ON scan
160 sel = selector()
161 sel.set_types( int(st.pson) )
162 s.set_selection( sel )
163 diron = numpy.array( s.get_directionval() ).transpose()
164 diron[0] = rotate( diron[0] )
165 s.set_selection()
166 sel.reset()
167
168 # OFF scan
169 sel.set_types( int(st.psoff) )
170 s.set_selection( sel )
171 diroff = numpy.array( s.get_directionval() ).transpose()
172 diroff[0] = rotate( diroff[0] )
173 s.set_selection()
174 sel.reset()
175 del s
176 del sel
177
178 # plot
179 pl.ioff()
180 ax=pl.axes()
181 ax.set_aspect(1.0)
182 pl.plot( diron[0], diron[1], '.', color='blue', label='ON' )
183 pl.plot( diroff[0], diroff[1], '.', color='green', label='OFF' )
184 [xmin,xmax,ymin,ymax] = pl.axis()
185 pl.axis([xmax,xmin,ymin,ymax])
186 pl.legend(loc='best',prop={'size':'small'},numpoints=1)
187 pl.xlabel( 'R.A. [rad]' )
188 pl.ylabel( 'Declination [rad]' )
189 pl.title( 'edgemarker result' )
190 pl.ion()
191 pl.draw()
192
193def _0to2pi( v ):
194 return v % (2.0*math.pi)
195
196def quadrant( v ):
197 vl = _0to2pi( v )
198 base = 0.5 * math.pi
199 return int( vl / base )
200
201def quadrantList( a ):
202 n = len(a)
203 nquad = numpy.zeros( 4, dtype=int )
204 for i in xrange(n):
205 v = quadrant( a[i] )
206 nquad[v] += 1
207 #print nquad
208 return nquad
209
210def rotate( v ):
211 a = numpy.zeros( len(v), dtype=float )
212 for i in xrange(len(v)):
213 a[i] = _0to2pi( v[i] )
214 nquad = quadrantList( a )
215 quadList = [[],[],[],[]]
216 rot = numpy.zeros( 4, dtype=bool )
217 if all( nquad==0 ):
218 print 'no data'
219 elif all( nquad>0 ):
220 #print 'extends in all quadrants'
221 pass
222 elif nquad[0]>0 and nquad[3]>0:
223 #print 'need rotation'
224 rot[3] = True
225 rot[2] = nquad[1]==0 and nquad[2]>0
226 #print rot
227
228 for i in xrange(len(a)):
229 if rot[quadrant(a[i])]:
230 a[i] -= 2*math.pi
231 return a
Note: See TracBrowser for help on using the repository browser.