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