source: sasview/guiframe/local_perspectives/plotting/boxSlicer.py @ b6b1669

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

working on boxslicer

  • Property mode set to 100644
File size: 24.2 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
10#from config import printEVT
11from BaseInteractor import _BaseInteractor
12from copy import deepcopy
13import math
14
15#from Plotter1D import AddPlotEvent
16import SlicerParameters
17import wx
18
19class BoxInteractor(_BaseInteractor):
20    """
21         Select an annulus through a 2D plot
22    """
23    def __init__(self,base,axes,color='black', zorder=3, x_min=0.0025, x_max=0.0025, y_min=0.0025, y_max=0.0025):
24       
25        _BaseInteractor.__init__(self, base, axes, color=color)
26        self.markers = []
27        self.axes = axes
28        self.qmax = self.base.qmax
29        self.connect = self.base.connect
30        self.xmin= -1* x_min
31        self.ymin= -1* y_min
32       
33        self.xmax= x_max
34        self.ymax=  y_max
35       
36        self.theta2= math.pi/4
37        ## Number of points on the plot
38        self.nbins = 20
39        self.count=0
40        self.error=0
41        self.main_line = LineInteractor(self, self.base.subplot,color='orange', zorder=zorder, r=self.qmax,
42                                           theta= self.theta2)
43        self.main_line.qmax = self.base.qmax
44       
45        self.left_line = VerticalLine(self, self.base.subplot,color='blue', zorder=zorder, 
46                                        ymin= self.ymin, ymax= self.ymax,
47                                        x=self.xmin,
48                                        theta2= self.theta2)
49        self.left_line.qmax = self.base.qmax
50       
51        self.right_line= VerticalLine(self, self.base.subplot,color='black', zorder=zorder,
52                                     ymin= self.ymin, ymax= self.ymax,
53                                     x=self.xmax,
54                                      theta2= self.theta2)
55        self.right_line.qmax = self.base.qmax
56       
57        self.top_line= HorizontalLine(self, self.base.subplot,color='green', zorder=zorder,
58                                    y= self.ymax,
59                                    xmin= self.xmin, xmax= self.xmax,
60                                     theta2= self.theta2)
61        self.top_line.qmax = self.base.qmax
62       
63        self.bottom_line= HorizontalLine(self, self.base.subplot,color='red', zorder=zorder,
64                                    y =self.ymin,
65                                    xmin= self.xmin, xmax= self.xmax,
66                                     theta2= self.theta2)
67        self.bottom_line.qmax = self.base.qmax
68        #self.outer_circle.set_cursor(self.base.qmax/1.8, 0)
69       
70                     
71        self.update()
72        #self._post_data()
73       
74        # Bind to slice parameter events
75        self.base.parent.Bind(SlicerParameters.EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
76
77
78    def _onEVT_SLICER_PARS(self, event):
79        #printEVT("AnnulusSlicer._onEVT_SLICER_PARS")
80        event.Skip()
81        if event.type == self.__class__.__name__:
82            #self.set_params(event.params)
83            self.base.update()
84
85    def update_and_post(self):
86        self.update()
87        self._post_data()
88
89    def save_data(self, path, image, x, y):
90        output = open(path, 'w')
91       
92        data_x, data_y = self.get_data(image, x, y)
93       
94        output.write("<phi>  <average>\n")
95        for i in range(len(data_x)):
96            output.write("%g  %g\n" % (data_x[i], data_y[i]))
97        output.close()
98
99    def set_layer(self, n):
100        self.layernum = n
101        self.update()
102       
103    def clear(self):
104        self.clear_markers()
105        self.left_line.clear()
106        self.right_line.clear()
107        self.top_line.clear()
108        self.bottom_line.clear()
109        self.main_line.clear()
110        #self.base.connect.disconnect()
111        self.base.parent.Unbind(SlicerParameters.EVT_SLICER_PARS)
112       
113    def update(self):
114        """
115        Respond to changes in the model by recalculating the profiles and
116        resetting the widgets.
117        """
118       
119        if self.main_line.has_move:
120            print "main has move"
121            self.main_line.update()
122            self.left_line.update(mline= self.main_line)
123            self.right_line.update(mline= self.main_line)
124            self.top_line.update(mline= self.main_line)
125            self.bottom_line.update(mline= self.main_line)
126       
127        if self.left_line.has_move:
128            print "left has moved"
129            self.left_line.update(translation=True)
130            self.right_line.update(xmin=-1*self.left_line.xmin,
131                                   xmax=-1*self.left_line.xmax,
132                                   ymin=self.left_line.ymin,
133                                   ymax=self.left_line.ymax,
134                                   translation=True)
135            self.top_line.update( xmin= self.left_line.xmax ,xmax= self.right_line.xmax,
136                                  translation=True)
137            self.bottom_line.update(xmin= self.left_line.xmin ,xmax= self.right_line.xmin,
138                                    translation=True)
139        if self.right_line.has_move:
140            print "right has moved"
141            self.right_line.update(translation=True)
142            self.left_line.update(xmin=-1*self.right_line.xmin,
143                                  xmax=-1*self.right_line.xmax,
144                                  translation=True)
145            self.top_line.update( xmin= self.left_line.xmax ,xmax= self.right_line.xmax,
146                                  translation=True)
147            self.bottom_line.update(xmin= self.left_line.xmin ,xmax= self.right_line.xmin,
148                                    translation=True)
149           
150           
151        if self.bottom_line.has_move:
152            print "bottom has moved"
153            self.bottom_line.update(translation=True)
154            self.top_line.update(ymin= -1*self.bottom_line.ymin,
155                                 ymax =-1*self.bottom_line.ymax,
156                                 translation=True)
157            self.left_line.update( ymin= self.bottom_line.ymin ,ymax= self.top_line.ymax,
158                                   translation=True)
159            self.right_line.update(ymin= self.bottom_line.ymin,ymax= self.top_line.ymax,
160                                   translation=True)
161           
162        if self.top_line.has_move:
163            print "top has moved"
164            self.top_line.update(mline= self.main_line,translation=True)
165            self.bottom_line.update(ymin= -1*self.top_line.ymin,
166                                    ymax=-1*self.top_line.ymax,
167                                    translation=True )
168            self.left_line.update(ymin= self.bottom_line.ymin ,ymax= self.top_line.ymax,
169                                  translation=True)
170            self.right_line.update(ymin= self.bottom_line.ymin ,ymax= self.top_line.ymax,
171                                   translation=True)
172           
173   
174    def save(self, ev):
175        """
176        Remember the roughness for this layer and the next so that we
177        can restore on Esc.
178        """
179        self.base.freeze_axes()
180        self.inner_circle.save(ev)
181        self.outer_circle.save(ev)
182
183    def _post_data(self):
184        # Compute data
185        data = self.base.data2D
186        from DataLoader.manipulations import  Boxavg
187        radius = math.sqrt(math.pow(self.qmax,2)+math.pow(self.qmax,2))
188        x_min= self.left_line.x
189        x_max= self.right_line.x
190        y_min= self.bottom_line.y
191        y_max= self.top_line.y
192        box =  Boxavg (x_min=x_min, x_max=x_max, y_min=y_min, y_max=y_max)
193       
194        self.count, self.error= box(self.base.data2D)
195       
196       
197             
198                                       
199    def moveend(self, ev):
200        self.base.thaw_axes()
201       
202        # Post paramters
203        event = SlicerParameters.SlicerParameterEvent()
204        event.type = self.__class__.__name__
205        #event.params = self.get_params()
206        wx.PostEvent(self.base.parent, event)
207
208        self._post_data()
209           
210    def restore(self):
211        """
212        Restore the roughness for this layer.
213        """
214        self.inner_circle.restore()
215        self.outer_circle.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["x_min"] = self.left_line.xmin
229        params["x_max"] = self.right_line.xmax
230        params["y_min"] = self.bottom_line.y
231        params["y_max"] = self.top_line.y
232        params["count"] = self.count
233        params["error"] = self.error
234        params["phi"] = self.main_line.theta
235        return params
236   
237    def set_params(self, params):
238       
239        x_min = params["x_min"] 
240        x_max = params["x_max"] 
241        y_min = params["y_min"]
242        y_max = params["y_max"] 
243        theta = params["theta"]
244       
245        self.left_line.update(ymin= y_min ,ymax= y_max)
246        self.right_line.update(ymin= y_min ,ymax= y_max)
247        self.top_line.update( xmin= x_min ,xmax= xmax)
248        self.bottom_line.update(xmin= xmin ,xmax= xmax)
249        self.main_line.update(theta)
250       
251        self._post_data()
252    def freeze_axes(self):
253        self.base.freeze_axes()
254       
255    def thaw_axes(self):
256        self.base.thaw_axes()
257
258    def draw(self):
259        self.base.draw()
260
261class HorizontalLine(_BaseInteractor):
262    """
263         Select an annulus through a 2D plot
264    """
265    def __init__(self,base,axes,color='black', zorder=5, y=0.5,
266                 xmin=0.0,xmax=0.5,
267                 theta2= math.pi/3 ):
268       
269        _BaseInteractor.__init__(self, base, axes, color=color)
270        self.markers = []
271        self.axes = axes
272       
273        self.y= y
274        self.save_y = y
275       
276        self.xmin = xmin
277        self.save_xmin = xmin
278        self.xmax = xmax
279        self.save_xmax = xmax
280       
281        self.theta2 = theta2
282       
283        self.clickx=self.xmin
284        self.clicky=self.y
285        self.clickxf=self.xmin
286        self.clickyf=self.y
287        self.deltax=0
288        self.deltay=0
289        x1= self.xmin*math.cos(self.theta2)- self.y*math.sin(self.theta2)
290        self.ymin= self.xmin*math.sin(self.theta2)+ self.y*math.sin(self.theta2)
291       
292        x2= self.xmax*math.cos(self.theta2)- self.y*math.sin(self.theta2)
293        self.ymax= self.xmax*math.sin(self.theta2)+ self.y*math.sin(self.theta2)
294        #print "x1, y1", x1, y1, x2,y2
295        self.line = self.axes.plot([x1,x2],[self.ymin,self.ymax],
296                                      linestyle='-', marker='',
297                                      color=self.color,
298                                      visible=True)[0]
299 
300
301        self.npts = 20
302        self.has_move=False
303        self.connect_markers([self.line])
304        self.update()
305
306    def set_layer(self, n):
307        self.layernum = n
308        self.update()
309       
310    def clear(self):
311        self.clear_markers()
312        try:
313           
314            self.line.remove()
315        except:
316            # Old version of matplotlib
317            for item in range(len(self.axes.lines)):
318                del self.axes.lines[0]
319    def onClick(self, ev):
320        """
321        Prepare to move the artist.  Calls save() to preserve the state for
322        later restore().
323        """
324        self.clickx,self.clicky = ev.xdata,ev.ydata
325        print "onclick",self.clickx,self.clicky
326        #self.save(ev)
327        return True   
328    def get_radius(self):
329       
330        return 0
331   
332    def update(self,xmin=None, xmax=None,ymin=None,ymax=None, mline=None,translation=False):
333        """
334        Draw the new roughness on the graph.
335        """
336        #print "update main line", self.has_move
337       
338        if translation :
339            self.deltax = self.clickxf- self.clickx
340            self.deltay = self.clickyf-self.clicky
341           
342            self.xmin= self.xmin +self.deltax
343            self.xmax=self.xmax+self.deltax
344            self.ymin= self.ymin +self.deltay
345            self.ymax=self.ymax+self.deltay
346           
347            if xmin !=None:
348                self.xmin=xmin
349            if xmax !=None:
350                self.xmax=xmax
351            if ymin !=None:
352                self.ymin = ymin
353            if ymax !=None:
354                self.ymax = ymax
355            self.line.set(xdata=[self.xmin, self.xmax],
356                          ydata=[self.ymin, self.ymax])
357        if mline !=None:
358            self.theta2= mline.theta
359           
360            x1= self.xmin*math.cos(self.theta2)- self.y*math.sin(self.theta2)
361            y1= self.xmin*math.sin(self.theta2)+ self.y*math.sin(self.theta2)
362       
363            x2= self.xmax*math.cos(self.theta2)- self.y*math.sin(self.theta2)
364            y2= self.xmax*math.sin(self.theta2)+ self.y*math.sin(self.theta2)
365           
366            self.line.set(xdata=[x1,x2], ydata=[y1,y2]) 
367            print x1,x2,y1,y2
368           
369        #else:
370        #    self.line.set(xdata=[self.xmin,self.xmax], ydata=[self.y,self.y])
371     
372       
373       
374    def save(self, ev):
375        """
376        Remember the roughness for this layer and the next so that we
377        can restore on Esc.
378        """
379        self.save_xmin= self.xmin
380        self.save_xmax= self.xmax
381       
382        self.save_y= self.y
383        self.base.freeze_axes()
384
385    def moveend(self, ev):
386        self.clickxf,self.clickyf = ev.xdata,ev.ydata
387        print "move end ",self.clickxf,self.clickyf
388        self.has_move=False
389        self.base.moveend(ev)
390           
391    def restore(self):
392        """
393        Restore the roughness for this layer.
394        """
395        self.ymin = self.save_ymin
396        self.ymax = self.save_ymax
397
398    def move(self, x, y, ev):
399        """
400        Process move to a new position, making sure that the move is allowed.
401        """
402       
403        self.has_move=True
404        self.base.base.update()
405       
406    def set_cursor(self, x, y):
407        self.move(x, y, None)
408        self.update()
409       
410       
411    def get_params(self):
412        params = {}
413        params["radius"] = self.xmin
414        params["theta"] = self.xmax
415        return params
416   
417    def set_params(self, params):
418
419        x = params["radius"] 
420        self.set_cursor(x, self._inner_mouse_y)
421       
422
423
424
425class VerticalLine(_BaseInteractor):
426    """
427         Select an annulus through a 2D plot
428    """
429    def __init__(self,base,axes,color='black', zorder=5, ymin=0.0, 
430                 ymax=0.5,x=0.5,
431                 theta2= math.pi/3 ):
432       
433        _BaseInteractor.__init__(self, base, axes, color=color)
434        self.markers = []
435        self.axes = axes
436        # x coordinate of the vertical line
437        self.x= x
438        self.save_x = x
439       
440        # minimum value of y coordinate of the vertical line
441        self.ymin = ymin
442        self.save_ymin = ymin
443        # maximum value of y coordinate of the vertical line
444        self.ymax=ymax
445        self.save_ymax=ymax
446        #insure rotation
447        self.theta2= theta2
448       
449        # Draw vertical line
450        self.xmin= self.x* math.cos(self.theta2)-self.ymin *math.sin(self.theta2)
451        self.xmax= self.x* math.cos(self.theta2)-self.ymax *math.sin(self.theta2)
452       
453        self.ymin= self.x* math.sin(self.theta2)+self.ymin *math.cos(self.theta2)
454        self.ymax= self.x* math.sin(self.theta2)+self.ymax *math.cos(self.theta2)
455       
456        self.clickx=self.xmin
457        self.clicky=self.ymin
458        self.clickxf=self.xmin
459        self.clickyf=self.ymin
460        self.deltax=0
461        self.deltay=0
462        self.line = self.axes.plot([self.xmin,self.xmax],[self.ymin,self.ymax],
463                                      linestyle='-', marker='',
464                                      color=self.color,
465                                      visible=True)[0]
466     
467        self.npts = 20
468        # Check vertical line motion
469        self.has_move=False
470        self.connect_markers([self.line])
471        self.update()
472
473    def set_layer(self, n):
474        self.layernum = n
475        self.update()
476       
477    def clear(self):
478        self.clear_markers()
479        try:
480           
481            self.line.remove()
482        except:
483            # Old version of matplotlib
484            for item in range(len(self.axes.lines)):
485                del self.axes.lines[0]
486    def onClick(self, ev):
487        """
488        Prepare to move the artist.  Calls save() to preserve the state for
489        later restore().
490        """
491        self.clickx,self.clicky = ev.xdata,ev.ydata
492        print "onclick",self.clickx,self.clicky
493        #self.save(ev)
494        return True   
495
496    def get_radius(self):
497        return 0
498   
499    def update(self,xmin=None,xmax=None,ymin=None, ymax=None, mline=None,translation=False):
500        """
501        Draw the new roughness on the graph.
502        """
503        if translation :
504            self.deltax = self.clickxf- self.clickx
505            self.deltay = self.clickyf-self.clicky
506           
507            self.xmin= self.xmin + self.deltax
508            self.xmax=self.xmax + self.deltax
509            self.ymin= self.ymin + self.deltay
510            self.ymax=self.ymax + self.deltay
511           
512            if xmin !=None:
513                self.xmin=xmin
514            if xmax !=None:
515                self.xmax=xmax
516            if ymin !=None:
517                self.ymin = ymin
518            if ymax !=None:
519                self.ymax = ymax
520            self.line.set(xdata=[self.xmin, self.xmax],
521                          ydata=[self.ymin, self.ymax])
522        if mline !=None:
523           
524            self.theta2= mline.theta
525            delta = mline.get_delta_angle()
526            if translation:
527                delta= 0
528            self.xmin= self.x* math.cos(self.theta2)-self.ymin *math.sin(self.theta2)
529            self.xmax= self.x* math.cos(self.theta2)-self.ymax *math.sin(self.theta2)
530       
531            self.ymin= self.x* math.sin(self.theta2)+self.ymin *math.cos(self.theta2)
532            self.ymax= self.x* math.sin(self.theta2)+self.ymax *math.cos(self.theta2)
533       
534
535            self.line.set(xdata=[self.xmin,self.xmax], ydata=[self.ymin,self.ymax]) 
536           
537             
538       
539    def save(self, ev):
540        """
541        Remember the roughness for this layer and the next so that we
542        can restore on Esc.
543        """
544        #self.save_x= self.x
545        self.save_xmin= self.xmin
546        self.save_xmax= self.xmax
547        self.save_ymin= self.ymin
548        self.save_ymax= self.ymax
549       
550        self.base.freeze_axes()
551
552    def moveend(self, ev):
553        self.clickxf,self.clickyf = ev.xdata,ev.ydata
554        print "move end ",self.clickxf,self.clickyf
555        self.has_move=False
556        self.base.moveend(ev)
557           
558    def restore(self):
559        """
560        Restore the roughness for this layer.
561        """
562        self.xmin = self.save_xmin
563        self.xmax = self.save_xmax
564        self.ymin=self.save_ymin
565        self.ymax=self.save_ymax
566       
567       
568    def move(self, x, y, ev):
569        """
570        Process move to a new position, making sure that the move is allowed.
571        """
572       
573        self.has_move=True
574        self.base.base.update()
575       
576       
577    def set_cursor(self, x, y):
578        self.move(x, y, None)
579        self.update()
580       
581       
582    def get_params(self):
583        params = {}
584        params["x"] = self.xmin
585        params["ymin"] = self.ymin
586        params["ymax"] = self.ymax
587        return params
588   
589    def set_params(self, params):
590        """
591            Draw a vertical line given some value of params
592            @param params: a dictionary containing value for x, ymin , ymax to draw
593            a vertical line
594        """
595        x = params["x"] 
596        ymin = params["ymin"] 
597        ymax = params["ymax"] 
598        #self.set_cursor(x, self._inner_mouse_y)
599        self.update(self,x =x,ymin =ymin, ymax =ymax)
600       
601
602       
603class LineInteractor(_BaseInteractor):
604    """
605         Select an annulus through a 2D plot
606    """
607    def __init__(self,base,axes,color='black', zorder=5, r=1.0,theta=math.pi/4):
608       
609        _BaseInteractor.__init__(self, base, axes, color=color)
610        self.markers = []
611        self.axes = axes
612       
613        self.save_theta = theta
614        self.theta= theta
615       
616        self.radius = r
617     
618        self.scale = 10.0
619           
620        # Inner circle
621        x1= self.radius*math.cos(self.theta)
622        y1= self.radius*math.sin(self.theta)
623        x2= -1*self.radius*math.cos(self.theta)
624        y2= -1*self.radius*math.sin(self.theta)
625       
626        self.line = self.axes.plot([x1,x2],[y1,y2],
627                                      linestyle='-', marker='',
628                                      color=self.color,
629                                      visible=True)[0]
630     
631        self.npts = 20
632        self.has_move=False
633        self.connect_markers([self.line])
634        self.update()
635
636    def set_layer(self, n):
637       
638        self.layernum = n
639        self.update()
640       
641    def clear(self):
642        """
643            Remove the line of the plot
644        """
645        self.clear_markers()
646        try:
647            self.line.remove()
648        except:
649            # Old version of matplotlib
650            for item in range(len(self.axes.lines)):
651                del self.axes.lines[0]
652       
653       
654       
655    def get_delta_angle(self):
656        """
657            return difference between initial angle and the final angle during
658            rotation
659        """
660        return self.theta - self.save_theta
661       
662    def update(self, theta=None,radius=None):
663        """
664            Draw a line given and angle relative to the x-axis and a radius
665            @param  theta: the angle realtive to the x-axis
666            @param radius: the distance between the center and one end of the line
667        """
668       
669        if theta !=None:
670            self.theta= theta
671        if radius !=None:
672            self.radius =radius
673        print "update main line", math.degrees(self.theta)
674        x1= self.radius*math.cos(self.theta)
675        y1= self.radius*math.sin(self.theta)
676        x2= -1*self.radius*math.cos(self.theta)
677        y2= -1*self.radius*math.sin(self.theta)
678     
679        self.line.set(xdata=[x1,x2], ydata=[y1,y2]) 
680     
681       
682       
683    def save(self, ev):
684        """
685        Remember the roughness for this layer and the next so that we
686        can restore on Esc.
687        """
688        self.save_theta= self.theta
689        self.base.freeze_axes()
690
691    def moveend(self, ev):
692       
693        self.has_move=False
694        self.base.moveend(ev)
695           
696    def restore(self):
697        """
698        Restore the roughness for this layer.
699        """
700        self.theta = self.save_theta
701
702    def move(self, x, y, ev):
703        """
704        Process move to a new position, making sure that the move is allowed.
705        """
706        self.theta= math.atan2(y,x)
707        #print "main_line previous theta --- next theta ",math.degrees(self.save_theta),math.degrees(self.theta)
708        self.has_move=True
709        self.base.base.update()
710       
711       
712    def set_cursor(self, x, y):
713       
714        self.move(x, y, None)
715        self.update()
716       
717       
718    def get_params(self):
719        """
720            return params a dictionary containing values of paramters necessary to draw
721            this line
722        """
723        params = {}
724        params["radius"] = self.radius
725        params["theta"] = self.theta
726        return params
727   
728    def set_params(self, params):
729        """
730            Draw the line given value contains by params
731            @param params: dictionary containing name of parameters and their values
732        """
733        radius = params["radius"]
734        theta = params["theta"]
735        self.update(x, theta= theta , radius = radius )
736       
737
738
739
740       
Note: See TracBrowser for help on using the repository browser.