source: sasview/guiframe/local_perspectives/plotting/SectorSlicer.py @ 3bae6c8

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 3bae6c8 was 3bae6c8, checked in by Jae Cho <jhjcho@…>, 15 years ago

sector lines is now longer enough to cover all area of 2D surface plot

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