Index: guiframe/local_perspectives/plotting/Arc.py
===================================================================
--- guiframe/local_perspectives/plotting/Arc.py	(revision b06ef8cb70788b49507ed818acd3b911d08edcbc)
+++ guiframe/local_perspectives/plotting/Arc.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
@@ -34,5 +34,5 @@
                                       color=self.color)
         self.npts = 20
-            
+        self.has_move= False    
         self.connect_markers([self.inner_circle])
         self.update()
@@ -115,4 +115,5 @@
 
     def moveend(self, ev):
+        self.has_move= False
         self.base.moveend(ev)
             
@@ -131,5 +132,5 @@
         self._inner_mouse_x = x
         self._inner_mouse_y = y
-      
+        self.has_move= True
         self.base.base.update()
         
Index: guiframe/local_perspectives/plotting/DataPanel.py
===================================================================
--- guiframe/local_perspectives/plotting/DataPanel.py	(revision 768656ee3fc923f226cb348145fb3cfb09f09903)
+++ guiframe/local_perspectives/plotting/DataPanel.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
@@ -18,5 +18,8 @@
 from sans.guicomm.events import StatusEvent ,NewPlotEvent
 
+
+from SlicerParameters import SlicerEvent
 from binder import BindArtist
+(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
 #from SlicerParameters import SlicerEvent
 #(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
@@ -375,5 +378,5 @@
         self.slicer_z = 5
         self.slicer = None
-        #self.parent.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
+        self.parent.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
         self.axes_frozen = False
         ## Graph        
@@ -457,8 +460,10 @@
         
         id = wx.NewId()
-        slicerpop.Append(id, '&Sector')
-        wx.EVT_MENU(self, id, self.onSector) 
-        
-        
+        slicerpop.Append(id, '&Sector Q')
+        wx.EVT_MENU(self, id, self.onSectorQ) 
+        
+        id = wx.NewId()
+        slicerpop.Append(id, '&Sector Phi')
+        wx.EVT_MENU(self, id, self.onSectorPhi) 
       
         
@@ -524,12 +529,92 @@
         #self.slicer.update()
         self.draw()
+        
+        
+    def _getEmptySlicerEvent(self):
+        return SlicerEvent(type=None,
+                           params=None,
+                           obj_class=None)
+    def _onEVT_INTERNAL(self, event):
+        """
+            I don't understand why Unbind followed by a Bind
+            using a modified self.slicer doesn't work.
+            For now, I post a clear event followed by
+            a new slicer event...
+        """
+        self._setSlicer(event.slicer)
+            
+    def _setSlicer(self, slicer):
+        # Clear current slicer
+        #printEVT("Plotter2D._setSlicer %s" % slicer)
+        
+        if not self.slicer == None:  
+            self.slicer.clear()            
+            
+        self.slicer_z += 1
+        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
+        self.subplot.set_ylim(-self.qmax, self.qmax)
+        self.subplot.set_xlim(-self.qmax, self.qmax)
+        self.update()
+        self.slicer.update()
+        
+        # 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.parent, event)
+
     def onCircular(self, event):
         """
-            perform circular averaging
-        """
+            perform circular averaging on Data2D
+        """
+        
         from DataLoader.manipulations import CircularAverage
-    def onSector(self, event):
-        """
-            Perform sector averaging
+        Circle = CircularAverage( r_min= -self.qmax, r_max= self.qmax, bin_width=0.001)
+        circ = Circle(self.data2D)
+        from sans.guiframe.dataFitting import Data1D
+        if hasattr(circ,"dxl"):
+            dxl= circ.dxl
+        else:
+            dxl= None
+        if hasattr(circ,"dxw"):
+            dxw= circ.dxw
+        else:
+            dxw= None
+            
+        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
+        new_plot.name = "Circ avg "+ self.data2D.name
+        new_plot.source=self.data2D.source
+        new_plot.info=self.data2D.info
+        new_plot.interactive = True
+        #print "loader output.detector",output.source
+        new_plot.detector =self.data2D.detector
+        
+        # If the data file does not tell us what the axes are, just assume...
+        new_plot.xaxis("\\rm{q}","A^{-1}")
+        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
+        new_plot.group_id = "Circ avg "+ self.data2D.name
+        self.scale = 'log'
+        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
+        
+        
+        
+    def onSectorQ(self, event):
+        """
+            Perform sector averaging on Q
+        """
+        from SectorSlicer import SectorInteractorQ
+              
+        self.slicer_z += 1
+        self.slicer = SectorInteractorQ(self, self.subplot, zorder=self.slicer_z)
+        self.subplot.set_ylim(-self.qmax, self.qmax)
+        self.subplot.set_xlim(-self.qmax, self.qmax)
+        self.update()
+        self.slicer.update()
+        
+        
+    def onSectorPhi(self, event):
+        """
+            Perform sector averaging on Phi
         """
         from SectorSlicer import SectorInteractor
@@ -544,6 +629,15 @@
        
     def onClearSlicer(self, event):
-        print "on clear"  
-        
+        """
+            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.parent, event)
           
     def _onEditDetector(self, event):
@@ -553,5 +647,5 @@
     def _onToggleScale(self, event):
         """
-            toggle axis and replot image
+            toggle pixel scale and replot image
         """
         if self.scale == 'log':
@@ -562,4 +656,9 @@
                    self.ymax_2D,self.zmin_2D ,self.zmax_2D )
         wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
+        
+        
+        
+        
+        
         
 class View1DModelPanel2D( View1DPanel2D):
Index: guiframe/local_perspectives/plotting/Edge.py
===================================================================
--- guiframe/local_perspectives/plotting/Edge.py	(revision b06ef8cb70788b49507ed818acd3b911d08edcbc)
+++ guiframe/local_perspectives/plotting/Edge.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
@@ -41,5 +41,5 @@
        
         self.npts = 20
-      
+        self.has_move= False
         self.connect_markers([self.line])
         self.update()
@@ -94,4 +94,5 @@
    
     def moveend(self, ev):
+        self.has_move= False
         self.base.moveend(ev)
             
@@ -108,5 +109,5 @@
         self.theta= math.atan2(y,x)
         
-        
+        self.has_move= True
         self.base.base.update()
         
Index: guiframe/local_perspectives/plotting/SectorSlicer.py
===================================================================
--- guiframe/local_perspectives/plotting/SectorSlicer.py	(revision 768656ee3fc923f226cb348145fb3cfb09f09903)
+++ guiframe/local_perspectives/plotting/SectorSlicer.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
@@ -55,5 +55,4 @@
         self.update()
         self._post_data()
-        
         # Bind to slice parameter events
         #self.base.parent.Bind(SlicerParameters.EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
@@ -67,10 +66,10 @@
             self.base.update()
 
-
+    """
     def update_and_post(self):
         self.update()
         self._post_data()
 
-
+    """
     def save_data(self, path, image, x, y):
         output = open(path, 'w')
@@ -91,4 +90,6 @@
         self.outer_circle.clear()
         self.inner_circle.clear()
+        self.inner_radius.clear()
+        self.outer_radius.clear()
         #self.base.connect.disconnect()
         #self.base.parent.Unbind(SlicerParameters.EVT_SLICER_PARS)
@@ -99,20 +100,31 @@
         resetting the widgets.
         """
-        # Update locations        
-        self.inner_circle.update()
-        self.outer_circle.update()
-        r1=self.inner_circle.get_radius()
-        r2=self.outer_circle.get_radius()
-        #print"annulus update",r1, r2
-        if self.inner_radius.update(r1,r2)==1:
-            #print "went here"
+        # Update locations   
+        if self.inner_circle.has_move:    
+            print "inner circle has moved" 
+            self.inner_circle.update()
+            r1=self.inner_circle.get_radius()
+            r2=self.outer_circle.get_radius()
+            self.inner_radius.update(r1,r2)
+            self.outer_radius.update(r1,r2)
+        if self.outer_circle.has_move:    
+            print "outer circle has moved" 
+            self.outer_circle.update()
+            r1=self.inner_circle.get_radius()
+            r2=self.outer_circle.get_radius()
+            self.inner_radius.update(r1,r2)
+            self.outer_radius.update(r1,r2)
+        if self.inner_radius.has_move:
+            print "inner radius has moved"
+            self.inner_radius.update()
             self.inner_circle.update(theta1=self.inner_radius.get_radius(), theta2=None)
-            self.outer_circle.update(theta1=self.inner_radius.get_radius(),theta2=None)
-        
-        if self.outer_radius.update(r1,r2)==1:#self.outer_circle.update(self.outer_radius.get_radius())
+            self.outer_circle.update(theta1=self.inner_radius.get_radius(), theta2=None)
+        if  self.outer_radius.has_move:
+             print "outer radius has moved"
+             self.outer_radius.update()
              self.inner_circle.update(theta1=None, theta2=self.outer_radius.get_radius())
-             self.outer_circle.update(theta1=None,theta2=self.outer_radius.get_radius())
-    
-
+             self.outer_circle.update(theta1=None, theta2=self.outer_radius.get_radius())
+             
+        
     def save(self, ev):
         """
@@ -123,47 +135,31 @@
         self.inner_circle.save(ev)
         self.outer_circle.save(ev)
-
     def _post_data(self):
-        """ post data"""
+        pass
+    def post_data(self,new_sector ):
+        """ post data averaging in Q"""
         rmin=self.inner_circle.get_radius()
         rmax=self.outer_circle.get_radius()
         phimin=self.inner_radius.get_radius()
         phimax=self.outer_radius.get_radius()
-        from DataLoader.manipulations import SectorQ, SectorPhi
-        sectQ = SectorQ(r_min=rmin, r_max=rmax, phi_min=phimin, phi_max=phimax)
-        sectorQ = sectQ(self.base.data2D)
-        
-        sectPhi = SectorPhi(r_min=rmin, r_max=rmax, phi_min=phimin, phi_max=phimax)
-        sectorPhi = sectPhi(self.base.data2D)
+        #from DataLoader.manipulations import SectorQ
+        sect = new_sector(r_min=rmin, r_max=rmax, phi_min=phimin, phi_max=phimax)
+        sector = sect(self.base.data2D)
+        
         from sans.guiframe.dataFitting import Data1D
-        if hasattr(sectorQ,"dxl"):
-            dxl= sectorQ.dxl
+        if hasattr(sector,"dxl"):
+            dxl= sector.dxl
         else:
             dxl= None
-        if hasattr(sectorQ,"dxw"):
-            dxw= sectorQ.dxw
+        if hasattr(sector,"dxw"):
+            dxw= sector.dxw
         else:
             dxw= None
             
-        new_plot1 = Data1D(x=sectorQ.x,y=sectorQ.y,dy=sectorQ.dy,dxl=dxl,dxw=dxw)
-        new_plot1.name = "SectorQ ("+ self.base.data2D.name+")"
-        if hasattr(sectorPhi,"dxl"):
-            dxl= sectorPhi.dxl
-        else:
-            dxl= None
-        if hasattr(sectorPhi,"dxw"):
-            dxw= sectorPhi.dxw
-        else:
-            dxw= None
-        new_plot2 = Data1D(x=sectorPhi.x,y=sectorPhi.y,dy=sectorPhi.dy,dxl=dxl,dxw=dxw)
-        new_plot2.name = "SectorPhi ("+ self.base.data2D.name+")"
-        self.plot_data( new_plot1)
-        self.plot_data( new_plot2)
-        
-        
-    def plot_data(self, new_plot): 
-        """
-             plot a new data 1D corresponding to the phi and Q sector average
-        """
+        new_plot = Data1D(x=sector.x,y=sector.y,dy=sector.dy,dxl=dxl,dxw=dxw)
+        new_plot.name = str(new_sector.__name__) +"("+ self.base.data2D.name+")"
+        
+       
+
         new_plot.source=self.base.data2D.source
         new_plot.info=self.base.data2D.info
@@ -175,5 +171,6 @@
         new_plot.yaxis(self.base.data2D._yaxis,self.base.data2D._yunit)
         new_plot.group_id = "sector"+self.base.data2D.name
-        wx.PostEvent(self.base.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
+        wx.PostEvent(self.base.parent, NewPlotEvent(plot=new_plot,
+                                                 title=str(new_sector.__name__) ))
         
         
@@ -209,6 +206,6 @@
         params["inner_radius"] = self.inner_circle._inner_mouse_x
         params["outer_radius"] = self.outer_circle._inner_mouse_x
-        params["phi_min"] = self.inner_radious.get_radious()
-        params["phi_max"] = self.inner_radious.get_radious()
+        params["phi_min"] = self.inner_radius.get_radius()
+        params["phi_max"] = self.inner_radius.get_radius()
         params["nbins"] = self.nbins
         return params
@@ -218,7 +215,13 @@
         inner = params["inner_radius"] 
         outer = params["outer_radius"] 
+        phi_min= params["phi_min"]
+        phi_min=params["phi_max"]
         self.nbins = int(params["nbins"])
+        
+        
         self.inner_circle.set_cursor(inner, self.inner_circle._inner_mouse_y)
         self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y)
+        self.inner_radius.set_cursor(inner, self.inner_circle._inner_mouse_y)
+        self.outer_radius.set_cursor(outer, self.outer_circle._inner_mouse_y)
         self._post_data()
         
@@ -232,3 +235,10 @@
         self.base.draw()
 
-    
+class SectorInteractorQ(SectorInteractor):
+    def __init__(self,base,axes,color='black', zorder=3):
+        SectorInteractor.__init__(self, base, axes, color=color)
+        self.base=base
+        self._post_data()
+    def _post_data(self):
+        from DataLoader.manipulations import SectorQ
+        self.post_data(SectorQ )   
Index: guiframe/local_perspectives/plotting/boxSlicer.py
===================================================================
--- guiframe/local_perspectives/plotting/boxSlicer.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
+++ guiframe/local_perspectives/plotting/boxSlicer.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
@@ -0,0 +1,507 @@
+#TODO: the line slicer should listen to all 2DREFRESH events, get the data and slice it
+#      before pushing a new 1D data update.
+
+#
+#TODO: NEED MAJOR REFACTOR
+#
+
+
+# Debug printout
+from config import printEVT
+from BaseInteractor import _BaseInteractor
+from copy import deepcopy
+import math
+
+from Plotter1D import AddPlotEvent
+import SlicerParameters
+import wx
+
+class AnnulusInteractor(_BaseInteractor):
+    """
+         Select an annulus through a 2D plot
+    """
+    def __init__(self,base,axes,color='black', zorder=3, x_min=0.025, x_max=0.025, y_min=0.025, y_max=0.025):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        self.markers = []
+        self.axes = axes
+        self.qmax = self.base.qmax
+        self.connect = self.base.connect
+        self.xmin=xmin
+        self.ymin=ymin
+        self.xmax=xmax
+        self.ymax=ymax
+        ## Number of points on the plot
+        self.nbins = 20
+        
+        #self.theta3= 2*self.theta2 -self.theta1
+        # Inner circle
+        self.left_line = VerticalLine(self, self.base.subplot,color='blue', zorder=zorder, 
+                                        ymin=-1*self.ymin, ymax=self.ymax,
+                                        xmin=-1*self.xmin,xmax=-1*self.xmax)
+        self.left_line.qmax = self.base.qmax
+        
+        self.right_line= VerticalLine(self, self.base.subplot,color='black', zorder=zorder,
+                                     ymin=-1*self.ymin, ymax=self.ymax,
+                                     xmin=self.xmin,xmax=self.xmax)
+        self.right_line.qmax = self.base.qmax
+        
+        self.top_line= HorizontalLine(self, self.base.subplot,color='green', zorder=zorder,
+                                    ymin=self.ymax, ymax=self.ymax,
+                                    xmin=-1*self.xmax,xmax=self.xmax)
+        self.top_line.qmax = self.base.qmax
+        
+        self.bottom_line= HorizontalLine(self, self.base.subplot,color='red', zorder=zorder,
+                                    ymin=-1*self.ymin, ymax=-1*self.ymin,
+                                    xmin=-1*self.xmin,xmax=self.xmin)
+        self.bottom_line.qmax = self.base.qmax
+        #self.outer_circle.set_cursor(self.base.qmax/1.8, 0)
+        
+                      
+        #self.update()
+        self._post_data()
+        
+        # Bind to slice parameter events
+        self.base.parent.Bind(SlicerParameters.EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
+
+
+    def _onEVT_SLICER_PARS(self, event):
+        printEVT("AnnulusSlicer._onEVT_SLICER_PARS")
+        event.Skip()
+        if event.type == self.__class__.__name__:
+            #self.set_params(event.params)
+            self.base.update()
+
+    def update_and_post(self):
+        self.update()
+        self._post_data()
+
+    def save_data(self, path, image, x, y):
+        output = open(path, 'w')
+        
+        data_x, data_y = self.get_data(image, x, y)
+        
+        output.write("<phi>  <average>\n")
+        for i in range(len(data_x)):
+            output.write("%g  %g\n" % (data_x[i], data_y[i]))
+        output.close()
+
+    def set_layer(self, n):
+        self.layernum = n
+        self.update()
+        
+    def clear(self):
+        self.clear_markers()
+        self.outer_circle.clear()
+        self.inner_circle.clear()
+        #self.base.connect.disconnect()
+        self.base.parent.Unbind(SlicerParameters.EVT_SLICER_PARS)
+        
+    def update(self):
+        """
+        Respond to changes in the model by recalculating the profiles and
+        resetting the widgets.
+        """
+        if self.left_line.has_move:
+            print "left has moved"
+            self.left_line.update()
+            self.right_line.update()
+            #self.right_line.update(xmin= self.left_line.x ,xmax=-1*self.left_line.x)
+            self.top_line.update( xmin= self.left_line.x ,xmax= self.right_line.x)
+            self.bottom_line.update(xmin= self.left_line.x ,xmax= self.right_line.x)
+        if self.right_line.has_move:
+            print "right has moved"
+            self.right_line.update()
+            self.left_line.update()
+            #self.left_line.update(xmin= self.right_line.x ,xmax=-1*self.right_line.x)
+            self.top_line.update( xmin= self.left_line.x ,xmax= self.right_line.x)
+            self.bottom_line.update(xmin= self.left_line.x ,xmax= self.right_line.x)
+            
+            
+        if self.bottom_line.has_move:
+            print "bottom has moved"
+            self.bottom_line.update()
+            self.top_line.update()
+            #self.top_line.update(ymin= -1*self.bottom_line.y ,ymax=-1*self.bottom_line.y)
+            self.left_line.update( ymin= self.bottom_line.y ,ymax= self.top_line.y)
+            self.right_line.update(ymin= self.bottom_line.y ,ymax= self.top_line.y)
+            
+        if self.top_line.has_move:
+            print "top has moved"
+            self.top_line.update()
+            #self.bottom_line.update()
+            self.bottom_line.update(ymin= -1*self.top_line.y ,ymax=-1*self.top_line.y)
+            self.left_line.update(ymin= self.bottom_line.y ,ymax= self.top_line.y)
+            self.right_line.update(ymin= self.bottom_line.y ,ymax= self.top_line.y)
+            
+    def get_data(self, image, x, y):
+        """ 
+            Return a 1D vector corresponding to the slice
+            @param image: data matrix
+            @param x: x matrix
+            @param y: y matrix
+        """
+        # If we have no data, just return
+        if image == None:
+            return        
+        
+        nbins = self.nbins
+        
+        data_x = nbins*[0]
+        data_y = nbins*[0]
+        counts = nbins*[0]
+        length = len(image)
+        print "length x , y , image", len(x), len(y), length
+        
+        for i_x in range(length):
+            for i_y in range(length):
+                        
+                q = math.sqrt(x[i_x]*x[i_x] + y[i_y]*y[i_y])
+                if (q>self.inner_circle._inner_mouse_x \
+                    and q<self.outer_circle._inner_mouse_x) \
+                    or (q<self.inner_circle._inner_mouse_x \
+                    and q>self.outer_circle._inner_mouse_x):
+                            
+                    i_bin = int(math.ceil(nbins*(math.atan2(y[i_y], x[i_x])+math.pi)/(2.0*math.pi)) - 1)
+                    
+                    
+                    #data_y[i_bin] += math.exp(image[i_x][i_y])
+                    data_y[i_bin] += image[i_y][i_x]
+                    counts[i_bin] += 1.0
+                    
+        for i in range(nbins):
+            data_x[i] = (1.0*i+0.5)*2.0*math.pi/nbins
+            if counts[i]>0:
+                data_y[i] = data_y[i]/counts[i]
+        
+        return data_x, data_y
+
+    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.inner_circle.save(ev)
+        self.outer_circle.save(ev)
+
+    def _post_data(self):
+        # Compute data
+        data = self.base.get_corrected_data()
+        # If we have no data, just return
+        if data == None:
+            return
+
+        data_x, data_y = self.get_data(data, self.base.x, self.base.y)
+        
+        name = "Ring"
+        if hasattr(self.base, "name"):
+            name += " %s" % self.base.name
+        
+        wx.PostEvent(self.base.parent, AddPlotEvent(name=name,
+                                               x = data_x,
+                                               y = data_y,
+                                               qmin = self.inner_circle._inner_mouse_x,
+                                               qmax = self.outer_circle._inner_mouse_x,
+                                               yscale = 'log',
+                                               variable = 'ANGLE',
+                                               ylabel = "\\rm{Intensity} ",
+                                               yunits = "cm^{-1}",
+                                               xlabel = "\\rm{\phi}",
+                                               xunits = "rad",
+                                               parent = self.base.__class__.__name__))
+                                               
+        
+    def moveend(self, ev):
+        self.base.thaw_axes()
+        
+        # Post paramters
+        event = SlicerParameters.SlicerParameterEvent()
+        event.type = self.__class__.__name__
+        #event.params = self.get_params()
+        wx.PostEvent(self.base.parent, event)
+
+        self._post_data()
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self.inner_circle.restore()
+        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):
+        params = {}
+        #params["main_phi"] = self.right_line.get_radius()
+        #params["left_phi"] = self.left_line.get_radius()
+        
+        params["nbins"] = self.nbins
+        return params
+    
+    def set_params(self, params):
+        
+        main = params["main_phi"] 
+        left = params["left_phi"] 
+       
+        self.nbins = int(params["nbins"])
+        #self.main_line.set_cursor(inner, self.inner_circle._inner_mouse_y)
+        #self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y)
+        self._post_data()
+        
+    def freeze_axes(self):
+        self.base.freeze_axes()
+        
+    def thaw_axes(self):
+        self.base.thaw_axes()
+
+    def draw(self):
+        self.base.draw()
+
+class HorizontalLine(_BaseInteractor):
+    """
+         Select an annulus through a 2D plot
+    """
+    def __init__(self,base,axes,color='black', zorder=5, ymin=0.0, ymax=0.5,xmin=0.0,xmax=0.5):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        self.markers = []
+        self.axes = axes
+        
+        self.y=ymin
+        self.save_y=ymin
+        
+        self.xmin=xmin
+        self.save_xmin=xmin
+        self.xmax=xmax
+        self.save_xmax=xmax
+        
+        self.line = self.axes.plot([self.xmin,self.xmax],[self.y,self.y],
+                                      linestyle='-', marker='',
+                                      color=self.color,
+                                      visible=True)[0]
+      
+        self.npts = 20
+        self.has_move=False
+        self.connect_markers([self.line])
+        self.update()
+
+    def set_layer(self, n):
+        self.layernum = n
+        self.update()
+        
+    def clear(self):
+        self.clear_markers()
+        try:
+            
+            self.line.remove()
+        except:
+            # Old version of matplotlib
+            for item in range(len(self.axes.lines)):
+                del self.axes.lines[0]
+        
+        
+        
+    def get_radius(self):
+        
+        return 0
+        
+    def update(self,xmin=None, xmax=None,ymin=None, ymax=None):
+        """
+        Draw the new roughness on the graph.
+        """
+        #print "update main line", self.has_move
+        if xmin !=None:
+            self.xmin=xmin
+        if xmax !=None:
+            self.xmax=xmax
+        if ymin !=None:
+            self.y=ymin
+        if ymax !=None:
+            self.y = ymax
+        self.line.set(xdata=[self.xmin,self.xmax], ydata=[self.y,self.y])
+     
+        
+        
+    def save(self, ev):
+        """
+        Remember the roughness for this layer and the next so that we
+        can restore on Esc.
+        """
+        self.save_xmin= self.xmin
+        self.save_xmax= self.xmax
+       
+        self.save_y= self.y
+        self.base.freeze_axes()
+
+    def moveend(self, ev):
+        
+        self.has_move=False
+        self.base.moveend(ev)
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self.ymin = self.save_ymin
+        self.ymax = self.save_ymax
+
+    def move(self, x, y, ev):
+        """
+        Process move to a new position, making sure that the move is allowed.
+        """
+        self.y=y
+       
+        
+        self.has_move=True
+        self.base.base.update()
+        
+    def set_cursor(self, x, y):
+        self.move(x, y, None)
+        self.update()
+        
+        
+    def get_params(self):
+        params = {}
+        params["radius"] = self.xmin
+        params["theta"] = self.xmax
+        return params
+    
+    def set_params(self, params):
+
+        x = params["radius"] 
+        self.set_cursor(x, self._inner_mouse_y)
+        
+
+
+
+class VerticalLine(_BaseInteractor):
+    """
+         Select an annulus through a 2D plot
+    """
+    def __init__(self,base,axes,color='black', zorder=5, ymin=0.0, ymax=0.5,xmin=0.0,xmax=0.5):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        self.markers = []
+        self.axes = axes
+        
+        self.x=xmin
+        self.save_x=xmin
+        
+        self.ymin=ymin
+        self.save_ymin=ymin
+        self.ymax=ymax
+        self.save_ymax=ymax
+        
+        self.line = self.axes.plot([self.x,self.x],[self.ymin,self.ymax],
+                                      linestyle='-', marker='',
+                                      color=self.color,
+                                      visible=True)[0]
+      
+        self.npts = 20
+        self.has_move=False
+        self.connect_markers([self.line])
+        self.update()
+
+    def set_layer(self, n):
+        self.layernum = n
+        self.update()
+        
+    def clear(self):
+        self.clear_markers()
+        try:
+            
+            self.line.remove()
+        except:
+            # Old version of matplotlib
+            for item in range(len(self.axes.lines)):
+                del self.axes.lines[0]
+        
+        
+        
+    def get_radius(self):
+        
+        return 0
+        
+    def update(self,xmin=None, xmax=None,ymin=None, ymax=None):
+        """
+        Draw the new roughness on the graph.
+        """
+        
+        if xmin !=None:
+            self.x=xmin
+        if xmin !=None:
+            self.x=xmax
+        if ymin !=None:
+            self.ymin=ymin
+        if ymax !=None:
+            self.ymax=ymax
+        print "update vertical line", self.has_move,[self.x,self.x], [self.ymin,self.ymax]
+        self.line.set(xdata=[self.x,self.x], ydata=[self.ymin,self.ymax])
+     
+        
+        
+    def save(self, ev):
+        """
+        Remember the roughness for this layer and the next so that we
+        can restore on Esc.
+        """
+        self.save_x= self.x
+      
+        self.save_ymin= self.ymin
+        self.save_ymax= self.ymax
+        self.base.freeze_axes()
+
+    def moveend(self, ev):
+        
+        self.has_move=False
+        self.base.moveend(ev)
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self.x = self.save_x
+        
+        self.ymin=self.save_ymin
+        self.ymax=self.save_ymax
+    def move(self, x, y, ev):
+        """
+        Process move to a new position, making sure that the move is allowed.
+        """
+        self.x=x
+        
+        
+        
+        self.has_move=True
+        self.base.base.update()
+        
+    def set_cursor(self, x, y):
+        self.move(x, y, None)
+        self.update()
+        
+        
+    def get_params(self):
+        params = {}
+        params["radius"] = self.xmin
+        params["theta"] = self.xmax
+        params["radius"] = self.xmin
+        params["theta"] = self.xmax
+        return params
+    
+    def set_params(self, params):
+
+        x = params["radius"] 
+        self.set_cursor(x, self._inner_mouse_y)
+        
+
+
+        
Index: guiframe/local_perspectives/plotting/ring.py
===================================================================
--- guiframe/local_perspectives/plotting/ring.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
+++ guiframe/local_perspectives/plotting/ring.py	(revision 2d107b883288e417fcd3b30f942cda5fd43b54c7)
@@ -0,0 +1,346 @@
+#TODO: the line slicer should listen to all 2DREFRESH events, get the data and slice it
+#      before pushing a new 1D data update.
+
+#
+#TODO: NEED MAJOR REFACTOR
+#
+
+
+# Debug printout
+from config import printEVT
+from BaseInteractor import _BaseInteractor
+from copy import deepcopy
+import math
+
+from Plotter1D import AddPlotEvent
+import SlicerParameters
+import wx
+
+class AnnulusInteractor(_BaseInteractor):
+    """
+         Select an annulus through a 2D plot
+    """
+    def __init__(self,base,axes,color='black', zorder=3):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        self.markers = []
+        self.axes = axes
+        self.qmax = self.base.qmax
+        self.connect = self.base.connect
+        
+        ## Number of points on the plot
+        self.nbins = 20
+
+        # Inner circle
+        self.inner_circle = RingInteractor(self, self.base.subplot, zorder=zorder, r=self.qmax/2.0)
+        self.inner_circle.qmax = self.base.qmax
+      
+        #self.outer_circle.set_cursor(self.base.qmax/1.8, 0)
+        
+                      
+        self.update()
+        self._post_data()
+        
+        # Bind to slice parameter events
+        self.base.parent.Bind(SlicerParameters.EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
+
+
+    def _onEVT_SLICER_PARS(self, event):
+        printEVT("AnnulusSlicer._onEVT_SLICER_PARS")
+        event.Skip()
+        if event.type == self.__class__.__name__:
+            self.set_params(event.params)
+            self.base.update()
+
+    def update_and_post(self):
+        self.update()
+        self._post_data()
+
+    def save_data(self, path, image, x, y):
+        output = open(path, 'w')
+        
+        data_x, data_y = self.get_data(image, x, y)
+        
+        output.write("<phi>  <average>\n")
+        for i in range(len(data_x)):
+            output.write("%g  %g\n" % (data_x[i], data_y[i]))
+        output.close()
+
+    def set_layer(self, n):
+        self.layernum = n
+        self.update()
+        
+    def clear(self):
+        self.clear_markers()
+       
+        self.inner_circle.clear()
+        #self.base.connect.disconnect()
+        self.base.parent.Unbind(SlicerParameters.EVT_SLICER_PARS)
+        
+    def update(self):
+        """
+        Respond to changes in the model by recalculating the profiles and
+        resetting the widgets.
+        """
+        # Update locations        
+        self.inner_circle.update()
+       
+        
+        
+    def get_data(self, image, x, y):
+        """ 
+            Return a 1D vector corresponding to the slice
+            @param image: data matrix
+            @param x: x matrix
+            @param y: y matrix
+        """
+        # If we have no data, just return
+        if image == None:
+            return        
+        
+        nbins = self.nbins
+        
+        data_x = nbins*[0]
+        data_y = nbins*[0]
+        counts = nbins*[0]
+        length = len(image)
+        print "length x , y , image", len(x), len(y), length
+        
+        for i_x in range(length):
+            for i_y in range(length):
+                        
+                q = math.sqrt(x[i_x]*x[i_x] + y[i_y]*y[i_y])
+                if (q>self.inner_circle._inner_mouse_x \
+                    and q<self.outer_circle._inner_mouse_x) \
+                    or (q<self.inner_circle._inner_mouse_x \
+                    and q>self.outer_circle._inner_mouse_x):
+                            
+                    i_bin = int(math.ceil(nbins*(math.atan2(y[i_y], x[i_x])+math.pi)/(2.0*math.pi)) - 1)
+                    
+                    
+                    #data_y[i_bin] += math.exp(image[i_x][i_y])
+                    data_y[i_bin] += image[i_y][i_x]
+                    counts[i_bin] += 1.0
+                    
+        for i in range(nbins):
+            data_x[i] = (1.0*i+0.5)*2.0*math.pi/nbins
+            if counts[i]>0:
+                data_y[i] = data_y[i]/counts[i]
+        
+        return data_x, data_y
+
+    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.inner_circle.save(ev)
+       
+
+    def _post_data(self):
+        # Compute data
+        data = self.base.get_corrected_data()
+        # If we have no data, just return
+        if data == None:
+            return
+
+        data_x, data_y = self.get_data(data, self.base.x, self.base.y)
+        
+        name = "Ring"
+        if hasattr(self.base, "name"):
+            name += " %s" % self.base.name
+        
+        wx.PostEvent(self.base.parent, AddPlotEvent(name=name,
+                                               x = data_x,
+                                               y = data_y,
+                                               qmin = self.inner_circle._inner_mouse_x,
+                                               qmax = self.outer_circle._inner_mouse_x,
+                                               yscale = 'log',
+                                               variable = 'ANGLE',
+                                               ylabel = "\\rm{Intensity} ",
+                                               yunits = "cm^{-1}",
+                                               xlabel = "\\rm{\phi}",
+                                               xunits = "rad",
+                                               parent = self.base.__class__.__name__))
+                                               
+        
+    def moveend(self, ev):
+        self.base.thaw_axes()
+        
+        # Post paramters
+        event = SlicerParameters.SlicerParameterEvent()
+        event.type = self.__class__.__name__
+        event.params = self.get_params()
+        wx.PostEvent(self.base.parent, event)
+
+        self._post_data()
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self.inner_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):
+        params = {}
+        params["inner_radius"] = self.inner_circle._inner_mouse_x
+       
+        params["nbins"] = self.nbins
+        return params
+    
+    def set_params(self, params):
+        
+        inner = params["inner_radius"] 
+        
+        self.nbins = int(params["nbins"])
+        self.inner_circle.set_cursor(inner, self.inner_circle._inner_mouse_y)
+       
+        self._post_data()
+        
+    def freeze_axes(self):
+        self.base.freeze_axes()
+        
+    def thaw_axes(self):
+        self.base.thaw_axes()
+
+    def draw(self):
+        self.base.draw()
+
+        
+class RingInteractor(_BaseInteractor):
+    """
+         Select an annulus through a 2D plot
+    """
+    def __init__(self,base,axes,color='black', zorder=5, r=1.0):
+        
+        _BaseInteractor.__init__(self, base, axes, color=color)
+        self.markers = []
+        self.axes = axes
+        self._inner_mouse_x = r
+        self._inner_mouse_y = 0
+        self._inner_save_x  = r
+        self._inner_save_y  = 0
+        self.scale = 10.0
+        
+        try:
+            # Inner circle marker
+            self.inner_marker = self.axes.plot([self._inner_mouse_x],[0], linestyle='',
+                                          marker='s', markersize=10,
+                                          color=self.color, alpha=0.6,
+                                          pickradius=5, label="pick", 
+                                          zorder=zorder, # Prefer this to other lines
+                                          visible=True)[0]
+        except:
+            self.inner_marker = self.axes.plot([self._inner_mouse_x],[0], linestyle='',
+                                          marker='s', markersize=10,
+                                          color=self.color, alpha=0.6,
+                                          label="pick", 
+                                          visible=True)[0]
+            message  = "\nTHIS PROTOTYPE NEEDS THE LATEST VERSION OF MATPLOTLIB\n"
+            message += "Get the SVN version that is at least as recent as June 1, 2007"
+            
+            #raise "Version error", message
+            
+        # Inner circle
+
+           
+        [self.inner_circle] = self.axes.plot([],[],
+                                      linestyle='-', marker='',
+                                      color=self.color)
+        self.npts = 20
+            
+        self.connect_markers([self.inner_marker])
+        self.update()
+
+    def set_layer(self, n):
+        self.layernum = n
+        self.update()
+        
+    def clear(self):
+        self.clear_markers()
+        try:
+            self.inner_marker.remove()
+            self.inner_circle.remove()
+        except:
+            # Old version of matplotlib
+            for item in range(len(self.axes.lines)):
+                del self.axes.lines[0]
+        
+        
+        
+    def get_radius(self):
+        return self._inner_mouse_x
+        
+    def update(self):
+        """
+        Draw the new roughness on the graph.
+        """
+        # Plot inner circle
+        x = []
+        y = []
+        for i in range(self.npts):
+            phi = 2.0*math.pi/(self.npts-1)*i
+            
+            xval = 1.0*self._inner_mouse_x*math.cos(phi) 
+            yval = 1.0*self._inner_mouse_x*math.sin(phi) 
+            
+            x.append(xval)
+            y.append(yval)
+        
+        self.inner_marker.set(xdata=[self._inner_mouse_x],ydata=[0])
+        self.inner_circle.set_data(x, y)        
+
+    def save(self, ev):
+        """
+        Remember the roughness for this layer and the next so that we
+        can restore on Esc.
+        """
+        self._inner_save_x = self._inner_mouse_x
+        self._inner_save_y = self._inner_mouse_y
+        self.base.freeze_axes()
+
+    def moveend(self, ev):
+        self.base.moveend(ev)
+            
+    def restore(self):
+        """
+        Restore the roughness for this layer.
+        """
+        self._inner_mouse_x = self._inner_save_x
+        self._inner_mouse_y = self._inner_save_y
+
+    def move(self, x, y, ev):
+        """
+        Process move to a new position, making sure that the move is allowed.
+        """
+        self._inner_mouse_x = x
+        self._inner_mouse_y = y
+        self.base.base.update()
+        
+    def set_cursor(self, x, y):
+        self.move(x, y, None)
+        self.update()
+        
+        
+    def get_params(self):
+        params = {}
+        params["radius"] = self._inner_mouse_x
+        return params
+    
+    def set_params(self, params):
+
+        x = params["radius"] 
+        self.set_cursor(x, self._inner_mouse_y)
+        
+        
