source: sasview/sansview/perspectives/fitting/AnnulusSlicer.py @ b2c3225

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

smearing added

  • Property mode set to 100644
File size: 10.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#TODO: NEED MAJOR REFACTOR
6#
7
8
9# Debug printout
10from config import printEVT
11from BaseInteractor import _BaseInteractor
12from copy import deepcopy
13import math
14
15from Plotter1D import AddPlotEvent
16import SlicerParameters
17import wx
18
19class AnnulusInteractor(_BaseInteractor):
20    """
21         Select an annulus through a 2D plot
22    """
23    def __init__(self,base,axes,color='black', zorder=3):
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       
31        ## Number of points on the plot
32        self.nbins = 20
33
34        # Inner circle
35        self.inner_circle = RingInteractor(self, self.base.subplot, zorder=zorder, r=self.qmax/2.0)
36        self.inner_circle.qmax = self.base.qmax
37        self.outer_circle = RingInteractor(self, self.base.subplot, zorder=zorder+1, r=self.qmax/1.8)
38        self.outer_circle.qmax = self.base.qmax*1.2
39        #self.outer_circle.set_cursor(self.base.qmax/1.8, 0)
40       
41                     
42        self.update()
43        self._post_data()
44       
45        # Bind to slice parameter events
46        self.base.parent.Bind(SlicerParameters.EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
47
48
49    def _onEVT_SLICER_PARS(self, event):
50        printEVT("AnnulusSlicer._onEVT_SLICER_PARS")
51        event.Skip()
52        if event.type == self.__class__.__name__:
53            self.set_params(event.params)
54            self.base.update()
55
56    def update_and_post(self):
57        self.update()
58        self._post_data()
59
60    def save_data(self, path, image, x, y):
61        output = open(path, 'w')
62       
63        data_x, data_y = self.get_data(image, x, y)
64       
65        output.write("<phi>  <average>\n")
66        for i in range(len(data_x)):
67            output.write("%g  %g\n" % (data_x[i], data_y[i]))
68        output.close()
69
70    def set_layer(self, n):
71        self.layernum = n
72        self.update()
73       
74    def clear(self):
75        self.clear_markers()
76        self.outer_circle.clear()
77        self.inner_circle.clear()
78        #self.base.connect.disconnect()
79        self.base.parent.Unbind(SlicerParameters.EVT_SLICER_PARS)
80       
81    def update(self):
82        """
83        Respond to changes in the model by recalculating the profiles and
84        resetting the widgets.
85        """
86        # Update locations       
87        self.inner_circle.update()
88        self.outer_circle.update()
89       
90       
91    def get_data(self, image, x, y):
92        """
93            Return a 1D vector corresponding to the slice
94            @param image: data matrix
95            @param x: x matrix
96            @param y: y matrix
97        """
98        # If we have no data, just return
99        if image == None:
100            return       
101       
102        nbins = self.nbins
103       
104        data_x = nbins*[0]
105        data_y = nbins*[0]
106        counts = nbins*[0]
107        length = len(image)
108       
109       
110        for i_x in range(length):
111            for i_y in range(length):
112                       
113                q = math.sqrt(x[i_x]*x[i_x] + y[i_y]*y[i_y])
114                if (q>self.inner_circle._inner_mouse_x \
115                    and q<self.outer_circle._inner_mouse_x) \
116                    or (q<self.inner_circle._inner_mouse_x \
117                    and q>self.outer_circle._inner_mouse_x):
118                           
119                    i_bin = int(math.ceil(nbins*(math.atan2(y[i_y], x[i_x])+math.pi)/(2.0*math.pi)) - 1)
120                   
121                   
122                    #data_y[i_bin] += math.exp(image[i_x][i_y])
123                    data_y[i_bin] += image[i_y][i_x]
124                    counts[i_bin] += 1.0
125                   
126        for i in range(nbins):
127            data_x[i] = (1.0*i+0.5)*2.0*math.pi/nbins
128            if counts[i]>0:
129                data_y[i] = data_y[i]/counts[i]
130       
131        return data_x, data_y
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):
143        # Compute data
144        data = self.base.get_corrected_data()
145        # If we have no data, just return
146        if data == None:
147            return
148
149        data_x, data_y = self.get_data(data, self.base.x, self.base.y)
150       
151        name = "Ring"
152        if hasattr(self.base, "name"):
153            name += " %s" % self.base.name
154       
155        wx.PostEvent(self.base.parent, AddPlotEvent(name=name,
156                                               x = data_x,
157                                               y = data_y,
158                                               qmin = self.inner_circle._inner_mouse_x,
159                                               qmax = self.outer_circle._inner_mouse_x,
160                                               yscale = 'log',
161                                               variable = 'ANGLE',
162                                               ylabel = "\\rm{Intensity} ",
163                                               yunits = "cm^{-1}",
164                                               xlabel = "\\rm{\phi}",
165                                               xunits = "rad",
166                                               parent = self.base.__class__.__name__))
167                                               
168       
169    def moveend(self, ev):
170        self.base.thaw_axes()
171       
172        # Post paramters
173        event = SlicerParameters.SlicerParameterEvent()
174        event.type = self.__class__.__name__
175        event.params = self.get_params()
176        wx.PostEvent(self.base.parent, event)
177
178        self._post_data()
179           
180    def restore(self):
181        """
182        Restore the roughness for this layer.
183        """
184        self.inner_circle.restore()
185        self.outer_circle.restore()
186
187    def move(self, x, y, ev):
188        """
189        Process move to a new position, making sure that the move is allowed.
190        """
191        pass
192       
193    def set_cursor(self, x, y):
194        pass
195       
196    def get_params(self):
197        params = {}
198        params["inner_radius"] = self.inner_circle._inner_mouse_x
199        params["outer_radius"] = self.outer_circle._inner_mouse_x
200        params["nbins"] = self.nbins
201        return params
202   
203    def set_params(self, params):
204       
205        inner = params["inner_radius"] 
206        outer = params["outer_radius"] 
207        self.nbins = int(params["nbins"])
208        self.inner_circle.set_cursor(inner, self.inner_circle._inner_mouse_y)
209        self.outer_circle.set_cursor(outer, self.outer_circle._inner_mouse_y)
210        self._post_data()
211       
212    def freeze_axes(self):
213        self.base.freeze_axes()
214       
215    def thaw_axes(self):
216        self.base.thaw_axes()
217
218    def draw(self):
219        self.base.draw()
220
221       
222class RingInteractor(_BaseInteractor):
223    """
224         Select an annulus through a 2D plot
225    """
226    def __init__(self,base,axes,color='black', zorder=5, r=1.0):
227       
228        _BaseInteractor.__init__(self, base, axes, color=color)
229        self.markers = []
230        self.axes = axes
231        self._inner_mouse_x = r
232        self._inner_mouse_y = 0
233        self._inner_save_x  = r
234        self._inner_save_y  = 0
235        self.scale = 10.0
236       
237        try:
238            # Inner circle marker
239            self.inner_marker = self.axes.plot([self._inner_mouse_x],[0], linestyle='',
240                                          marker='s', markersize=10,
241                                          color=self.color, alpha=0.6,
242                                          pickradius=5, label="pick", 
243                                          zorder=zorder, # Prefer this to other lines
244                                          visible=True)[0]
245        except:
246            self.inner_marker = self.axes.plot([self._inner_mouse_x],[0], linestyle='',
247                                          marker='s', markersize=10,
248                                          color=self.color, alpha=0.6,
249                                          label="pick", 
250                                          visible=True)[0]
251            message  = "\nTHIS PROTOTYPE NEEDS THE LATEST VERSION OF MATPLOTLIB\n"
252            message += "Get the SVN version that is at least as recent as June 1, 2007"
253           
254            #raise "Version error", message
255           
256        # Inner circle
257
258           
259        [self.inner_circle] = self.axes.plot([],[],
260                                      linestyle='-', marker='',
261                                      color=self.color)
262        self.npts = 20
263           
264        self.connect_markers([self.inner_marker])
265        self.update()
266
267    def set_layer(self, n):
268        self.layernum = n
269        self.update()
270       
271    def clear(self):
272        self.clear_markers()
273        try:
274            self.inner_marker.remove()
275            self.inner_circle.remove()
276        except:
277            # Old version of matplotlib
278            for item in range(len(self.axes.lines)):
279                del self.axes.lines[0]
280       
281       
282       
283    def get_radius(self):
284        return self._inner_mouse_x
285       
286    def update(self):
287        """
288        Draw the new roughness on the graph.
289        """
290        # Plot inner circle
291        x = []
292        y = []
293        for i in range(self.npts):
294            phi = 2.0*math.pi/(self.npts-1)*i
295           
296            xval = 1.0*self._inner_mouse_x*math.cos(phi) 
297            yval = 1.0*self._inner_mouse_x*math.sin(phi) 
298           
299            x.append(xval)
300            y.append(yval)
301       
302        self.inner_marker.set(xdata=[self._inner_mouse_x],ydata=[0])
303        self.inner_circle.set_data(x, y)       
304
305    def save(self, ev):
306        """
307        Remember the roughness for this layer and the next so that we
308        can restore on Esc.
309        """
310        self._inner_save_x = self._inner_mouse_x
311        self._inner_save_y = self._inner_mouse_y
312        self.base.freeze_axes()
313
314    def moveend(self, ev):
315        self.base.moveend(ev)
316           
317    def restore(self):
318        """
319        Restore the roughness for this layer.
320        """
321        self._inner_mouse_x = self._inner_save_x
322        self._inner_mouse_y = self._inner_save_y
323
324    def move(self, x, y, ev):
325        """
326        Process move to a new position, making sure that the move is allowed.
327        """
328        self._inner_mouse_x = x
329        self._inner_mouse_y = y
330        self.base.base.update()
331       
332    def set_cursor(self, x, y):
333        self.move(x, y, None)
334        self.update()
335       
336       
337    def get_params(self):
338        params = {}
339        params["radius"] = self._inner_mouse_x
340        return params
341   
342    def set_params(self, params):
343
344        x = params["radius"] 
345        self.set_cursor(x, self._inner_mouse_y)
346       
347       
Note: See TracBrowser for help on using the repository browser.