source: sasview/guiframe/local_perspectives/plotting/SectorSlicer.py @ 0bd2cd8

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 0bd2cd8 was 8b30e62, checked in by Jae Cho <jhjcho@…>, 16 years ago

add id for averaging plot

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