source: sasview/guiframe/local_perspectives/plotting/SectorSlicer.py @ 72b524b

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 72b524b was 1a6ec25, checked in by Gervaise Alina <gervyh@…>, 16 years ago

renaming variables

  • Property mode set to 100644
File size: 21.6 KB
RevLine 
[ef0c170]1#TODO: the line slicer should listen to all 2DREFRESH events, get the data and slice it
2#      before pushing a new 1D data update.
3
4#
5#TODO: NEED MAJOR REFACTOR
6#
7
8
9# Debug printout
10import math
[0d9dae8]11import wx
12from copy import deepcopy
13
14from BaseInteractor import _BaseInteractor
15from sans.guicomm.events import NewPlotEvent, StatusEvent,SlicerParameterEvent,EVT_SLICER_PARS
16
17
18
[ef0c170]19
20
21
22class SectorInteractor(_BaseInteractor):
23    """
24         Select an annulus through a 2D plot
25    """
26    def __init__(self,base,axes,color='black', zorder=3):
27       
28        _BaseInteractor.__init__(self, base, axes, color=color)
29        self.markers = []
[fbd0bece]30        self.axes = axes       
[0c218d9]31        self.qmax = math.sqrt(math.pow(max(self.base.data2D.xmax,math.fabs(self.base.data2D.xmin)),2)+math.pow(max(self.base.data2D.xmax,math.fabs(self.base.data2D.xmin)),2))
[fbd0bece]32        #print "sector qmax", self.qmax
[ef0c170]33        self.connect = self.base.connect
34       
35        ## Number of points on the plot
[b783024]36        self.nbins = 20
[ef0c170]37        self.theta1= math.pi/4
38        self.theta2= math.pi/3
39        self.phi=math.pi/12
40        #self.theta3= 2*self.theta2 -self.theta1
41        # Inner circle
[e23a20c]42        self.main_line = LineInteractor(self, self.base.subplot,color='green', zorder=zorder, r=self.qmax,
[ef0c170]43                                           theta= self.theta2)
[2dda74ac]44        self.main_line.qmax = self.qmax
[ef0c170]45        #self.left_line = SectionInteractor(self, self.base.subplot, zorder=zorder+1, r=self.qmax,
46        #                                   theta1= self.theta1, theta2= self.theta2)
47        #self.left_line.qmax = self.base.qmax
48        self.right_line= SideInteractor(self, self.base.subplot,color='black', zorder=zorder,
49                                     r=self.qmax,
50                                           phi= -1*self.phi,
51                                           theta2=self.theta2)
[2dda74ac]52        self.right_line.qmax = self.qmax
[e23a20c]53        self.left_line= SideInteractor(self, self.base.subplot,color='blue', zorder=zorder,
[ef0c170]54                                     r=self.qmax,
55                                           phi= self.phi,
56                                           theta2=self.theta2)
[2dda74ac]57        self.left_line.qmax = self.qmax
[ef0c170]58        #self.outer_circle.set_cursor(self.base.qmax/1.8, 0)
59       
60                     
61        self.update()
62        self._post_data()
63       
64        # Bind to slice parameter events
[1ce365f8]65        self.base.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
[ef0c170]66
67    def _onEVT_SLICER_PARS(self, event):
[18eba35]68       
69        wx.PostEvent(self.base.parent, StatusEvent(status="SectorSlicer._onEVT_SLICER_PARS"))
[ef0c170]70        event.Skip()
71        if event.type == self.__class__.__name__:
72            self.set_params(event.params)
73            self.base.update()
74
75    def update_and_post(self):
76        self.update()
77        #self._post_data()
78
79    def save_data(self, path, image, x, y):
80        output = open(path, 'w')
81       
82        data_x, data_y = self.get_data(image, x, y)
83       
84        output.write("<phi>  <average>\n")
85        for i in range(len(data_x)):
86            output.write("%g  %g\n" % (data_x[i], data_y[i]))
87        output.close()
88
89    def set_layer(self, n):
90        self.layernum = n
91        self.update()
92       
93    def clear(self):
94        self.clear_markers()
95        self.main_line.clear()
96        self.left_line.clear()
97        self.right_line.clear()
[18eba35]98        self.base.connect.clearall()
99       
[d468daa]100        self.base.Unbind(EVT_SLICER_PARS)
[ef0c170]101       
102    def update(self):
103        """
104        Respond to changes in the model by recalculating the profiles and
105        resetting the widgets.
106        """
107        # Update locations       
108       
109        #if self.main_line.has_move:
110        #self.main_line.update()   
111        #self.right_line.update()   
112        #self.left_line.update()     
113        if self.main_line.has_move:
114            self.main_line.update()
[31e3298]115            #print "main_theta--->",self.main_line.get_radius()*180/3.14
116            self.right_line.update( delta = -self.left_line.phi/2+math.pi,mline= self.main_line.theta)
117            #print "main_theta--->",self.main_line.get_radius()*180/3.14
118            self.left_line.update( delta = self.left_line.phi/2+math.pi ,mline= self.main_line.theta)
119            #print "main_theta--->",self.main_line.get_radius()*180/3.14
120            #print "Main line has moved ---> phi right",math.degrees(self.main_line.theta),math.degrees(self.main_line.get_radius()),math.degrees(self.main_line.get_radius()+self.right_line.theta)
[7a28ba7]121            #print "Main line has moved ---> phi left",math.degrees(self.left_line.theta+self.main_line.get_radius())
[ef0c170]122        if self.left_line.has_move:
[7a28ba7]123            #print "left line has moved --->"
[ef0c170]124            self.main_line.update()
[e23a20c]125            self.left_line.update(phi=None,delta=None, mline=self.main_line,side=True, left=True)
[ef0c170]126            #self.right_line.update(-1*delta,linem=self.main_line,linel=self.left_line)
[7a28ba7]127            self.right_line.update(phi=self.left_line.phi,delta=None, mline=self.main_line,side=True,left=False, right=True)
128       
[ef0c170]129        if self.right_line.has_move:
[7a28ba7]130       
[ef0c170]131            self.main_line.update()
[7a28ba7]132            self.right_line.update(phi=None,delta=None, mline=self.main_line,side=True, left=False,right=True)
133            #print "right line has moved --->",self.right_line.phi
134            self.left_line.update(phi=self.right_line.phi,delta=None, mline=self.main_line,side=True, left=False)
[ef0c170]135   
[7a28ba7]136       
[ef0c170]137   
138
139    def save(self, ev):
140        """
141        Remember the roughness for this layer and the next so that we
142        can restore on Esc.
143        """
144        self.base.freeze_axes()
145        self.inner_circle.save(ev)
146        self.outer_circle.save(ev)
147
148    def _post_data(self, nbins=None):
149        # Compute data
150        data = self.base.data2D
151        # If we have no data, just return
152        if data == None:
153            return
154
155        name = "Sector "
156        from DataLoader.manipulations import SectorQ
[b783024]157        radius = self.qmax #radius=math.sqrt(math.pow(self.qmax,2)+math.pow(self.qmax,2))
[31e3298]158        phimin =  -self.left_line.phi+self.main_line.theta
159        phimax = self.left_line.phi+self.main_line.theta
[7a28ba7]160        #phimin = min(self.right_line.theta+math.pi,self.left_line.theta+math.pi)
161        #phimax = max(self.right_line.theta+math.pi,self.left_line.theta+math.pi)
[31e3298]162        #print "sector Q angles=",phimin*180/math.pi,phimax*180/math.pi,self.main_line.theta*180/math.pi
163        #phi must be 0 to 2pi with cut-off line sts on the left.
[1ce365f8]164        if nbins==None:
165            nbins = 20
166        sect = SectorQ(r_min=0.0, r_max= radius , phi_min=phimin+math.pi, phi_max=phimax+math.pi, nbins=nbins)
[e23a20c]167        #sect = SectorQ(r_min=-1*radius , r_max= radius , phi_min=phimin, phi_max=phimax)
[1ce365f8]168       
[ef0c170]169       
170        sector = sect(self.base.data2D)
171       
172        from sans.guiframe.dataFitting import Data1D
173        if hasattr(sector,"dxl"):
174            dxl= sector.dxl
175        else:
176            dxl= None
177        if hasattr(sector,"dxw"):
178            dxw= sector.dxw
179        else:
180            dxw= None
181       
182        new_plot = Data1D(x=sector.x,y=sector.y,dy=sector.dy,dxl=dxl,dxw=dxw)
183        new_plot.name = "SectorQ" +"("+ self.base.data2D.name+")"
184       
185       
186
187        new_plot.source=self.base.data2D.source
[8b30e62]188        #new_plot.info=self.base.data2D.info
[ef0c170]189        new_plot.interactive = True
[fbd0bece]190        #print "loader output.detector",self.base.data2D.info,output.source,
[ef0c170]191        new_plot.detector =self.base.data2D.detector
[fbd0bece]192        #print "loader output.detector",new_plot.detector
[ef0c170]193        # If the data file does not tell us what the axes are, just assume...
[e23a20c]194        new_plot.xaxis("\\rm{Q}", 'A^{-1}')
[ef0c170]195        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
196        new_plot.group_id = "SectorQ"+self.base.data2D.name
[8b30e62]197        new_plot.id = "SectorQ"+self.base.data2D.name
[ef0c170]198        wx.PostEvent(self.base.parent, NewPlotEvent(plot=new_plot,
[fbd0bece]199                                                 title="SectorQ"+self.base.data2D.name ))
[ef0c170]200       
201         
202       
203    def moveend(self, ev):
204        self.base.thaw_axes()
205       
206        # Post paramters
[0d9dae8]207        event = SlicerParameterEvent()
[ef0c170]208        event.type = self.__class__.__name__
209        event.params = self.get_params()
[d468daa]210        #wx.PostEvent(self.base.parent, event)
211        wx.PostEvent(self.base, event)
[ef0c170]212        self._post_data()
213           
214    def restore(self):
215        """
216        Restore the roughness for this layer.
217        """
218        self.main_line.restore()
219        self.left_line.restore()
220        self.right_line.restore()
221
222    def move(self, x, y, ev):
223        """
224        Process move to a new position, making sure that the move is allowed.
225        """
226        pass
227       
228    def set_cursor(self, x, y):
229        pass
230       
231    def get_params(self):
232        params = {}
[1a6ec25]233        params["Phi"] = self.main_line.theta
[ef0c170]234        if math.fabs(self.left_line.phi) != math.fabs(self.right_line.phi):
235            raise ValueError,"Phi left and phi right are different %f, %f"%(self.left_line.phi, self.right_line.phi)
[1a6ec25]236        params["Delta_Phi"] = math.fabs(self.left_line.phi)
[ef0c170]237        params["nbins"] = self.nbins
238        return params
239   
240    def set_params(self, params):
241       
[1a6ec25]242        main = params["Phi"] 
243        phi = math.fabs(params["Delta_Phi"] )
[ef0c170]244        self.nbins = int(params["nbins"])
245        self.main_line.theta= main
246       
247        self.main_line.update()
[7a28ba7]248        self.right_line.update(phi=phi,delta=None, mline=self.main_line,side=True,right=True)
[ef0c170]249        self.left_line.update(phi=phi,delta=None, mline=self.main_line,side=True)
250       
251        self._post_data(nbins=self.nbins)
252       
253    def freeze_axes(self):
254        self.base.freeze_axes()
255       
256    def thaw_axes(self):
257        self.base.thaw_axes()
258
259    def draw(self):
260        self.base.draw()
261
262       
263class SideInteractor(_BaseInteractor):
264    """
265         Select an annulus through a 2D plot
266    """
267    def __init__(self,base,axes,color='black', zorder=5, r=1.0,phi=math.pi/4, theta2= math.pi/3):
268       
269        _BaseInteractor.__init__(self, base, axes, color=color)
270        self.markers = []
271        self.axes = axes
272       
[31e3298]273           
[ef0c170]274        self.save_theta = theta2 + phi
[31e3298]275        self.theta= theta2 + phi
[ef0c170]276        self.theta2 = theta2
277        self.radius = r
278        self.phi = phi
279        self.scale = 10.0
[7a28ba7]280         # Inner circle
[ef0c170]281        x1= self.radius*math.cos(self.theta)
282        y1= self.radius*math.sin(self.theta)
283        x2= -1*self.radius*math.cos(self.theta)
284        y2= -1*self.radius*math.sin(self.theta)
[7a28ba7]285       
286        try:
287            # Inner circle marker
[0c218d9]288            self.inner_marker = self.axes.plot([x1/2.5],[y1/2.5], linestyle='',
[7a28ba7]289                                          marker='s', markersize=10,
290                                          color=self.color, alpha=0.6,
291                                          pickradius=5, label="pick", 
292                                          zorder=zorder, # Prefer this to other lines
293                                          visible=True)[0]
294        except:
[0c218d9]295            self.inner_marker = self.axes.plot([x1/2.5],[y1/2.5], linestyle='',
[7a28ba7]296                                          marker='s', markersize=10,
297                                          color=self.color, alpha=0.6,
298                                          label="pick", 
299                                          visible=True)[0]
300            message  = "\nTHIS PROTOTYPE NEEDS THE LATEST VERSION OF MATPLOTLIB\n"
301            message += "Get the SVN version that is at least as recent as June 1, 2007"
302           
303         
304       
[ef0c170]305       
306        self.line = self.axes.plot([x1,x2],[y1,y2],
307                                      linestyle='-', marker='',
308                                      color=self.color,
309                                      visible=True)[0]
[7a28ba7]310        self.left_moving=False
311       
[ef0c170]312        self.npts = 20
313        self.has_move=False
[7a28ba7]314        self.connect_markers([self.inner_marker, self.line])
[ef0c170]315        #self.update()
316
317    def set_layer(self, n):
318        self.layernum = n
319        self.update()
320       
321    def clear(self):
322        self.clear_markers()
323        try:
324            self.line.remove()
[7a28ba7]325            self.inner_marker.remove()
[ef0c170]326        except:
327            # Old version of matplotlib
328            for item in range(len(self.axes.lines)):
329                del self.axes.lines[0]
330       
331       
332       
333    def get_radius(self):
334       
335        return self.theta - self.save_theta
336       
[e23a20c]337    def update(self,phi=None,delta=None, mline=None,side=False, left= False, right=False):
[ef0c170]338        """
339        Draw the new roughness on the graph.
340        """
341        #print "update left or right ", self.has_move
[7a28ba7]342        self.left_moving=left
[31e3298]343        theta3=0
[ef0c170]344        if phi !=None:
[7a28ba7]345            self.phi= phi
[31e3298]346        if delta==None:
347            delta = 0
348
[7a28ba7]349        if  right:
350            self.phi = -1*math.fabs(self.phi)
[31e3298]351            #delta=-delta
[7a28ba7]352        else:
353            self.phi =math.fabs(self.phi)
[e23a20c]354        if side:
[ef0c170]355            self.theta=  mline.theta + self.phi
[31e3298]356                   
357        if mline!=None :
358            if delta!=0:
359                self.theta2 = mline+delta
360            else:
361                self.theta2 = mline.theta
362        if delta==0:
363            theta3=self.theta+delta
364        else:
365            theta3=self.theta2+delta
[7a28ba7]366       
[e23a20c]367            #self.phi= math.fabs(self.theta2 - (self.theta+delta))
[ef0c170]368        #print "U:for line side theta2, phi, theta",math.degrees(self.theta2),math.degrees(self.phi),math.degrees(self.theta)
369        #if self.theta2 >= self.theta and self.theta>=0:
370        #    print "between 0-pi",math.degrees(self.theta)
371       
[31e3298]372        x1= self.radius*math.cos(theta3)
373        y1= self.radius*math.sin(theta3)
374        x2= -1*self.radius*math.cos(theta3)
375        y2= -1*self.radius*math.sin(theta3)
[ef0c170]376       
[0c218d9]377        self.inner_marker.set(xdata=[x1/2.5],ydata=[y1/2.5])
[ef0c170]378        self.line.set(xdata=[x1,x2], ydata=[y1,y2]) 
379       
380       
381       
382       
383    def save(self, ev):
384        """
385        Remember the roughness for this layer and the next so that we
386        can restore on Esc.
387        """
388        self.save_theta= self.theta
389        self.base.freeze_axes()
390
391    def moveend(self, ev):
392       
393        self.has_move=False
394        self.base.moveend(ev)
395           
396    def restore(self):
397        """
398        Restore the roughness for this layer.
399        """
400        self.theta = self.save_theta
401
402    def move(self, x, y, ev):
403        """
404        Process move to a new position, making sure that the move is allowed.
405        """
406       
407        self.theta= math.atan2(y,x)
[7a28ba7]408        self.has_move=True
[0c218d9]409        #ToDo: Simplify below
[7a28ba7]410        if not self.left_moving:
[0c218d9]411            if  self.theta2-self.theta <= 0 and self.theta2>0:#>= self.theta2:
412                #print "my theta", self.theta
413                self.restore()
414                return 
415            elif self.theta2 < 0 and self.theta < 0 and self.theta-self.theta2 >= 0:
416                self.restore()
417                return                             
418            elif  self.theta2 < 0 and self.theta > 0 and self.theta2+2*math.pi-self.theta >=math.pi/2:
419                #print "my theta", self.theta
420                self.restore()
421                return 
422            elif  self.theta2 < 0 and self.theta < 0 and self.theta2-self.theta >=math.pi/2:
423                #print "my theta", self.theta
[7a28ba7]424                self.restore()
425                return 
[0c218d9]426            elif self.theta2>0 and (self.theta2-self.theta >= math.pi/2 or (self.theta2-self.theta >= math.pi/2)):#<= self.theta2 -math.pi/2:
427                #print "self theta encore"
[7a28ba7]428                self.restore()
429                return 
430        else:
[0c218d9]431            #print "left move"
432            if  self.theta < 0 and self.theta+math.pi*2-self.theta2 <= 0:
[7a28ba7]433                self.restore()
434                return 
[0c218d9]435            elif self.theta2 < 0 and self.theta-self.theta2 <= 0:
436                self.restore()
437                return                             
438            elif  self.theta > 0 and self.theta-self.theta2 <=0:
439                #print "my theta", self.theta
440                self.restore()
441                return 
442            elif self.theta-self.theta2 >= math.pi/2 or  (self.theta+math.pi*2-self.theta2 >= math.pi/2 and self.theta<0 and self.theta2>0):
443                #print "self theta encore"
[7a28ba7]444                self.restore()
445                return 
[0c218d9]446           
[e23a20c]447        self.phi= math.fabs(self.theta2 - self.theta)
[0c218d9]448        if self.phi>math.pi:
449            self.phi= 2*math.pi-math.fabs(self.theta2 - self.theta)
[ef0c170]450       
[0c218d9]451        #print "move , self.phi, self.theta,", self.theta*180/math.pi,self.theta2*180/math.pi,self.phi*180/math.pi
[7a28ba7]452       
453           
454       
[ef0c170]455        self.base.base.update()
456       
457    def set_cursor(self, x, y):
458        self.move(x, y, None)
459        self.update()
460       
461       
462    def get_params(self):
463        params = {}
464        params["radius"] = self.radius
465        params["theta"] = self.theta
466        return params
467   
468    def set_params(self, params):
469
470        x = params["radius"] 
471        self.set_cursor(x, self._inner_mouse_y)
472       
[7a28ba7]473 
[ef0c170]474       
475class LineInteractor(_BaseInteractor):
476    """
477         Select an annulus through a 2D plot
478    """
479    def __init__(self,base,axes,color='black', zorder=5, r=1.0,theta=math.pi/4):
480       
481        _BaseInteractor.__init__(self, base, axes, color=color)
482        self.markers = []
483        self.axes = axes
484       
485        self.save_theta = theta
486        self.theta= theta
487       
488        self.radius = r
489     
490        self.scale = 10.0
491     
492        #raise "Version error", message
493           
494        # Inner circle
495        x1= self.radius*math.cos(self.theta)
496        y1= self.radius*math.sin(self.theta)
497        x2= -1*self.radius*math.cos(self.theta)
498        y2= -1*self.radius*math.sin(self.theta)
[7a28ba7]499        try:
500            # Inner circle marker
[0c218d9]501            self.inner_marker = self.axes.plot([x1/2.5],[y1/2.5], linestyle='',
[7a28ba7]502                                          marker='s', markersize=10,
503                                          color=self.color, alpha=0.6,
504                                          pickradius=5, label="pick", 
505                                          zorder=zorder, # Prefer this to other lines
506                                          visible=True)[0]
507        except:
[0c218d9]508            self.inner_marker = self.axes.plot([x1/2.5],[y1/2.5], linestyle='',
[7a28ba7]509                                          marker='s', markersize=10,
510                                          color=self.color, alpha=0.6,
511                                          label="pick", 
512                                          visible=True)[0]
513            message  = "\nTHIS PROTOTYPE NEEDS THE LATEST VERSION OF MATPLOTLIB\n"
514            message += "Get the SVN version that is at least as recent as June 1, 2007"
515           
[ef0c170]516       
517        self.line = self.axes.plot([x1,x2],[y1,y2],
518                                      linestyle='-', marker='',
519                                      color=self.color,
520                                      visible=True)[0]
521     
522        self.npts = 20
523        self.has_move=False
[7a28ba7]524        self.connect_markers([self.inner_marker, self.line])
[ef0c170]525        self.update()
526
527    def set_layer(self, n):
528        self.layernum = n
529        self.update()
530       
531    def clear(self):
532        self.clear_markers()
533        try:
[7a28ba7]534            self.inner_marker.remove()
[ef0c170]535            self.line.remove()
536        except:
537            # Old version of matplotlib
538            for item in range(len(self.axes.lines)):
539                del self.axes.lines[0]
540       
541       
542       
543    def get_radius(self):
544       
545        return self.theta - self.save_theta
546       
547    def update(self, theta=None):
548        """
549        Draw the new roughness on the graph.
550        """
[0c218d9]551        #print "update main line", self.theta
[ef0c170]552        if theta !=None:
553            self.theta= theta
554        x1= self.radius*math.cos(self.theta)
555        y1= self.radius*math.sin(self.theta)
556        x2= -1*self.radius*math.cos(self.theta)
557        y2= -1*self.radius*math.sin(self.theta)
[7a28ba7]558       
[0c218d9]559        self.inner_marker.set(xdata=[x1/2.5],ydata=[y1/2.5])
[ef0c170]560        self.line.set(xdata=[x1,x2], ydata=[y1,y2]) 
561     
562       
563       
564    def save(self, ev):
565        """
566        Remember the roughness for this layer and the next so that we
567        can restore on Esc.
568        """
569        self.save_theta= self.theta
570        self.base.freeze_axes()
571
572    def moveend(self, ev):
573       
574        self.has_move=False
575        self.base.moveend(ev)
576           
577    def restore(self):
578        """
579        Restore the roughness for this layer.
580        """
581        self.theta = self.save_theta
582
583    def move(self, x, y, ev):
584        """
585        Process move to a new position, making sure that the move is allowed.
586        """
587       
588        self.theta= math.atan2(y,x)
[0c218d9]589        #print "main_line previous theta --- next theta ",math.degrees(self.save_theta),math.degrees(self.theta)
[ef0c170]590       
591        self.has_move=True
[0c218d9]592       
[ef0c170]593        self.base.base.update()
594       
595    def set_cursor(self, x, y):
596        self.move(x, y, None)
597        self.update()
598       
599       
600    def get_params(self):
601        params = {}
602        params["radius"] = self.radius
603        params["theta"] = self.theta
604        return params
605   
606    def set_params(self, params):
607
608        x = params["radius"] 
609        self.set_cursor(x, self._inner_mouse_y)
610
611
[356aea78]612       
Note: See TracBrowser for help on using the repository browser.