source: sasview/guiframe/local_perspectives/plotting/LineSlicer.py @ 3b909b7

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

add a new module containing common classes that I used often:
sans.guiframe.utils

remove event slicer and add it in sans.guicoom.events,
modified slicer for those events

  • Property mode set to 100644
File size: 9.8 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#
6#TODO: NEED MAJOR REFACTOR
7#
8
9# Debug printout
10import math
11import wx
12from copy import deepcopy
13
14from sans.guicomm.events import NewPlotEvent, StatusEvent,SlicerParameterEvent,EVT_SLICER_PARS
15from BaseInteractor import _BaseInteractor
16
17
18
19class LineInteractor(_BaseInteractor):
20    """
21        Select a slice through a 2D plot
22    """
23    #TODO: get rid of data that is not related to the image
24    # For instance, get rid of access to qmax
25   
26    def __init__(self,base,axes,color='black', zorder=3):
27        _BaseInteractor.__init__(self, base, axes, color=color)
28        self.markers = []
29        self.axes = axes
30        self._mouse_x = 0
31        self._mouse_y = self.base.data2D.xmax/2
32        self._save_x  = 0
33        self._save_y  = self.base.data2D.xmax/2
34        self.scale = 10.0
35       
36        self.npts = 150
37        ## Number of bins on the line
38        self.nbins = 50
39        ## Width of the line
40        self.tolerance = None
41       
42        try:
43            self.marker = self.axes.plot([0],[self.base.qmax/2], linestyle='',
44                                          marker='s', markersize=10,
45                                          color=self.color, alpha=0.6,
46                                          label="pick", 
47                                          zorder=zorder, # Prefer this to other lines
48                                          visible=True)[0]
49        except:
50            self.marker = self.axes.plot([0],[self.base.qmax/2], linestyle='',
51                                          marker='s', markersize=10,
52                                          color=self.color, alpha=0.6,
53                                          pickradius=5, label="pick", 
54                                          visible=True)[0]
55           
56            message  = "\nTHIS PROTOTYPE NEEDS THE LATEST VERSION OF MATPLOTLIB\n"
57            message += "Get the SVN version that is at least as recent as June 1, 2007"
58                         
59        self.line = self.axes.plot([0,0],[0.0,self.base.qmax/2*self.scale],
60                                      linestyle='-', marker='',
61                                      color=self.color,
62                                      visible=True)[0]
63       
64           
65        self.connect_markers([self.marker])
66        self.update()
67        self._post_data()
68       
69        # Bind to slice parameter events
70        self.base.parent.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
71       
72    def _onEVT_SLICER_PARS(self, event):
73        event.Skip()
74        wx.PostEvent(self.base.parent, StatusEvent(status="LineSlicer._onEVT_SLICER_PARS"))
75        if event.type == self.__class__.__name__:
76            self.set_params(event.params)
77            self.base.update()
78       
79    def update_and_post(self):
80        self.update()
81        self._post_data()
82
83    def save_data(self, path, image, x, y):
84        output = open(path, 'w')
85       
86        data_x, data_y = self.get_data(image, x, y)
87       
88        output.write("<q>  <average>\n")
89        for i in range(len(data_x)):
90            output.write("%g  %g\n" % (data_x[i], data_y[i]))
91        output.close()
92
93
94    def get_event(self, image=None, x=None, y=None):
95        evt = SliceEvent(self._mouse_x, self._mouse_y)
96        evt.type = SliceInteractor
97        if not image==None and not x==None and not y==None:
98            data_x, data_y = self.get_data(image, x, y)
99            evt.data_x = data_x
100            evt.data_y = data_y
101        evt.min_xlim = 0
102        evt.max_xlim = self.base.qmax
103        evt.params = self.get_params()
104        evt.ylabel = r'$\rm{Intensity}\ (cm^{-1})$'
105        evt.xlabel = r'$\rm{q}\ (A^{-1})$'
106
107        return evt
108
109    def set_layer(self, n):
110        self.layernum = n
111        self.update()
112       
113    def clear(self):
114        self.clear_markers()
115        try:
116            self.marker.remove()
117            self.line.remove()
118        except:
119            # Old version of matplotlib
120            for item in range(len(self.axes.lines)):
121                del self.axes.lines[0]
122       
123        # Unbind panel
124        #self.base.connect.disconnect()
125        self.base.parent.Unbind(EVT_SLICER_PARS)
126
127       
128    def update(self):
129        """
130        Draw the new roughness on the graph.
131        """
132        self.marker.set(xdata=[self._mouse_x],ydata=[self._mouse_y])
133        self.line.set(xdata=[0,self._mouse_x*self.scale], ydata=[0,self._mouse_y*self.scale])
134
135    def get_data(self, image=None, x=None, y=None):
136        """
137            Return the slice data
138        """
139        #TODO: Computer variance
140       
141        # If we have no data, just return
142        if image == None:
143            return
144       
145        # Now the slice
146        nbins = self.nbins
147        data_x = nbins*[0]
148        data_y = nbins*[0]
149        counts = nbins*[0]
150       
151        length = len(image)
152        qmax = x[length-1]
153       
154        #TODO: only good for square detector!
155        #data_step = (x[length-1]-x[length-2])/2.0
156        data_step = (x[length-1]-x[length-2])
157        if self.tolerance==None:
158            self.tolerance = data_step
159        else:
160            data_step = self.tolerance
161       
162        #TODO: calculate the slice from the actual matrix
163        # this must be done for real data
164        print "STEP", data_step
165        for i_x in range(length):
166            for i_y in range(length):
167                   
168                # Check whether that cell touches the line
169                # Careful with the sign of the slope
170                xval = x[i_x]
171                yval = y[i_y]
172               
173                if (self._mouse_x==0 and math.fabs(xval)<data_step) \
174                    or (self._mouse_x>0 and \
175                        math.fabs(yval-xval*self._mouse_y/self._mouse_x)<data_step) \
176                    or (self._mouse_x<0 and \
177                        math.fabs(yval+xval*self._mouse_y/self._mouse_x)<data_step) \
178                    or (self._mouse_y>0 and \
179                        math.fabs(xval-yval*self._mouse_x/self._mouse_y)<data_step) \
180                    or (self._mouse_y<0 and \
181                        math.fabs(xval+yval*self._mouse_x/self._mouse_y)<data_step):
182                   
183                    q = math.sqrt(x[i_x]*x[i_x] + y[i_y]*y[i_y])
184                       
185                    i_bin = int(math.floor(q/(qmax/nbins)))
186                   
187                    # Check for out-of-range q bins (possible in the corners)
188                    if i_bin<nbins:
189                        #data_y[i_bin] += math.exp(image[i_x][i_y])
190                        data_y[i_bin] += image[i_y][i_x]
191                        counts[i_bin] += 1
192                   
193        data_pos_x = []
194        data_pos_y = []
195        for i in range(nbins):
196            data_x[i] = (i+0.5)*qmax/nbins
197            if counts[i]>0:
198                data_y[i] = data_y[i]/counts[i]
199                data_pos_x.append(data_x[i])
200                data_pos_y.append(data_y[i])
201       
202        return data_x, data_y
203
204
205    def save(self, ev):
206        """
207        Remember the roughness for this layer and the next so that we
208        can restore on Esc.
209        """
210        self._save_x = self._mouse_x
211        self._save_y = self._mouse_y
212        self.base.freeze_axes()
213
214    def _post_data(self):
215        # Compute data
216        data = self.base.get_corrected_data()
217        # If we have no data, just return
218        if data == None:
219            return
220
221        data_x, data_y = self.get_data(data, self.base.x, self.base.y)
222       
223        name = "Line"
224        if hasattr(self.base, "name"):
225            name += " %s" % self.base.name
226        print "data_x", data_x
227        """   
228        wx.PostEvent(self.base.parent, AddPlotEvent(name=name,
229                                               x = data_x,
230                                               y = data_y,
231                                               yscale = 'log',
232                                               variable = 'Q',
233                                               ylabel = "\\rm{Intensity} ",
234                                               yunits = "cm^{-1}",
235                                               xlabel = '\\rm{q} ',
236                                               xunits = 'A^{-1}',
237                                               parent = self.base.__class__.__name__))
238        """
239    def moveend(self, ev):
240        self.base.thaw_axes()
241       
242        # Post paramters
243        event = SlicerParameterEvent()
244        event.type = self.__class__.__name__
245        event.params = self.get_params()
246        wx.PostEvent(self.base.parent, event)
247
248        self._post_data()
249           
250    def restore(self):
251        """
252        Restore the roughness for this layer.
253        """
254        self._mouse_x = self._save_x
255        self._mouse_y = self._save_y
256
257    def move(self, x, y, ev):
258        """
259        Process move to a new position, making sure that the move is allowed.
260        """
261        self._mouse_x = x
262        self._mouse_y = y
263       
264    def set_cursor(self, x, y):
265        self.move(x, y, None)
266        self.update()
267        self._post_data()
268       
269    def get_params(self):
270        params = {}
271        params["x"] = self._mouse_x
272        params["y"] = self._mouse_y
273        params["nbins"] = self.nbins
274        params["line_width"] = self.tolerance
275        return params
276   
277    def set_params(self, params):
278
279        x = params["x"] 
280        y = params["y"] 
281        if "nbins" in params:
282            self.nbins = int(params["nbins"])
283        if "line_width" in params:
284            self.tolerance = params["line_width"]
285        self.set_cursor(x, y)
286       
Note: See TracBrowser for help on using the repository browser.