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

Last change on this file since 1498 was 1498, checked in by Kana Sugimoto, 15 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.