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

Last change on this file since 1767 was 1767, checked in by Kana Sugimoto, 14 years ago

New Development: No

JIRA Issue: No (no effect)

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs:

Put in Release Notes: No

Module(s): None

Description: Just removed dead lines


File size: 10.3 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           my_mask=interactivemask(plotter,scan)
11           my_mask.set_basemask(masklist=[[0,10],[90,100]],invert=False)
12           # Do interactive mask selection
13           my_mask.select_mask()
14           finish=raw_input('Press return to finish selection.\n')
15           my_mask.finish_selection(callback=func)
16           mask=my_mask.get_mask()
17           
18        Modify mask region by selecting a region on a plot with mouse.
19        """
20
21        def __init__(self,plotter=None, scan=None):
22                """
23                Create a interactive masking object.
24                Either or both 'plotter' or/and 'scan' should be defined.
25
26                Parameters:
27                   plotter: an ASAP plotter object for interactive selection
28                   scan: a scantable to create a mask interactively
29                """
30                # Return if GUI is not active
31                if not rcParams['plotter.gui']:
32                        print 'GUI plotter is disabled.\n'
33                        print 'Exit interactive mode.'
34                        return
35                # Verify input parameters
36                if scan is None and plotter is None:
37                        msg = "Either scantable or plotter should be defined."
38                        raise TypeError(msg)
39
40                self.scan=None
41                self.p=None
42                self.newplot=False
43                if scan and isinstance(scan, scantable):
44                        self.scan=scan
45                from asap.asapplotter import asapplotter
46                if plotter and isinstance(plotter,asapplotter):
47                        self.p = plotter
48                        if self.scan is None and isinstance(self.p._data,scantable):
49                                self.scan=self.p._data
50                if self.scan is None:
51                        msg = "Invalid scantable."
52                        raise TypeError(msg)
53
54                self.mask=_n_bools(self.scan.nchan(),True)
55                self.callback=None
56                self.event=None
57                self.once=False
58                self.showmask=True
59                self.rect={}
60                self.xold=None
61                self.yold=None
62                self.xdataold=None
63                self.ydataold=None
64                self._polygons=[]
65       
66
67        def set_basemask(self,masklist=[],invert=False):
68                """
69                Set initial channel mask.
70               
71                Parameters:
72                    masklist:  [[min, max], [min2, max2], ...]
73                               A list of pairs of start/end points (inclusive)
74                               specifying the regions to be masked
75                    invert:    optional argument. If specified as True,
76                               return an inverted mask, i.e. the regions
77                               specified are excluded
78                You can reset the mask selection by running this method with
79                the default parameters.
80                """
81                # Verify input parameters
82                if not (isinstance(masklist, list) or isinstance(masklist, tuple)) \
83                   or not isinstance(invert, bool):
84                        msg = 'Invalid mask definition'
85                        raise TypeError(msg)
86
87                # Create base mask
88                if ( len(masklist) > 0 ):
89                        self.mask=self.scan.create_mask(masklist,invert=invert)
90                elif invert==True:
91                        self.mask=_n_bools(self.scan.nchan(),False)
92                else:
93                        self.mask=_n_bools(self.scan.nchan(),True)
94
95
96        def set_startevent(self,event):
97                """
98                Inherit an event from the parent function.
99               
100                Parameters:
101                    event: 'button_press_event' object to be inherited to
102                           start interactive region selection .
103                """
104                from matplotlib.backend_bases import MouseEvent
105                if isinstance(event,MouseEvent) and event.name=='button_press_event':
106                        self.event=event
107                else:
108                        msg="Invalid event."
109                        raise TypeError(msg)   
110
111        def set_callback(self,callback):
112                """
113                Set callback function to run when finish_selection() is executed.
114                    callback: The post processing function to run after
115                              the mask selections are completed.
116                              This will be overwritten if callback is defined in
117                              finish_selection(callback=func)
118                """
119                self.callback=callback
120
121        def select_mask(self,once=False,showmask=True):
122                """
123                Do interactive mask selection.
124                Modify masks interactively by adding/deleting regions with
125                mouse drawing.(left-button: mask; right-button: UNmask)
126                Note that the interactive region selection is available only
127                when GUI plotter is active.
128
129                Parameters:
130                    once:     If specified as True, you can modify masks only
131                              once. Else if False, you can modify them repeatedly.
132                    showmask: If specified as True, the masked regions are plotted
133                              on the plotter.
134                              Note this parameter is valid only when once=True.
135                              Otherwise, maskes are forced to be plotted for reference.
136                """
137                # Return if GUI is not active
138                if not rcParams['plotter.gui']:
139                        print 'GUI plotter is disabled.\n'
140                        print 'Exit interactive mode.'
141                        return
142
143                self.once = once
144                if self.once:
145                        self.showmask=showmask
146                else:
147                        if not showmask: print 'Warning: showmask spcification is ignored. Mask regions are plotted anyway.'
148                        self.showmask=True
149
150                #if not self.p._plotter or self.p._plotter.is_dead:
151                if not self.p or self.p._plotter.is_dead:
152                        print 'A new ASAP plotter will be loaded'
153                        from asap.asapplotter import asapplotter
154                        self.p=asapplotter()
155                        self.newplot=True
156
157                # Plot selected spectra if needed
158                if self.scan != self.p._data:
159                        # Need replot
160                        self.p.plot(self.scan)
161                        # disable casa toolbar
162                        if self.p._plotter.figmgr.casabar:  self.p._plotter.figmgr.casabar.disable_button()
163                        for panel in self.p._plotter.subplots:
164                                xmin, xmax = panel['axes'].get_xlim()
165                                marg = 0.05*abs(xmax-xmin)
166                                panel['axes'].set_xlim(xmin-marg, xmax+marg)
167                                if rcParams['plotter.ganged']: break
168                        self.p._plotter.show()
169
170                # Plot initial mask region
171                #if self.showmask or not self.once:
172                if self.showmask:
173                        self._plot_mask()
174                        print ''
175                        print 'Selected regions are shaded with yellow. (gray: projections)'
176                        print 'Now you can modify the selection.'
177                        print 'Draw rectangles with Left-mouse to add the regions,'
178                        print 'or with Right-mouse to exclude the regions.'
179
180
181                if self.event != None:
182                        self._region_start(self.event)
183                else:
184                        self.p._plotter.register('button_press',None)
185                        self.p._plotter.register('button_press',self._region_start)
186
187
188        def _region_start(self,event):
189                # Do not fire event when in zooming/panning mode
190                mode = self.p._plotter.figmgr.toolbar.mode
191                if not mode =='':
192                        return
193                # Return if selected point is out of panel
194                if event.inaxes == None: return
195                # Select mask/unmask region with mask
196                self.rect = {'button': event.button, 'axes': event.inaxes,
197                             'x': event.x, 'y': event.y,
198                             'world': [event.xdata, event.ydata,
199                                       event.xdata, event.ydata],
200                             'pixel': [event.x, event.y,
201                                       event.x, event.y]}
202                self.p._plotter.register('motion_notify', self._region_draw)
203                self.p._plotter.register('button_release', self._region_end)
204
205        def _region_draw(self,event):
206                sameaxes=(event.inaxes == self.rect['axes'])
207                if sameaxes:
208                        xnow=event.x
209                        ynow=event.y
210                        self.xold=xnow
211                        self.yold=ynow
212                        self.xdataold=event.xdata
213                        self.ydataold=event.ydata
214                else:
215                        xnow=self.xold
216                        ynow=self.yold
217
218                self.p._plotter.figmgr.toolbar.draw_rubberband(event, xnow, ynow, self.rect['x'], self.rect['y'])
219
220        def _region_end(self,event):
221                self.p._plotter.register('motion_notify', None)
222                self.p._plotter.register('button_release', None)
223
224                # Delete the rubber band
225                self.p._plotter.figmgr.toolbar.release(event)
226               
227                if event.inaxes == self.rect['axes']:
228                        xend=event.x
229                        yend=event.y
230                        xdataend=event.xdata
231                        ydataend=event.ydata
232                else:
233                        xend=self.xold
234                        yend=self.yold
235                        xdataend=self.xdataold
236                        ydataend=self.ydataold
237                       
238                self.rect['world'][2:4] = [xdataend, ydataend]
239                self.rect['pixel'][2:4] = [xend, yend]
240                self._update_mask()
241                # Clear up region selection
242                self.rect={}
243                self.xold=None
244                self.yold=None
245                self.xdataold=None
246                self.ydataold=None
247                if self.once: self.finish_selection(callback=self.callback)
248
249        def _update_mask(self):
250                # Min and Max for new mask
251                xstart=self.rect['world'][0]
252                xend=self.rect['world'][2]
253                if xstart <= xend: newlist=[xstart,xend]
254                else: newlist=[xend,xstart]
255                # Mask or unmask
256                invmask=None
257                if self.rect['button'] == 1:
258                        invmask=False
259                        mflg='Mask'
260                elif self.rect['button'] == 3:
261                        invmask=True
262                        mflg='UNmask'
263                print mflg+': ',newlist
264                newmask=self.scan.create_mask(newlist,invert=invmask)
265                # Logic operation to update mask
266                if invmask:
267                        self.mask=mask_and(self.mask,newmask)
268                else:
269                        self.mask=mask_or(self.mask,newmask)
270                # Plot masked regions
271                #if self.showmask or not self.once: self._plot_mask()
272                if self.showmask: self._plot_mask()
273
274        # Plot masked regions
275        def _plot_mask(self):
276                msks = []
277                msks = self.scan.get_masklist(self.mask,row=0)
278                # Get projection masks for multi-IF
279                ifs=self.scan.getifnos()
280                projs = []
281                if len(ifs) > 1:
282                        row0if=self.scan.getif(0)
283                        for ifno in ifs:
284                                if ifno == row0if: continue
285                                for row in xrange(self.scan.nrow()):
286                                        if self.scan.getif(row) == ifno:
287                                                projs.append(self.scan.get_masklist(self.mask,row=row))
288                                                break
289                if len(self._polygons)>0:
290                        # Remove old polygons
291                        for polygon in self._polygons: polygon.remove()
292                        self._polygons=[]
293                # Plot new polygons
294                if len(msks) > 0:
295                        npanel=len(self.p._plotter.subplots)
296                        j=-1
297                        for iloop in range(len(msks)*npanel):
298                                i = iloop % len(msks)
299                                if  i == 0 : j += 1
300                                if len(ifs) > 1:
301                                        for k in xrange(len(ifs)-1):
302                                                self._polygons.append(self.p._plotter.subplots[j]['axes'].axvspan(projs[k][i][0],projs[k][i][1],facecolor='#aaaaaa'))                   
303                                self._polygons.append(self.p._plotter.subplots[j]['axes'].axvspan(msks[i][0],msks[i][1],facecolor='yellow'))
304                self.p._plotter.canvas.draw()
305
306        def finish_selection(self, callback=None):
307                """
308                Execute callback function, reset or close plotter window as
309                necessary.
310
311                Parameters:
312                    callback: The post processing function to run after
313                              the mask selections are completed.
314                              Specifying the callback function here will overwrite
315                              the one set by set_callback(func)
316               
317                Note this function is automatically called at the end of
318                select_mask() if once=True.
319                """
320                if callback: self.callback=callback
321                if self.callback: self.callback()
322                if not self.event: self.p._plotter.register('button_press',None)
323                # Finish the plot
324                if not self.newplot:
325                        self.clear_polygon()
326                else:
327                        self.p._plotter.unmap()
328                        self.p._plotter = None
329                        del self.p
330                        self.p=None
331                        self._polygons=[]
332
333
334        def clear_polygon(self):
335                """
336                Erase masks plots from the plotter.
337                """
338                if len(self._polygons)>0:
339                        # Remove old polygons
340                        for polygon in self._polygons: polygon.remove()
341                        self.p._plotter.show()
342                        self._polygons=[]
343
344
345        def get_mask(self):
346                """
347                Get the interactively selected channel mask.
348                Returns:
349                    A list of channel mask.
350                """
351                return self.mask
352
353
Note: See TracBrowser for help on using the repository browser.