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

Last change on this file since 1460 was 1460, checked in by Kana Sugimoto, 15 years ago

New Development: Yes

JIRA Issue: Yes (CAS-1080)

Ready to Release: Yes

Interface Changes: Yes

What Interface Changed: This is a brand new module.

Test Programs:

#from ASAP
scan=scantable('A_FILE_NAME') # Read spectral data from 'A_FILE_NAME'.
new_mask=interactivemask() # Create a interactive masking object
new_mask.select_mask(scan) # Do interactive mask selection
mask=new_mask.get_mask() # Get a final channel mask

Put in Release Notes: No

Description:

The class for interactive mask selection, 'interactivemask', is used
to hard coded in CASA tasks 'sdbaseline' and 'sdstat'.
I moved the class from the tasks and defined as a new ASAP module.


File size: 6.6 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._plot_mask()
85
86                print ''
87                print 'Masked regions are shaded with yellow. (gray: projections)'
88                print 'Now you can modify mask regions.'
89                print 'Draw rectangles with Left-mouse to add Mask region,'
90                print 'or with Right-mouse to UNMask region.'
91               
92                cid = None
93                cid = self._p.canvas.mpl_connect('button_press_event', self._region_start)
94                finish=raw_input('Press return to calculate statistics.\n')
95                if cid is not None:
96                        self._p.canvas.mpl_disconnect(cid)
97
98                # Finish the plot
99                self._p.unmap()
100                self._p = None
101                del plotter
102
103        def _region_start(self,event):
104                # Do not fire event when in zooming/panning mode
105                mode = self._p.figmgr.toolbar.mode
106                if not mode =='':
107                        return
108                # Return if selected point is out of panel
109                if event.inaxes == None: return
110                # Select mask/unmask region with mask
111                height = self._p.canvas.figure.bbox.height()
112                self.rect = {'button': event.button, 'axes': event.inaxes,
113                             'fig': None, 'height': height,
114                             'x': event.x, 'y': height - event.y,
115                             'world': [event.xdata, event.ydata,
116                                       event.xdata, event.ydata],
117                             'pixel': [event.x, height - event.y,
118                                       event.x, height -event.y]}
119                self._p.register('motion_notify', self._region_draw)
120                self._p.register('button_release', self._region_end)
121
122        def _region_draw(self,event):
123                self._p.canvas._tkcanvas.delete(self.rect['fig'])
124                sameaxes=(event.inaxes == self.rect['axes'])
125                if sameaxes:
126                        xnow=event.x
127                        ynow=event.y
128                        self.xold=xnow
129                        self.yold=ynow
130                        self.xdataold=event.xdata
131                        self.ydataold=event.ydata
132                else:
133                        xnow=self.xold
134                        ynow=self.yold
135                       
136                self.rect['fig'] = self._p.canvas._tkcanvas.create_rectangle(
137                        self.rect['x'], self.rect['y'],
138                        xnow, self.rect['height'] - ynow)
139
140        def _region_end(self,event):
141                height = self._p.canvas.figure.bbox.height()
142                self._p.register('motion_notify', None)
143                self._p.register('button_release', None)
144               
145                self._p.canvas._tkcanvas.delete(self.rect['fig'])
146               
147                if event.inaxes == self.rect['axes']:
148                        xend=event.x
149                        yend=event.y
150                        xdataend=event.xdata
151                        ydataend=event.ydata
152                else:
153                        xend=self.xold
154                        yend=self.yold
155                        xdataend=self.xdataold
156                        ydataend=self.ydataold
157                       
158                self.rect['world'][2:4] = [xdataend, ydataend]
159                self.rect['pixel'][2:4] = [xend, height - yend]
160                self._update_mask()
161
162        def _update_mask(self):
163                # Min and Max for new mask
164                xstart=self.rect['world'][0]
165                xend=self.rect['world'][2]
166                if xstart <= xend: newlist=[xstart,xend]
167                else: newlist=[xend,xstart]
168                # Mask or unmask
169                invmask=None
170                if self.rect['button'] == 1:
171                        invmask=False
172                        mflg='Mask'
173                elif self.rect['button'] == 3:
174                        invmask=True
175                        mflg='UNmask'
176                print mflg+': ',newlist
177                newmask=self.scan.create_mask(newlist,invert=invmask)
178                # Logic operation to update mask
179                if invmask:
180                        self.mask=mask_and(self.mask,newmask)
181                else:
182                        self.mask=mask_or(self.mask,newmask)
183                # Plot masked regions
184                self._plot_mask()
185
186        # Plot masked regions
187        def _plot_mask(self):
188                msks = []
189                msks = self.scan.get_masklist(self.mask,row=0)
190                # Get projection masks for multi-IF
191                ifs=self.scan.getifnos()
192                projs = []
193                if len(ifs) > 1:
194                        row0if=self.scan.getif(0)
195                        for ifno in ifs:
196                                if ifno == row0if: continue
197                                for row in xrange(self.scan.nrow()):
198                                        if self.scan.getif(row) == ifno:
199                                                projs.append(self.scan.get_masklist(self.mask,row=row))
200                                                break
201                if len(self._polygons)>0:
202                        # Remove old polygons
203                        for polygon in self._polygons: polygon.remove()
204                        self._polygons=[]
205                # Plot new polygons
206                if len(msks) < 1: return
207                npanel=len(self._p.subplots)
208                j=-1
209                for iloop in range(len(msks)*npanel):
210                        i = iloop % len(msks)
211                        if  i == 0 : j += 1
212                        if len(ifs) > 1:
213                                for k in xrange(len(ifs)-1):
214                                        self._polygons.append(self._p.subplots[j]['axes'].axvspan(projs[k][i][0],projs[k][i][1],facecolor='#aaaaaa'))                   
215                        self._polygons.append(self._p.subplots[j]['axes'].axvspan(msks[i][0],msks[i][1],facecolor='yellow'))
216                self._p.show()
217
218        def get_mask(self):
219                """
220                Get the interactively selected channel mask.
221                Returns:
222                    A list of channel mask.
223                """
224                return self.mask
225
Note: See TracBrowser for help on using the repository browser.