source: sasview/guiframe/local_perspectives/plotting/SectorSlicer.py @ 4937983

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 4937983 was 1ce365f8, checked in by Gervaise Alina <gervyh@…>, 16 years ago

print preview added back

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