source: branches/alma/python/interactivemask.py@ 1556

Last change on this file since 1556 was 1498, checked in by Kana Sugimoto, 16 years ago

New Development: No

JIRA Issue: No

Ready to Release: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): tasks which call interactivemask,

i.e., sdbaseline and sdstat.

Description:

Fixed a bug reported from CASA tutorial in Chille.
Made sure mask regions are deleted from the plot when no
region is selected.

File size: 6.5 KB
Line 
1from asap import rcParams
2from asap import _n_bools, mask_and, mask_or
3from asap.scantable import scantable
4
5class interactivemask:
6 """
7 The class for interactive mask selection.
8
9 Example:
10 new_mask=interactivemask()
11 new_mask.select_mask(scan,masklist=[[0,10],[90,100]],invert=False)
12 mask=new_mask.get_mask()
13
14 Modify mask region by selecting a region on a plot with mouse.
15 """
16
17 def __init__(self):
18 """
19 Create a interactive masking object
20 """
21 self.scan=None
22 self.rect={}
23 self.xold=None
24 self.yold=None
25 self.xdataold=None
26 self.ydataold=None
27 self.mask=None
28 self._polygons=[]
29 self._p=None
30
31 def select_mask(self,scan,masklist=[],invert=False):
32 """
33 Do interactive mask selection.
34 Calculate initial channel mask based on the parameters and modify
35 it interactively by adding/deleting regions with mouse drawing.
36 When finish modifying, press <Return> to calculate the final mask.
37
38 Parameters:
39 scan: a scantable
40 masklist: [[min, max], [min2, max2], ...]
41 A list of pairs of start/end points (inclusive)
42 specifying the regions to be masked
43 invert: optional argument. If specified as True,
44 return an inverted mask, i.e. the regions
45 specified are excluded
46
47 Interactive region selection is available only when GUI plotter
48 is active. When GUI plotter is disabled, this method only
49 calculates a initial channel mask.
50 """
51 # Verify input parameters
52 if not isinstance(scan, scantable):
53 msg = 'Input is not a scantable'
54 raise TypeError(msg)
55 if not (isinstance(masklist, list) or isinstance(masklist, tuple)) \
56 or not isinstance(invert, bool):
57 msg = 'Invalid mask definition'
58 raise TypeError(msg)
59
60 self.scan=scan
61
62 # Create initial mask
63 if ( len(masklist) > 0 ):
64 self.mask=self.scan.create_mask(masklist,invert=invert)
65 else:
66 self.mask=_n_bools(self.scan.nchan(),True)
67
68 # Return if GUI is not active
69 if not rcParams['plotter.gui']:
70 print 'GUI plotter is disabled.\n'
71 print 'Exit interactive mode.'
72 return
73
74 # Plot selected spectra
75 if not self._p or self._p.is_dead:
76 from asap.asapplotter import asapplotter
77 plotter=asapplotter()
78 self._p = plotter._plotter
79 plotter.plot(self.scan)
80 for panel in self._p.subplots:
81 xmin, xmax = panel['axes'].get_xlim()
82 marg = 0.05*(xmax-xmin)
83 panel['axes'].set_xlim(xmin-marg, xmax+marg)
84 self._p.show()
85 self._plot_mask()
86
87 print ''
88 print 'Masked regions are shaded with yellow. (gray: projections)'
89 print 'Now you can modify mask regions.'
90 print 'Draw rectangles with Left-mouse to add Mask region,'
91 print 'or with Right-mouse to UNMask region.'
92
93 cid = None
94 cid = self._p.canvas.mpl_connect('button_press_event', self._region_start)
95 finish=raw_input('Press return to calculate statistics.\n')
96 if cid is not None:
97 self._p.canvas.mpl_disconnect(cid)
98
99 # Finish the plot
100 self._p.unmap()
101 self._p = None
102 del plotter
103
104 def _region_start(self,event):
105 # Do not fire event when in zooming/panning mode
106 mode = self._p.figmgr.toolbar.mode
107 if not mode =='':
108 return
109 # Return if selected point is out of panel
110 if event.inaxes == None: return
111 # Select mask/unmask region with mask
112 height = self._p.canvas.figure.bbox.height()
113 self.rect = {'button': event.button, 'axes': event.inaxes,
114 'fig': None, 'height': height,
115 'x': event.x, 'y': height - event.y,
116 'world': [event.xdata, event.ydata,
117 event.xdata, event.ydata],
118 'pixel': [event.x, height - event.y,
119 event.x, height -event.y]}
120 self._p.register('motion_notify', self._region_draw)
121 self._p.register('button_release', self._region_end)
122
123 def _region_draw(self,event):
124 self._p.canvas._tkcanvas.delete(self.rect['fig'])
125 sameaxes=(event.inaxes == self.rect['axes'])
126 if sameaxes:
127 xnow=event.x
128 ynow=event.y
129 self.xold=xnow
130 self.yold=ynow
131 self.xdataold=event.xdata
132 self.ydataold=event.ydata
133 else:
134 xnow=self.xold
135 ynow=self.yold
136
137 self.rect['fig'] = self._p.canvas._tkcanvas.create_rectangle(
138 self.rect['x'], self.rect['y'],
139 xnow, self.rect['height'] - ynow)
140
141 def _region_end(self,event):
142 height = self._p.canvas.figure.bbox.height()
143 self._p.register('motion_notify', None)
144 self._p.register('button_release', None)
145
146 self._p.canvas._tkcanvas.delete(self.rect['fig'])
147
148 if event.inaxes == self.rect['axes']:
149 xend=event.x
150 yend=event.y
151 xdataend=event.xdata
152 ydataend=event.ydata
153 else:
154 xend=self.xold
155 yend=self.yold
156 xdataend=self.xdataold
157 ydataend=self.ydataold
158
159 self.rect['world'][2:4] = [xdataend, ydataend]
160 self.rect['pixel'][2:4] = [xend, height - yend]
161 self._update_mask()
162
163 def _update_mask(self):
164 # Min and Max for new mask
165 xstart=self.rect['world'][0]
166 xend=self.rect['world'][2]
167 if xstart <= xend: newlist=[xstart,xend]
168 else: newlist=[xend,xstart]
169 # Mask or unmask
170 invmask=None
171 if self.rect['button'] == 1:
172 invmask=False
173 mflg='Mask'
174 elif self.rect['button'] == 3:
175 invmask=True
176 mflg='UNmask'
177 print mflg+': ',newlist
178 newmask=self.scan.create_mask(newlist,invert=invmask)
179 # Logic operation to update mask
180 if invmask:
181 self.mask=mask_and(self.mask,newmask)
182 else:
183 self.mask=mask_or(self.mask,newmask)
184 # Plot masked regions
185 self._plot_mask()
186
187 # Plot masked regions
188 def _plot_mask(self):
189 msks = []
190 msks = self.scan.get_masklist(self.mask,row=0)
191 # Get projection masks for multi-IF
192 ifs=self.scan.getifnos()
193 projs = []
194 if len(ifs) > 1:
195 row0if=self.scan.getif(0)
196 for ifno in ifs:
197 if ifno == row0if: continue
198 for row in xrange(self.scan.nrow()):
199 if self.scan.getif(row) == ifno:
200 projs.append(self.scan.get_masklist(self.mask,row=row))
201 break
202 if len(self._polygons)>0:
203 # Remove old polygons
204 for polygon in self._polygons: polygon.remove()
205 self._polygons=[]
206 # Plot new polygons
207 if len(msks) > 0:
208 npanel=len(self._p.subplots)
209 j=-1
210 for iloop in range(len(msks)*npanel):
211 i = iloop % len(msks)
212 if i == 0 : j += 1
213 if len(ifs) > 1:
214 for k in xrange(len(ifs)-1):
215 self._polygons.append(self._p.subplots[j]['axes'].axvspan(projs[k][i][0],projs[k][i][1],facecolor='#aaaaaa'))
216 self._polygons.append(self._p.subplots[j]['axes'].axvspan(msks[i][0],msks[i][1],facecolor='yellow'))
217 self._p.canvas.draw()
218
219 def get_mask(self):
220 """
221 Get the interactively selected channel mask.
222 Returns:
223 A list of channel mask.
224 """
225 return self.mask
226
Note: See TracBrowser for help on using the repository browser.