Index: guiframe/local_perspectives/plotting/AnnulusSlicer.py
===================================================================
--- guiframe/local_perspectives/plotting/AnnulusSlicer.py	(revision 78cae5a1149ac83383cdbfa454099e1712185aa3)
+++ guiframe/local_perspectives/plotting/AnnulusSlicer.py	(revision c5874f2a97966aef2f30b9fdd83304fbd769368e)
@@ -395,3 +395,174 @@
         self.set_cursor(x, self._inner_mouse_y)
         
-        
+class CircularMask(_BaseInteractor):
+    """
+         Draw a ring Given a radius 
+         @param: the color of the line that defined the ring
+         @param r: the radius of the ring
+         @param sign: the direction of motion the the marker 
+    """
+    def __init__(self,base,axes,color='black', zorder=3, side=None):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        self.markers = []
+        self.axes = axes
+        self.base= base
+        self.is_inside = side
+        self.qmax = min(math.fabs(self.base.data.xmax),math.fabs(self.base.data.xmin))  #must be positive
+        self.connect = self.base.connect
+        
+        #Cursor position of Rings (Left(-1) or Right(1))
+        self.xmaxd=self.base.data.xmax
+        self.xmind=self.base.data.xmin
+
+        if (self.xmaxd+self.xmind)>0:
+            self.sign=1
+        else:
+            self.sign=-1
+                 
+        # Inner circle
+        self.outer_circle = RingInteractor(self, self.base.subplot, zorder=zorder+1, r=self.qmax/1.8,sign=self.sign)
+        self.outer_circle.qmax = self.qmax*1.2
+       
+        self.update()
+        self._post_data()
+        
+        # Bind to slice parameter events
+        #self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
+        
+        
+
+    def _onEVT_SLICER_PARS(self, event):
+        """
+            receive an event containing parameters values to reset the slicer
+            @param event: event of type SlicerParameterEvent with params as 
+            attribute
+        """
+        wx.PostEvent(self.base, StatusEvent(status="AnnulusSlicer._onEVT_SLICER_PARS"))
+        event.Skip()
+        if event.type == self.__class__.__name__:
+            self.set_params(event.params)
+            self.base.update()
+
+    def set_layer(self, n):
+        """
+             Allow adding plot to the same panel
+             @param n: the number of layer
+        """
+        self.layernum = n
+        self.update()
+        
+    def clear(self):
+        """
+            Clear the slicer and all connected events related to this slicer
+        """
+        self.clear_markers()
+        self.outer_circle.clear()
+        self.base.connect.clearall()
+        #self.base.Unbind(EVT_SLICER_PARS)
+        
+        
+    def update(self):
+        """
+            Respond to changes in the model by recalculating the profiles and
+            resetting the widgets.
+        """
+        # Update locations        
+        self.outer_circle.update()
+        #if self.is_inside != None:
+        out = self._post_data()
+        return out
+
+    def save(self, ev):
+        """
+            Remember the roughness for this layer and the next so that we
+            can restore on Esc.
+        """
+        self.base.freeze_axes()
+        self.outer_circle.save(ev)
+
+    def _post_data(self):
+        """
+            Uses annulus parameters to plot averaged data into 1D data.
+            @param nbins: the number of points to plot 
+        """
+        #Data to average
+        data = self.base.data
+              
+        # If we have no data, just return
+        if data == None:
+            return
+        mask = data.mask  
+        from DataLoader.manipulations import Ringcut
+    
+        rmin= 0
+        rmax = math.fabs(self.outer_circle.get_radius())
+
+        ## create the data1D Q average of data2D    
+        mask = Ringcut(r_min=rmin , r_max= rmax)
+
+        if self.is_inside:
+            out = (mask(data)==False)
+        else:
+            out = (mask(data))
+        #self.base.data.mask=out
+        return out                    
+
+         
+    def moveend(self, ev):
+        """
+            Called when any dragging motion ends.
+            Post an event (type =SlicerParameterEvent)
+            to plotter 2D with a copy  slicer parameters
+            Call  _post_data method
+        """
+        self.base.thaw_axes()
+        # create a 1D data plot
+        self._post_data()
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self.outer_circle.restore()
+
+    def move(self, x, y, ev):
+        """
+        Process move to a new position, making sure that the move is allowed.
+        """
+        pass
+        
+    def set_cursor(self, x, y):
+        pass
+        
+    def get_params(self):
+        """
+            Store a copy of values of parameters of the slicer into a dictionary.
+            @return params: the dictionary created
+        """
+        params = {}
+        params["outer_radius"] = math.fabs(self.outer_circle._inner_mouse_x)
+        return params
+    
+    def set_params(self, params):
+        """
+            Receive a dictionary and reset the slicer with values contained 
+            in the values of the dictionary.
+            @param params: a dictionary containing name of slicer parameters and 
+            values the user assigned to the slicer.
+        """
+        outer = math.fabs(params["outer_radius"] )
+        ## Update the picture
+        self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y)
+        ## Post the data given the nbins entered by the user 
+        self._post_data()
+        
+    def freeze_axes(self):
+        self.base.freeze_axes()
+        
+    def thaw_axes(self):
+        self.base.thaw_axes()
+
+    def draw(self):
+        self.base.update()
+              
Index: guiframe/local_perspectives/plotting/boxMask.py
===================================================================
--- guiframe/local_perspectives/plotting/boxMask.py	(revision c5874f2a97966aef2f30b9fdd83304fbd769368e)
+++ guiframe/local_perspectives/plotting/boxMask.py	(revision c5874f2a97966aef2f30b9fdd83304fbd769368e)
@@ -0,0 +1,243 @@
+
+
+
+import math
+import wx
+from copy import deepcopy
+from BaseInteractor import _BaseInteractor
+from boxSum import PointInteractor,VerticalDoubleLine,HorizontalDoubleLine
+from sans.guicomm.events import SlicerParamUpdateEvent
+
+
+class BoxMask(_BaseInteractor):
+    """
+        BoxMask Class: determine 2 rectangular area to find the pixel of
+        a Data inside of box. 
+        Uses PointerInteractor , VerticalDoubleLine,HorizontalDoubleLine.
+        @param zorder:  Artists with lower zorder values are drawn first.
+        @param x_min: the minimum value of the x coordinate
+        @param x_max: the maximum value of the x coordinate
+        @param y_min: the minimum value of the y coordinate
+        @param y_max: the maximum value of the y coordinate
+
+    """
+    def __init__(self,base,axes,color='black', zorder=3, side=None, 
+                   x_min=0.008, x_max=0.008, y_min=0.0025, y_max=0.0025):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        ## class initialization
+        ## list of Boxmask markers
+        self.markers = []
+        self.axes = axes
+        self.is_inside = side
+        ## connect the artist for the motion
+        self.connect = self.base.connect
+        ## when qmax is reached the selected line is reset the its previous value
+        self.qmax = min(self.base.data.xmax, self.base.data.xmin)
+        ## Define the box limits
+        self.xmin= -1* 0.5*min(math.fabs(self.base.data.xmax),math.fabs( self.base.data.xmin))
+        self.ymin= -1* 0.5*min(math.fabs(self.base.data.xmax),math.fabs( self.base.data.xmin))
+       
+        self.xmax= 0.5*min(math.fabs(self.base.data.xmax),math.fabs( self.base.data.xmin))
+        self.ymax=  0.5*min(math.fabs(self.base.data.xmax),math.fabs( self.base.data.xmin))
+        ## center of the box
+        self.center_x= 0.0002
+        self.center_y= 0.0003
+        ## Number of points on the plot
+        self.nbins = 20
+        ## Define initial result the summation 
+        self.count=0
+        self.error=0
+        self.data = self.base.data
+        ## Flag to determine if the current figure has moved
+        ## set to False == no motion , set to True== motion
+        self.has_move= False
+        ## Create Box edges 
+        self.horizontal_lines= HorizontalDoubleLine(self, self.base.subplot,color='blue',
+                                                      zorder=zorder,
+                                    y= self.ymax,
+                                    x= self.xmax,
+                                    center_x= self.center_x,
+                                    center_y= self.center_y)
+        self.horizontal_lines.qmax = self.qmax
+        
+        self.vertical_lines= VerticalDoubleLine(self, self.base.subplot,color='black',
+                                                      zorder=zorder,
+                                    y= self.ymax,
+                                    x= self.xmax,
+                                    center_x= self.center_x,
+                                    center_y= self.center_y)
+        self.vertical_lines.qmax = self.qmax
+        
+        self.center= PointInteractor(self, self.base.subplot,color='grey',
+                                                      zorder=zorder,
+                                    center_x= self.center_x,
+                                    center_y= self.center_y)
+        ## Save the name of the slicer panel associate with this slicer 
+        self.panel_name=""    
+        ## Update and post slicer parameters  
+        self.update()
+        self._post_data()
+        
+        
+    def clear(self):
+        """
+            Clear the slicer and all connected events related to this slicer
+        """
+        self.clear_markers()
+        self.horizontal_lines.clear()
+        self.vertical_lines.clear()
+        self.center.clear()
+        self.base.connect.clearall()
+        #self.base.Unbind(EVT_SLICER_PARS)
+        
+
+    def update(self):
+        """
+            Respond to changes in the model by recalculating the profiles and
+            resetting the widgets.
+        """
+
+        ## check if the center point has moved and update the figure accordingly 
+        if self.center.has_move:
+            self.center.update()
+            self.horizontal_lines.update( center= self.center)
+            self.vertical_lines.update( center= self.center)
+        ## check if the horizontal lines have moved and update the figure accordingly    
+        if self.horizontal_lines.has_move:
+            self.horizontal_lines.update()
+            self.vertical_lines.update(y1=self.horizontal_lines.y1,
+                                       y2=self.horizontal_lines.y2,
+                                       height= self.horizontal_lines.half_height )
+        ## check if the vertical lines have moved and update the figure accordingly    
+        if self.vertical_lines.has_move:
+            self.vertical_lines.update()
+            self.horizontal_lines.update(x1=self.vertical_lines.x1,
+                                         x2=self.vertical_lines.x2,
+                                         width=self.vertical_lines.half_width)
+        #if self.is_inside != None:
+        out = self._post_data()
+        return out
+        
+    def save(self, ev):
+        """
+        Remember the roughness for this layer and the next so that we
+        can restore on Esc.
+        """
+        self.base.freeze_axes()
+        self.horizontal_lines.save(ev)
+        self.vertical_lines.save(ev)
+        self.center.save(ev)
+        
+    def _post_data(self):
+        """
+            Get the limits of the boxsum and compute the sum of the pixel
+            contained in that region and the error on that sum
+        """
+        from DataLoader.manipulations import Boxcut
+        ## Data 2D for which the pixel will be summed
+        data = self.base.data
+        mask = data.mask
+        ## the region of the summation
+        x_min= self.horizontal_lines.x2 
+        x_max= self.horizontal_lines.x1 
+        y_min= self.vertical_lines.y2
+        y_max= self.vertical_lines.y1
+        mask = Boxcut(x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max)
+
+        if self.is_inside:
+            out = (mask(data)==False)
+        else:
+            out = (mask(data))
+        #self.base.data.mask=out
+        return out            
+    def moveend(self, ev):
+        """
+            After a dragging motion this function is called to compute
+            the error and the sum of pixel of a given data 2D 
+        """
+        self.base.thaw_axes()
+        ## post
+        self._post_data()
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self.horizontal_lines.restore()
+        self.vertical_lines.restore()
+        self.center.restore()
+        
+        
+    def move(self, x, y, ev):
+        """
+        Process move to a new position, making sure that the move is allowed.
+        """
+        pass
+    
+    
+    def set_cursor(self, x, y):
+        pass
+        
+        
+    def get_params(self):
+        """
+            Store a copy of values of parameters of the slicer into a dictionary.
+            @return params: the dictionary created
+        """
+        params = {}
+        params["Width"] = math.fabs(self.vertical_lines.half_width)*2
+        params["Height"] = math.fabs(self.horizontal_lines.half_height)*2 
+        params["center_x"] = self.center.x
+        params["center_y"] =self.center.y
+
+        return params
+    
+  
+    def get_mask(self):
+        """
+            return mask as a result of boxcut
+        """
+        mask = self.mask
+        return mask
+    
+        
+    def set_params(self, params):
+        """
+            Receive a dictionary and reset the slicer with values contained 
+            in the values of the dictionary.
+            @param params: a dictionary containing name of slicer parameters and 
+            values the user assigned to the slicer.
+        """
+        x_max = math.fabs(params["Width"] )/2
+        y_max = math.fabs(params["Height"] )/2
+        
+        self.center_x=params["center_x"] 
+        self.center_y=params["center_y"]
+        #update the slicer given values of params
+        self.center.update(center_x=self.center_x,center_y=self.center_y)
+        self.horizontal_lines.update(center= self.center,
+                                     width=x_max,
+                                     height=y_max)
+        self.vertical_lines.update(center= self.center,
+                                    width=x_max,
+                                    height=y_max)
+        #compute the new error and sum given values of params
+        self._post_data()
+               
+        
+    def freeze_axes(self):
+        self.base.freeze_axes()
+        
+        
+    def thaw_axes(self):
+        self.base.thaw_axes()
+
+
+    def draw(self):
+        self.base.update()
+
+class inner_BoxMask(BoxMask):   
+    def __call__(self):     
+        self.base.data.mask=(self._post_data()==False)
+         
Index: guiframe/local_perspectives/plotting/masking.py
===================================================================
--- guiframe/local_perspectives/plotting/masking.py	(revision c5874f2a97966aef2f30b9fdd83304fbd769368e)
+++ guiframe/local_perspectives/plotting/masking.py	(revision c5874f2a97966aef2f30b9fdd83304fbd769368e)
@@ -0,0 +1,596 @@
+"""
+This software was developed by the University of Tennessee as part of the
+Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+project funded by the US National Science Foundation. 
+
+If you use DANSE applications to do scientific research that leads to 
+publication, we ask that you acknowledge the use of the software with the 
+following sentence:
+
+"This work benefited from DANSE software developed under NSF award DMR-0520547." 
+
+copyright 2008, University of Tennessee
+"""
+import wx
+import sys
+
+import copy,numpy
+from danse.common.plottools.PlotPanel import PlotPanel
+from binder import BindArtist
+from sans.guiframe.dataFitting import Data2D
+from boxMask import BoxMask
+from sectorMask import SectorMask
+from sans.guicomm.events import SlicerEvent, StatusEvent
+(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
+from pylab import  gca, gcf
+import math,pylab,re
+DEFAULT_CMAP= pylab.cm.jet
+
+_BOX_WIDTH = 76
+_STATICBOX_WIDTH = 400
+_SCALE = 1e-6
+
+#SLD panel size 
+if sys.platform.count("win32")>0:
+    _STATICBOX_WIDTH = 380
+    PANEL_SIZE = 420
+    FONT_VARIANT = 0
+else:
+    _STATICBOX_WIDTH = 410
+    PANEL_SIZE = 450
+    FONT_VARIANT = 1
+    
+
+            
+class MaskPanel(wx.Dialog):
+    """
+        Provides the Mask Editor GUI.
+    """
+    ## Internal nickname for the window, used by the AUI manager
+    window_name = "Mask Editor"
+    ## Name to appear on the window title bar
+    window_caption = "Mask Editor"
+    ## Flag to tell the AUI manager to put this panel in the center pane
+    CENTER_PANE = True
+    def __init__(self, parent=None,base=None,data =None, id = -1, *args, **kwds):
+        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
+        wx.Dialog.__init__(self, parent, id = id,  size=wx.Size(_STATICBOX_WIDTH*2,PANEL_SIZE), *args, **kwds)
+        if data != None:
+            
+            #Font size 
+            kwds =[]
+            self.SetWindowVariant(variant=FONT_VARIANT)
+
+            self.SetTitle("Mask Editor for "+ data.name)
+            self.parent = base
+            self.data = data
+            self.str = self.data.__str__()
+            ## mask for 2D
+            self.mask = data.mask
+            self.default_mask = copy.deepcopy(data.mask)
+            ## masked data from GUI
+            self.slicer_mask = None
+            self.slicer = None
+            self.slicer_z = 5
+
+            self.data.interactive = True
+            ## when 2 data have the same id override the 1 st plotted
+            self.name = self.data.name
+
+            # Panel for 2D plot
+            self.plotpanel    = SANSplotpanel(self, -1, style=wx.TRANSPARENT_WINDOW)
+            self.cmap = DEFAULT_CMAP
+            ## Create Artist and bind it
+            self.subplot = self.plotpanel.subplot
+            self.connect = BindArtist(self.subplot.figure)
+
+            self._setup_layout()
+            self.newplot=Data2D(image=self.data.data)
+            self.newplot.setValues(self.data)
+            self.plotpanel.add_image(self.newplot) 
+            self._update_mask(self.mask)
+            self.Centre()
+            self.Layout()
+            # bind evt_close to _draw in fitpage
+            self.Bind(wx.EVT_CLOSE, self._draw_model)
+            
+    def ShowMessage(self, msg=''):
+        """
+            Show error message when mask covers whole data area
+        """
+        mssg = 'Erase, redraw or clear the mask. \n\r'
+        mssg += 'The data range can not be completely masked... \n\r'
+        mssg += msg
+        wx.MessageBox(mssg, 'Error', wx.OK | 
+            wx.ICON_ERROR)
+    
+    def _setup_layout(self):
+        """
+            Set up the layout
+        """
+        shape = "Select a Shape for Masking:"
+        
+        #  panel
+        sizer = wx.GridBagSizer(10,10)
+
+        #---------inputs----------------
+        #inputbox = wx.StaticBox(self, -1, "Draw Mask")
+        shape_txt = wx.StaticText(self, -1, shape)  
+        sizer.Add(shape_txt, (1, 1), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=5)
+                
+        #innersector_x_txt = wx.StaticText(self, -1, 'Inner Sector')
+        self.innersector_rb = wx.RadioButton(self, -1,"Double Wings")
+        self.Bind(wx.EVT_RADIOBUTTON,self.onInnerSectorMask , id=self.innersector_rb.GetId())
+        sizer.Add(self.innersector_rb, (2, 1),flag=wx.RIGHT | wx.BOTTOM, border=5)
+        
+        #innersector_x_txt = wx.StaticText(self, -1, 'Inner Sector')
+        self.innercircle_rb = wx.RadioButton(self, -1,"Circular Disk")
+        self.Bind(wx.EVT_RADIOBUTTON,self.onInnerRingMask , id=self.innercircle_rb.GetId())
+        sizer.Add(self.innercircle_rb, (3, 1),flag=wx.RIGHT | wx.BOTTOM, border=5)
+        
+        self.innerbox_rb = wx.RadioButton(self, -1,"Rectangular Disk")
+        self.Bind(wx.EVT_RADIOBUTTON,self.onInnerBoxMask , id=self.innerbox_rb.GetId())
+        sizer.Add(self.innerbox_rb, (4, 1),flag=wx.RIGHT | wx.BOTTOM, border=5)
+
+        #outersector_y_txt = wx.StaticText(self, -1, 'Outer Sector')
+        self.outersector_rb = wx.RadioButton(self, -1,"Double Wing Window")
+        self.Bind(wx.EVT_RADIOBUTTON,self.onOuterSectorMask , id=self.outersector_rb.GetId())
+        sizer.Add(self.outersector_rb, (5, 1),flag=wx.RIGHT | wx.BOTTOM, border=5)
+        
+        #outersector_y_txt = wx.StaticText(self, -1, 'Outer Sector')
+        self.outercircle_rb = wx.RadioButton(self, -1,"Circular Window")
+        self.Bind(wx.EVT_RADIOBUTTON,self.onOuterRingMask , id=self.outercircle_rb.GetId())
+        sizer.Add(self.outercircle_rb, (6, 1),flag=wx.RIGHT | wx.BOTTOM, border=5)
+        
+        #outerbox_txt = wx.StaticText(self, -1, 'Outer Box')
+        self.outerbox_rb = wx.RadioButton(self, -1,"Rectangular Window")
+        self.Bind(wx.EVT_RADIOBUTTON,self.onOuterBoxMask , id=self.outerbox_rb.GetId())
+        sizer.Add(self.outerbox_rb, (7, 1),flag=wx.RIGHT | wx.BOTTOM, border=5)
+        
+        self.innercircle_rb.SetValue(False)
+        self.outercircle_rb.SetValue(False)        
+        self.innerbox_rb.SetValue(False)
+        self.outerbox_rb.SetValue(False)
+        self.innersector_rb.SetValue(False)
+        self.outersector_rb.SetValue(False)
+        
+        sizer.Add(self.plotpanel,(0, 2), (13, 13), wx.EXPAND | wx.LEFT| wx.RIGHT, 15)
+
+        #-----Buttons------------1
+        id = wx.NewId()
+        
+        button_add = wx.Button(self, id, "Add")
+        button_add.SetToolTipString("Add the mask drawn.")
+        button_add.Bind(wx.EVT_BUTTON, self.onAddMask, id = button_add.GetId()) 
+        sizer.Add(button_add, (13, 7))
+        
+        id = wx.NewId()
+        button_erase = wx.Button(self, id, "Erase")
+        button_erase.SetToolTipString("Erase the mask drawn.")
+        button_erase.Bind(wx.EVT_BUTTON, self.onEraseMask, id = button_erase.GetId()) 
+        sizer.Add(button_erase, (13, 8))
+        
+        id = wx.NewId()
+        button_reset = wx.Button(self, id, "Reset")
+        button_reset.SetToolTipString("Reset the mask.")
+        button_reset.Bind(wx.EVT_BUTTON, self.onResetMask, id = button_reset.GetId()) 
+        sizer.Add(button_reset, (13, 9), flag=wx.RIGHT | wx.BOTTOM, border=15)
+        
+        id = wx.NewId()
+        button_reset = wx.Button(self, id, "Clear")
+        button_reset.SetToolTipString("Clear all mask.")
+        button_reset.Bind(wx.EVT_BUTTON, self.onClearMask, id = button_reset.GetId()) 
+        sizer.Add(button_reset, (13, 10), flag=wx.RIGHT | wx.BOTTOM, border=15)
+
+        sizer.AddGrowableCol(3)
+        sizer.AddGrowableRow(2)
+        self.SetSizerAndFit(sizer)
+
+        self.Centre()
+        self.Show(True)
+
+
+    def onInnerBoxMask(self,event=None):
+        """
+            Call Draw Box Slicer and get mask inside of the box
+        """
+        #get ready for next evt
+        event.Skip()        
+        from boxMask import BoxMask
+        if event !=None:
+            self.onClearSlicer(event)
+                    
+        self.slicer_z += 1
+        self.slicer =  BoxMask(self, self.subplot, zorder=self.slicer_z, side=True)
+
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)
+        self.update()
+        self.slicer_mask = self.slicer.update()
+
+        #wx.PostEvent(self, InternalEvent(slicer= BoxMask))
+        
+    
+    def onOuterBoxMask(self,event=None):
+        """
+            Call Draw Box Slicer and get mask outside of the box
+        """
+        event.Skip()        
+        from boxMask import BoxMask
+        if event !=None:
+            self.onClearSlicer(event)
+                    
+        self.slicer_z += 1
+        self.slicer =  BoxMask(self, self.subplot, zorder=self.slicer_z, side=False)
+
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)
+        self.update()
+        self.slicer_mask = self.slicer.update()
+        #wx.PostEvent(self, InternalEvent(slicer= BoxMask))
+
+        
+    def onInnerSectorMask(self,event=None):
+        """
+            Call Draw Sector Slicer and get mask inside of the sector
+        """
+        event.Skip()
+        from sectorMask import SectorMask
+        if event !=None:
+            self.onClearSlicer(event)
+
+        self.slicer_z += 1
+        self.slicer =  SectorMask(self, self.subplot, zorder=self.slicer_z, side=True)
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)   
+
+        #mask = self.slicer.update()   
+        self.update()
+        self.slicer_mask = self.slicer.update() 
+        #wx.PostEvent(self, InternalEvent(slicer= SectorMask))
+        
+    def onOuterSectorMask(self,event=None):
+        """
+            Call Draw Sector Slicer and get mask outside of the sector
+        """
+        event.Skip()
+        from sectorMask import SectorMask
+        if event !=None:
+            self.onClearSlicer(event)
+
+        self.slicer_z += 1
+        self.slicer =  SectorMask(self, self.subplot, zorder=self.slicer_z, side=False)
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)    
+
+        self.update()     
+        self.slicer_mask = self.slicer.update()   
+        #wx.PostEvent(self, InternalEvent(slicer= SectorMask))
+        
+    def onInnerRingMask(self, event=None):
+        """
+            Perform inner circular cut on Phi and draw circular slicer
+        """
+        event.Skip()
+        from AnnulusSlicer import CircularMask
+        if event !=None:
+            self.onClearSlicer(event)
+        
+        self.slicer_z += 1
+        self.slicer = CircularMask(self,self.subplot, zorder=self.slicer_z, side=True)
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)   
+        #mask = self.slicer.update()   
+        self.update()
+        self.slicer_mask = self.slicer.update() 
+ 
+        #wx.PostEvent(self, InternalEvent(slicer= AnnulusInteractor))
+        
+    def onOuterRingMask(self, event=None):
+        """
+            Perform outer circular cut on Phi and draw circular slicer
+        """
+        event.Skip()
+        from AnnulusSlicer import CircularMask
+        if event !=None:
+            self.onClearSlicer(event)
+        
+        self.slicer_z += 1
+        self.slicer = CircularMask(self,self.subplot, zorder=self.slicer_z, side=False)   
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)
+        self.update()
+        self.slicer_mask = self.slicer.update()     
+        
+    def onAddMask(self, event):
+        """
+            Add new mask to old mask 
+        """
+        if not self.slicer==None:
+            data = Data2D()
+            data = self.data
+            self.slicer_mask = self.slicer.update()
+            data.mask = self.data.mask & self.slicer_mask
+
+            self._check_display_mask(data.mask, event)
+            # Post slicer None event
+            #event = self._getEmptySlicerEvent()
+            #wx.PostEvent(self, event)
+            
+    def _check_display_mask(self, mask, event):
+        """
+            check if the mask valid and update the plot
+            @param mask: mask data
+        """
+        ## Redraw the current image
+        self._update_mask(mask)
+
+    def onEraseMask(self, event):
+        """
+            Erase new mask from old mask
+        """
+        if not self.slicer==None:
+            self.slicer_mask = self.slicer.update()
+            mask = self.data.mask
+            mask[self.slicer_mask==False] = True
+
+            #event = self._getEmptySlicerEvent()
+            #wx.PostEvent(self, event)
+            self._check_display_mask(mask, event)
+            
+    def onResetMask(self, event):
+        """
+            Reset mask to the original mask 
+        """
+                    
+        self.slicer_z += 1
+        self.slicer =  BoxMask(self, self.subplot, zorder=self.slicer_z, side=True)
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)   
+
+        mask = copy.deepcopy(self.default_mask)
+        self.data.mask = mask
+
+        # Post slicer None event
+        #event = self._getEmptySlicerEvent()
+        #wx.PostEvent(self, event)
+        # update mask plot
+        self._check_display_mask(mask, event)
+        
+    def onClearMask(self, event):
+        """
+            Clear mask
+        """            
+        self.slicer_z += 1
+        self.slicer =  BoxMask(self, self.subplot, zorder=self.slicer_z, side=True)
+        self.subplot.set_ylim(self.data.ymin, self.data.ymax)
+        self.subplot.set_xlim(self.data.xmin, self.data.xmax)   
+
+        #mask = copy.deepcopy(self.default_mask)
+        mask = numpy.ones(len(self.data.mask), dtype=bool)
+        self.data.mask = mask
+        
+        # Post slicer None event
+        #event = self._getEmptySlicerEvent()
+        #wx.PostEvent(self, event)
+        # update mask plot
+        self._check_display_mask(mask, event)
+        
+    def onClearSlicer(self, event):
+        """
+            Clear the slicer on the plot
+        """
+        if not self.slicer==None:
+            self.slicer.clear()
+            self.subplot.figure.canvas.draw()
+            self.slicer = None
+        
+            # Post slicer None event
+            #event = self._getEmptySlicerEvent()
+            #wx.PostEvent(self, event)
+
+            
+    def _setSlicer(self):
+        """
+            Clear the previous slicer and create a new one.Post an internal
+            event.
+            @param slicer: slicer class to create
+        """
+        
+        ## Clear current slicer
+        if not self.slicer == None:  
+            self.slicer.clear()            
+        ## Create a new slicer    
+        self.slicer_z += 1
+        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
+        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
+        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
+        ## Draw slicer
+        self.update()
+        self.slicer.update()
+        wx.PostEvent(self.parent, StatusEvent(status=\
+                        "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__))
+        # Post slicer event
+        event = self._getEmptySlicerEvent()
+        event.type = self.slicer.__class__.__name__
+        
+        event.obj_class = self.slicer.__class__
+        event.params = self.slicer.get_params()
+        wx.PostEvent(self, event)
+   
+    def update(self, draw=True):
+        """
+            Respond to changes in the model by recalculating the 
+            profiles and resetting the widgets.
+        """
+        self.plotpanel.draw()
+        
+    def _set_mask(self, mask):
+        """
+            Set mask"
+        """
+        self.data.mask = mask
+        
+    def _update_mask(self,mask):
+        """
+            Respond to changes in masking
+        """ 
+        # the case of liitle numbers of True points
+        if (len(mask[mask])<10 and self.data !=None):
+            self.ShowMessage()
+            mask = copy.deepcopy(self.mask)
+            self.data.mask = mask
+        else:
+            self.mask = mask
+
+        # make temperary data to plot
+        temp_mask = numpy.zeros(len(mask))
+        temp_data = copy.deepcopy(self.data)
+        # temp_data default is None
+        # This method is to distinguish between masked point and data point = 0.
+        temp_mask = temp_mask/temp_mask
+        temp_mask[mask] = temp_data.data[mask]
+        # set temp_data value for self.mask==True, else still None 
+        #temp_mask[mask] = temp_data[mask]
+        temp_data.data[mask==False] = temp_mask[mask==False]
+        self.plotpanel.clear()
+        if self.slicer != None:
+            self.slicer.clear()
+            self.slicer = None
+        
+        # Post slicer None event
+        event = self._getEmptySlicerEvent()
+        wx.PostEvent(self, event)
+        
+        #replot
+        
+        plot = self.plotpanel.image(data= temp_mask,
+                       qx_data=self.data.qx_data,
+                       qy_data=self.data.qy_data,
+                       xmin= self.data.xmin,
+                       xmax= self.data.xmax,
+                       ymin= self.data.ymin,
+                       ymax= self.data.ymax,
+                       zmin= self.data.zmin,
+                       zmax= self.data.zmax,
+                       cmap= self.cmap,
+                       color=0,symbol=0,label=self.data.name)
+        
+        
+        #self.plotpanel.add_image(temp_data)
+        self.plotpanel.xaxis('Qx ', '1/A')
+        self.plotpanel.yaxis('Qy ', '1/A')
+        self.plotpanel.render()
+        self.plotpanel.subplot.figure.canvas.draw_idle()
+        
+        
+    def _getEmptySlicerEvent(self):
+        """
+            create an empty slicervent 
+        """
+        self.innerbox_rb.SetValue(False)
+        self.outerbox_rb.SetValue(False)
+        self.innersector_rb.SetValue(False)
+        self.outersector_rb.SetValue(False)
+        self.innercircle_rb.SetValue(False)
+        self.outercircle_rb.SetValue(False)
+
+        return SlicerEvent(type=None,
+                           params=None,
+                           obj_class=None) 
+             
+    def _draw_model(self,event):
+        """
+            on_close, update the model2d plot
+        """
+        pass
+        
+    def freeze_axes(self):
+        self.plotpanel.axes_frozen = True
+    def thaw_axes(self):
+        self.plotpanel.axes_frozen = False        
+    def onMouseMotion(self,event):
+        pass
+    def onWheel(self, event):
+        pass  
+           
+class SANSplotpanel(PlotPanel):
+    
+    def __init__(self, parent, id = -1, color = None,\
+        dpi = None, **kwargs):
+        PlotPanel.__init__(self, parent, id=id, color=color, dpi=dpi, **kwargs)
+        
+        # Keep track of the parent Frame
+        self.parent = parent
+       
+        # Internal list of plottable names (because graph 
+        # doesn't have a dictionary of handles for the plottables)
+        self.plots = {}
+        
+    def add_toolbar(self):
+        """ 
+            Add toolbar
+        """
+        # Not implemented
+        pass
+    def on_set_focus(self, event):
+        """
+            send to the parenet the current panel on focus
+        """
+        #change the panel background
+        #self.SetColor((170, 202, 255))
+        self.draw()   
+         
+    def add_image(self, plot):
+        self.plots[plot.name] = plot
+        
+        self.graph.add(plot)
+        self.graph.xaxis('\\rm{Q}_{x} ', 'A^{-1}')
+        self.graph.yaxis('\\rm{Q}_{y} ', 'A^{-1}')
+        self.graph.render(self)
+        self.subplot.figure.canvas.draw_idle()
+        #self.onResetGraph(None)
+    def onMouseMotion(self, event):
+        """
+            Disable dragging 2D image
+        """
+        pass
+   
+    def onContextMenu(self, event):
+        """
+            Default context menu for a plot panel
+        """
+        # Slicer plot popup menu
+        #id = wx.NewId()
+        #slicerpop = wx.Menu()
+        #slicerpop.Append(id,'&Save image', 'Save image as PNG')
+        #wx.EVT_MENU(self, id, self.onSaveImage)
+        
+        id = wx.NewId()
+        slicerpop.Append(id, '&Toggle Linear/Log scale')
+        wx.EVT_MENU(self, id, self._onToggleScale)
+               
+        pos = event.GetPosition()
+        pos = self.ScreenToClient(pos)
+        self.PopupMenu(slicerpop, pos)
+
+
+
+
+from DataLoader.readers.IgorReader import Reader
+        
+class ViewApp(wx.App):
+    def OnInit(self):
+        frame = MaskPanel(None, -1, 'Mask Editor') 
+        data = Data2D()
+        data = Reader().read('/test/MAR07232_rest.ASC')
+        panel = frame(self, data=data)  
+        panel.Show(True)
+        self.SetTopWindow(panel)
+        
+        return True
+        
+
+if __name__ == "__main__": 
+    app = ViewApp(0)
+    app.MainLoop()     
Index: guiframe/local_perspectives/plotting/sectorMask.py
===================================================================
--- guiframe/local_perspectives/plotting/sectorMask.py	(revision c5874f2a97966aef2f30b9fdd83304fbd769368e)
+++ guiframe/local_perspectives/plotting/sectorMask.py	(revision c5874f2a97966aef2f30b9fdd83304fbd769368e)
@@ -0,0 +1,215 @@
+
+import math
+import wx
+from copy import deepcopy
+
+from BaseInteractor import _BaseInteractor
+from SectorSlicer import SideInteractor, LineInteractor
+from sans.guicomm.events import SlicerParameterEvent
+
+class SectorMask(_BaseInteractor):
+    """
+         Draw a sector slicer.Allow to find the data 2D inside of the sector lines
+    """
+    def __init__(self,base,axes,color='black', zorder=3, side = False):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        ## Class initialization
+        self.markers = []
+        self.axes = axes   
+        self.is_inside = side
+        ## connect the plot to event 
+        self.connect = self.base.connect
+        
+        ## compute qmax limit to reset the graph     
+        x = math.pow(max(self.base.data.xmax,math.fabs(self.base.data.xmin)),2)
+        y = math.pow(max(self.base.data.ymax,math.fabs(self.base.data.ymin)),2)
+        self.qmax= math.sqrt(x + y)
+        ## Number of points on the plot
+        self.nbins = 20
+        ## Angle of the middle line
+        self.theta2= math.pi/3
+        ## Absolute value of the Angle between the middle line and any side line
+        self.phi=math.pi/12
+        
+        ## Middle line
+        self.main_line = LineInteractor(self, self.base.subplot,color='blue', zorder=zorder, r=self.qmax,
+                                           theta= self.theta2)
+        self.main_line.qmax = self.qmax
+        ## Right Side line
+        self.right_line= SideInteractor(self, self.base.subplot,color='black', zorder=zorder,
+                                     r=self.qmax,
+                                           phi= -1*self.phi,
+                                           theta2=self.theta2)
+        self.right_line.qmax = self.qmax
+        ## Left Side line 
+        self.left_line= SideInteractor(self, self.base.subplot,color='black', zorder=zorder,
+                                     r=self.qmax,
+                                           phi= self.phi,
+                                           theta2=self.theta2)
+        self.left_line.qmax = self.qmax
+        ## draw the sector               
+        self.update()
+        self._post_data()
+
+        
+    def clear(self):
+        """
+            Clear the slicer and all connected events related to this slicer
+        """
+        self.clear_markers()
+        self.main_line.clear()
+        self.left_line.clear()
+        self.right_line.clear()
+        self.base.connect.clearall()
+        #self.base.Unbind(EVT_SLICER_PARS)
+        
+        
+    def update(self):
+        """
+            Respond to changes in the model by recalculating the profiles and
+            resetting the widgets.
+        """
+        # Update locations  
+        ## Check if the middle line was dragged and update the picture accordingly     
+        if self.main_line.has_move:
+            self.main_line.update()
+            self.right_line.update( delta= -self.left_line.phi/2,
+                                    mline= self.main_line.theta )
+            self.left_line.update( delta = self.left_line.phi/2,
+                                   mline= self.main_line.theta )
+        ## Check if the left side has moved and update the slicer accordingly  
+        if self.left_line.has_move:
+            self.main_line.update()
+            self.left_line.update( phi=None, delta=None, mline=self.main_line ,
+                                  side=True, left=True )
+            self.right_line.update( phi= self.left_line.phi, delta= None,
+                                     mline= self.main_line, side= True,
+                                     left=False, right= True )
+        ## Check if the right side line has moved and update the slicer accordingly
+        if self.right_line.has_move:
+            self.main_line.update()
+            self.right_line.update( phi=None, delta=None, mline=self.main_line,
+                                   side=True, left=False, right=True )
+            self.left_line.update( phi=self.right_line.phi, delta=None,
+                                    mline=self.main_line, side=True, left=False )
+        #if self.is_inside != None:
+        out = self._post_data()
+        return out
+
+    def save(self, ev):
+        """
+        Remember the roughness for this layer and the next so that we
+        can restore on Esc.
+        """
+        self.base.freeze_axes()
+        self.main_line.save(ev)
+        self.right_line.save(ev)
+        self.left_line.save(ev)
+
+    def _post_data(self):
+        """
+            compute sector averaging of data into data1D
+        """
+        ## get the data to average
+        data = self.base.data
+        # If we have no data, just return
+        if data == None:
+            return
+
+        mask = data.mask
+        ## Averaging
+        from DataLoader.manipulations import Sectorcut
+        radius = self.qmax 
+        phimin =  -self.left_line.phi + self.main_line.theta
+        phimax = self.left_line.phi + self.main_line.theta
+         
+        mask = Sectorcut(phi_min= phimin, phi_max= phimax)
+        
+        if self.is_inside:
+            out = (mask(data)==False)
+        else:
+            out = (mask(data))
+        #self.base.data.mask=out
+        return out       
+
+    def moveend(self, ev):
+        """
+            Called a dragging motion ends.Get slicer event 
+        """
+        self.base.thaw_axes()
+        ## Post parameters
+        event = SlicerParameterEvent()
+        event.type = self.__class__.__name__
+        event.params = self.get_params()
+        ## Send slicer paramers to plotter2D
+        wx.PostEvent(self.base, event)
+        self._post_data()
+            
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self.main_line.restore()
+        self.left_line.restore()
+        self.right_line.restore()
+
+    def move(self, x, y, ev):
+        """
+        Process move to a new position, making sure that the move is allowed.
+        """
+        pass
+        
+        
+    def set_cursor(self, x, y):
+        pass
+        
+        
+    def get_params(self):
+        """
+            Store a copy of values of parameters of the slicer into a dictionary.
+            @return params: the dictionary created
+        """
+        params = {}
+        ## Always make sure that the left and the right line are at phi 
+        ## angle of the middle line
+        if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
+            raise ValueError,"Phi left and phi right are different %f, %f"%(self.left_line.phi, self.right_line.phi)
+        
+        params["Phi"] = self.main_line.theta
+        params["Delta_Phi"] = math.fabs(self.left_line.phi)
+        return params
+    
+    
+    def set_params(self, params):
+        """
+            Receive a dictionary and reset the slicer with values contained 
+            in the values of the dictionary.
+            @param params: a dictionary containing name of slicer parameters and 
+            values the user assigned to the slicer.
+        """
+        main = params["Phi"] 
+        phi = math.fabs(params["Delta_Phi"] )
+        
+        self.main_line.theta= main
+        ## Reset the slicer parameters
+        self.main_line.update()
+        self.right_line.update( phi=phi,delta=None, mline=self.main_line,
+                               side=True, right=True )
+        self.left_line.update( phi=phi, delta=None, mline=self.main_line, side=True )
+        ## post the new corresponding data
+        self._post_data()
+        
+        
+    def freeze_axes(self):
+        self.base.freeze_axes()
+        
+        
+    def thaw_axes(self):
+        self.base.thaw_axes()
+
+
+    def draw(self):
+        self.base.update()
+        
