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

Last change on this file since 1622 was 1622, 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):

Description:

A bug fix


File size: 9.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           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                        for panel in self.p._plotter.subplots:
162                                xmin, xmax = panel['axes'].get_xlim()
163                                marg = 0.05*(xmax-xmin)
164                                panel['axes'].set_xlim(xmin-marg, xmax+marg)
165                        self.p._plotter.show()
166
167                # Plot initial mask region
168                #if self.showmask or not self.once:
169                if self.showmask:
170                        self._plot_mask()
171                        print ''
172                        print 'Selected regions are shaded with yellow. (gray: projections)'
173                        print 'Now you can modify the selection.'
174                        print 'Draw rectangles with Left-mouse to add the regions,'
175                        print 'or with Right-mouse to exclude the regions.'
176
177
178                if self.event != None:
179                        self._region_start(self.event)
180                else:
181                        self.p._plotter.register('button_press',None)
182                        self.p._plotter.register('button_press',self._region_start)
183
184
185        def _region_start(self,event):
186                # Do not fire event when in zooming/panning mode
187                mode = self.p._plotter.figmgr.toolbar.mode
188                if not mode =='':
189                        return
190                # Return if selected point is out of panel
191                if event.inaxes == None: return
192                # Select mask/unmask region with mask
193                self.rect = {'button': event.button, 'axes': event.inaxes,
194                             'x': event.x, 'y': event.y,
195                             'world': [event.xdata, event.ydata,
196                                       event.xdata, event.ydata],
197                             'pixel': [event.x, event.y,
198                                       event.x, event.y]}
199                self.p._plotter.register('motion_notify', self._region_draw)
200                self.p._plotter.register('button_release', self._region_end)
201
202        def _region_draw(self,event):
203                sameaxes=(event.inaxes == self.rect['axes'])
204                if sameaxes:
205                        xnow=event.x
206                        ynow=event.y
207                        self.xold=xnow
208                        self.yold=ynow
209                        self.xdataold=event.xdata
210                        self.ydataold=event.ydata
211                else:
212                        xnow=self.xold
213                        ynow=self.yold
214
215                self.p._plotter.figmgr.toolbar.draw_rubberband(event, xnow, ynow, self.rect['x'], self.rect['y'])
216
217
218        def _region_end(self,event):
219                self.p._plotter.register('motion_notify', None)
220                self.p._plotter.register('button_release', None)
221
222                self.p._plotter.figmgr.toolbar.release(event)
223               
224                if event.inaxes == self.rect['axes']:
225                        xend=event.x
226                        yend=event.y
227                        xdataend=event.xdata
228                        ydataend=event.ydata
229                else:
230                        xend=self.xold
231                        yend=self.yold
232                        xdataend=self.xdataold
233                        ydataend=self.ydataold
234                       
235                self.rect['world'][2:4] = [xdataend, ydataend]
236                self.rect['pixel'][2:4] = [xend, yend]
237                self._update_mask()
238                if self.once: self.finish_selection(callback=self.callback)
239
240        def _update_mask(self):
241                # Min and Max for new mask
242                xstart=self.rect['world'][0]
243                xend=self.rect['world'][2]
244                if xstart <= xend: newlist=[xstart,xend]
245                else: newlist=[xend,xstart]
246                # Mask or unmask
247                invmask=None
248                if self.rect['button'] == 1:
249                        invmask=False
250                        mflg='Mask'
251                elif self.rect['button'] == 3:
252                        invmask=True
253                        mflg='UNmask'
254                print mflg+': ',newlist
255                newmask=self.scan.create_mask(newlist,invert=invmask)
256                # Logic operation to update mask
257                if invmask:
258                        self.mask=mask_and(self.mask,newmask)
259                else:
260                        self.mask=mask_or(self.mask,newmask)
261                # Plot masked regions
262                #if self.showmask or not self.once: self._plot_mask()
263                if self.showmask: self._plot_mask()
264
265        # Plot masked regions
266        def _plot_mask(self):
267                msks = []
268                msks = self.scan.get_masklist(self.mask,row=0)
269                # Get projection masks for multi-IF
270                ifs=self.scan.getifnos()
271                projs = []
272                if len(ifs) > 1:
273                        row0if=self.scan.getif(0)
274                        for ifno in ifs:
275                                if ifno == row0if: continue
276                                for row in xrange(self.scan.nrow()):
277                                        if self.scan.getif(row) == ifno:
278                                                projs.append(self.scan.get_masklist(self.mask,row=row))
279                                                break
280                if len(self._polygons)>0:
281                        # Remove old polygons
282                        for polygon in self._polygons: polygon.remove()
283                        self._polygons=[]
284                # Plot new polygons
285                if len(msks) > 0:
286                        npanel=len(self.p._plotter.subplots)
287                        j=-1
288                        for iloop in range(len(msks)*npanel):
289                                i = iloop % len(msks)
290                                if  i == 0 : j += 1
291                                if len(ifs) > 1:
292                                        for k in xrange(len(ifs)-1):
293                                                self._polygons.append(self.p._plotter.subplots[j]['axes'].axvspan(projs[k][i][0],projs[k][i][1],facecolor='#aaaaaa'))                   
294                                self._polygons.append(self.p._plotter.subplots[j]['axes'].axvspan(msks[i][0],msks[i][1],facecolor='yellow'))
295                self.p._plotter.canvas.draw()
296
297        def finish_selection(self, callback=None):
298                if callback: self.callback=callback
299                if self.callback: self.callback()
300                if not self.event: self.p._plotter.register('button_press',None)
301                # Finish the plot
302                if not self.newplot:
303                        self.clear_polygon()
304                else:
305                        self.p._plotter.unmap()
306                        self.p._plotter = None
307                        del self.p
308                        self.p=None
309
310
311        def clear_polygon(self):
312                """
313                Erase masks plots from the plotter.
314                """
315                if len(self._polygons)>0:
316                        # Remove old polygons
317                        for polygon in self._polygons: polygon.remove()
318                        self.p._plotter.show()
319                        self._polygons=[]
320
321
322        def get_mask(self):
323                """
324                Get the interactively selected channel mask.
325                Returns:
326                    A list of channel mask.
327                """
328                return self.mask
329
330
Note: See TracBrowser for help on using the repository browser.