source: sasview/guiframe/local_perspectives/plotting/Plotter2D.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 7ab9241, checked in by Gervaise Alina <gervyh@…>, 16 years ago

small change on annulus

  • Property mode set to 100644
File size: 15.3 KB
Line 
1"""
2This software was developed by the University of Tennessee as part of the
3Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
4project funded by the US National Science Foundation.
5
6See the license text in license.txt
7
8copyright 2008, University of Tennessee
9"""
10
11
12import wx
13import sys
14import danse.common.plottools
15from danse.common.plottools.PlotPanel import PlotPanel
16from danse.common.plottools.plottables import Graph,Data1D
17from sans.guicomm.events import EVT_NEW_PLOT
18from sans.guicomm.events import StatusEvent ,NewPlotEvent
19
20
21from SlicerParameters import SlicerEvent
22from binder import BindArtist
23(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
24#from SlicerParameters import SlicerEvent
25#(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
26from Plotter1D import ModelPanel1D
27DEFAULT_QMAX = 0.05
28
29DEFAULT_QSTEP = 0.001
30DEFAULT_BEAM = 0.005
31BIN_WIDTH = 1.0
32import pylab
33from Plotter1D import PanelMenu
34
35class ModelPanel2D( ModelPanel1D):
36    """
37        Plot panel for use with the GUI manager
38    """
39   
40    ## Internal name for the AUI manager
41    window_name = "plotpanel"
42    ## Title to appear on top of the window
43    window_caption = "Plot Panel"
44    ## Flag to tell the GUI manager that this panel is not
45    #  tied to any perspective
46    ALWAYS_ON = True
47    ## Group ID
48    group_id = None
49   
50   
51    def __init__(self, parent, id = -1,data2d=None, color = None,\
52        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
53        """
54            Initialize the panel
55        """
56        ModelPanel1D.__init__(self, parent, id = id, style = style, **kwargs)
57       
58        ## Reference to the parent window
59        self.parent = parent
60        ## Plottables
61        self.plots = {}
62        self.data2D= data2d
63        self.data = data2d.data
64        ## Unique ID (from gui_manager)
65        self.uid = None
66       
67        ## Action IDs for internal call-backs
68        self.action_ids = {}
69        self.connect = BindArtist(self.subplot.figure)
70       
71        # Beam stop
72        self.beamstop_radius = DEFAULT_BEAM
73        # Slicer
74        if data2d.xmax==None:
75            data2d.xmax=DEFAULT_QMAX+self.qstep*0.01
76       
77        self.qmax = data2d.xmax
78        if data2d.ymax==None:
79            data2d.ymax=DEFAULT_QMAX+self.qstep*0.01
80        self.imax = data2d.ymax
81        #self.radius = math.sqrt(data2d.)
82        self.qstep = DEFAULT_QSTEP
83        #print "panel2D qmax",self.qmax,
84       
85        self.x = pylab.arange(-1*self.qmax, self.qmax+self.qstep*0.01, self.qstep)
86        self.y = pylab.arange(-1*self.imax, self.imax+self.qstep*0.01, self.qstep)
87
88        self.slicer_z = 5
89        self.slicer = None
90        self.parent.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
91        self.axes_frozen = False
92       
93       
94        ## Graph       
95        self.graph = Graph()
96        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
97        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
98        self.graph.render(self)
99 
100    def _onEVT_1DREPLOT(self, event):
101        """
102            Data is ready to be displayed
103            @param event: data event
104        """
105        #TODO: Check for existence of plot attribute
106
107        # Check whether this is a replot. If we ask for a replot
108        # and the plottable no longer exists, ignore the event.
109        if hasattr(event, "update") and event.update==True \
110            and event.plot.name not in self.plots.keys():
111            return
112       
113        if hasattr(event, "reset"):
114            self._reset()
115        #print "model2 d event",event.plot.name, event.plot.id, event.plot.group_id
116        #print "plottable list ",self.plots.keys()
117        #print self.plots
118        is_new = True
119        if event.plot.name in self.plots.keys():
120            # Check whether the class of plottable changed
121            if not event.plot.__class__==self.plots[event.plot.name].__class__:
122                #overwrite a plottable using the same name
123                print "is deleting the new plottable"
124                self.graph.delete(self.plots[event.plot.name])
125            else:
126                # plottable is already draw on the panel
127                is_new = False
128
129           
130        if is_new:
131            # a new plottable overwrites a plotted one  using the same id
132            #print "went here",self.plots.itervalues()
133            for plottable in self.plots.itervalues():
134                if event.plot.id==plottable.id :
135                    self.graph.delete(plottable)
136           
137            self.plots[event.plot.name] = event.plot
138            self.graph.add(self.plots[event.plot.name])
139        else:
140            #replot the graph
141            self.plots[event.plot.name].x = event.plot.x   
142            self.plots[event.plot.name].y = event.plot.y   
143            self.plots[event.plot.name].dy = event.plot.dy 
144            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
145                self.plots[event.plot.name].dx = event.plot.dx   
146 
147       
148        # Check axis labels
149        #TODO: Should re-factor this
150        #if event.plot._xunit != self.graph.prop["xunit"]:
151        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
152           
153        #if event.plot._yunit != self.graph.prop["yunit"]:
154        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
155     
156        self.graph.render(self)
157        self.subplot.figure.canvas.draw_idle()
158
159
160    def onContextMenu(self, event):
161        """
162            2D plot context menu
163            @param event: wx context event
164        """
165       
166        #slicerpop = wx.Menu()
167        slicerpop = PanelMenu()
168        slicerpop.set_plots(self.plots)
169        slicerpop.set_graph(self.graph)
170               
171        # Option to save the data displayed
172   
173        # Various plot options
174        id = wx.NewId()
175        slicerpop.Append(id,'&Save image', 'Save image as PNG')
176        wx.EVT_MENU(self, id, self.onSaveImage)
177       
178       
179        item_list = self.parent.get_context_menu(self.graph)
180        if (not item_list==None) and (not len(item_list)==0):
181                slicerpop.AppendSeparator()
182                for item in item_list:
183                    try:
184                        id = wx.NewId()
185                        slicerpop.Append(id, item[0], item[1])
186                        wx.EVT_MENU(self, id, item[2])
187                    except:
188                        print sys.exc_value
189                        print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
190       
191        slicerpop.AppendSeparator()
192       
193        id = wx.NewId()
194        slicerpop.Append(id, '&Perform circular average')
195        wx.EVT_MENU(self, id, self.onCircular) 
196       
197        id = wx.NewId()
198        slicerpop.Append(id, '&Sector [Q view]')
199        wx.EVT_MENU(self, id, self.onSectorQ) 
200       
201        id = wx.NewId()
202        slicerpop.Append(id, '&Annulus [Phi view ]')
203        wx.EVT_MENU(self, id, self.onSectorPhi) 
204       
205        id = wx.NewId()
206        slicerpop.Append(id, '&Box Sum')
207        wx.EVT_MENU(self, id, self.onBoxSum) 
208       
209        id = wx.NewId()
210        slicerpop.Append(id, '&Box averaging')
211        wx.EVT_MENU(self, id, self.onBoxavg) 
212       
213        id = wx.NewId()
214        slicerpop.Append(id, '&Clear slicer')
215        wx.EVT_MENU(self, id,  self.onClearSlicer) 
216       
217        id = wx.NewId()
218        slicerpop.Append(id, '&Edit Slicer Parameters')
219        wx.EVT_MENU(self, id, self._onEditSlicer) 
220       
221        slicerpop.AppendSeparator()
222       
223        id = wx.NewId()
224        slicerpop.Append(id, '&Save image')
225        wx.EVT_MENU(self, id, self.onSaveImage) 
226     
227        id = wx.NewId()
228        slicerpop.Append(id, '&Toggle Linear/Log scale')
229        wx.EVT_MENU(self, id, self._onToggleScale) 
230         
231        pos = event.GetPosition()
232        pos = self.ScreenToClient(pos)
233        self.PopupMenu(slicerpop, pos)
234   
235    def _setSlicer(self, slicer):
236        # Clear current slicer
237        #printEVT("Plotter2D._setSlicer %s" % slicer)
238       
239        if not self.slicer == None: 
240            self.slicer.clear()           
241           
242        self.slicer_z += 1
243        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
244        self.subplot.set_ylim(-self.qmax, self.qmax)
245        self.subplot.set_xlim(-self.qmax, self.qmax)
246        self.update()
247        self.slicer.update()
248       
249       
250    def get_corrected_data(self):
251        # Protect against empty data set
252        if self.data == None:
253            return None
254        import copy
255        output = copy.deepcopy(self.data)
256        return output
257    def freeze_axes(self):
258        self.axes_frozen = True
259       
260    def thaw_axes(self):
261        self.axes_frozen = False
262       
263    def onMouseMotion(self,event):
264        pass
265    def onWheel(self, event):
266        pass   
267    def update(self, draw=True):
268        """
269            Respond to changes in the model by recalculating the
270            profiles and resetting the widgets.
271        """
272        #self.slicer.update()
273        self.draw()
274       
275       
276    def _getEmptySlicerEvent(self):
277        return SlicerEvent(type=None,
278                           params=None,
279                           obj_class=None)
280    def _onEVT_INTERNAL(self, event):
281        """
282            I don't understand why Unbind followed by a Bind
283            using a modified self.slicer doesn't work.
284            For now, I post a clear event followed by
285            a new slicer event...
286        """
287        self._setSlicer(event.slicer)
288           
289    def _setSlicer(self, slicer):
290        # Clear current slicer
291        #printEVT("Plotter2D._setSlicer %s" % slicer)
292       
293        if not self.slicer == None: 
294            self.slicer.clear()           
295           
296        self.slicer_z += 1
297        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
298        self.subplot.set_ylim(-self.qmax, self.qmax)
299        self.subplot.set_xlim(-self.qmax, self.qmax)
300        self.update()
301        self.slicer.update()
302       
303        # Post slicer event
304        event = self._getEmptySlicerEvent()
305        event.type = self.slicer.__class__.__name__
306        event.obj_class = self.slicer.__class__
307        event.params = self.slicer.get_params()
308        wx.PostEvent(self.parent, event)
309
310    def onCircular(self, event):
311        """
312            perform circular averaging on Data2D
313        """
314       
315        from DataLoader.manipulations import CircularAverage
316        import math
317        self.radius= math.sqrt( math.pow(self.qmax,2)+math.pow(self.qmax,2)) 
318        print "radius?",self.radius
319        Circle = CircularAverage( r_min=0, r_max=self.radius, bin_width=0.001)
320        #Circle = CircularAverage( r_min=0, r_max=13705.0, bin_width=BIN_WIDTH )
321        #Circle = CircularAverage( r_min= -1, r_max= 1, bin_width=0.001 )
322        #Circle = CircularAverage( r_min= -1*self.radius, r_max= self.radius, bin_width=0.001 )
323        circ = Circle(self.data2D)
324        from sans.guiframe.dataFitting import Data1D
325        if hasattr(circ,"dxl"):
326            dxl= circ.dxl
327        else:
328            dxl= None
329        if hasattr(circ,"dxw"):
330            dxw= circ.dxw
331        else:
332            dxw= None
333       
334        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
335        new_plot.name = "Circ avg "+ self.data2D.name
336        new_plot.source=self.data2D.source
337        new_plot.info=self.data2D.info
338        new_plot.interactive = True
339        #print "loader output.detector",output.source
340        new_plot.detector =self.data2D.detector
341       
342        # If the data file does not tell us what the axes are, just assume...
343        new_plot.xaxis("\\rm{q}","A^{-1}")
344        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
345        new_plot.group_id = "Circ avg "+ self.data2D.name
346        self.scale = 'log'
347       
348        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
349       
350    def _onEditSlicer(self, event):
351        if self.slicer !=None:
352            from SlicerParameters import SlicerParameterPanel
353            dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
354            dialog.set_slicer(self.slicer.__class__.__name__,
355                            self.slicer.get_params())
356            if dialog.ShowModal() == wx.ID_OK:
357                dialog.Destroy() 
358       
359    def onSectorQ(self, event):
360        """
361            Perform sector averaging on Q
362        """
363       
364        from SectorSlicer import SectorInteractor
365        self.onClearSlicer(event)
366        wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractor))
367       
368    def onSectorPhi(self, event):
369        """
370            Perform sector averaging on Phi
371        """
372        from AnnulusSlicer import AnnulusInteractor
373        self.onClearSlicer(event)
374        wx.PostEvent(self.parent, InternalEvent(slicer= AnnulusInteractor))
375       
376    def onBoxSum(self,event):
377        from boxSum import BoxSum
378        self.onClearSlicer(event)
379        wx.PostEvent(self.parent, InternalEvent(slicer= BoxSum))
380        """
381        self.onClearSlicer(event)
382        self.slicer=BoxInteractor
383        from SlicerParameters import SlicerParameterPanel
384       
385        dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
386        dialog.set_slicer(self.slicer.__name__,
387                        self.slicer.get_params())
388        if dialog.ShowModal() == wx.ID_OK:
389            dialog.Destroy()
390        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
391        print "onboxavg",self.slicer
392        """ 
393    def onBoxavg(self,event):
394        from boxSlicer import BoxInteractor
395        self.onClearSlicer(event)
396        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
397        """
398        self.onClearSlicer(event)
399        self.slicer=BoxInteractor
400        from SlicerParameters import SlicerParameterPanel
401       
402        dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
403        dialog.set_slicer(self.slicer.__name__,
404                        self.slicer.get_params())
405        if dialog.ShowModal() == wx.ID_OK:
406            dialog.Destroy()
407        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
408        print "onboxavg",self.slicer
409        """
410       
411    def onClearSlicer(self, event):
412        """
413            Clear the slicer on the plot
414        """
415        if not self.slicer==None:
416            self.slicer.clear()
417            self.subplot.figure.canvas.draw()
418            self.slicer = None
419       
420            # Post slicer None event
421            event = self._getEmptySlicerEvent()
422            wx.PostEvent(self.parent, event)
423         
424    def _onEditDetector(self, event):
425        print "on parameter"
426       
427       
428    def _onToggleScale(self, event):
429        """
430            toggle pixel scale and replot image
431        """
432        if self.scale == 'log':
433            self.scale = 'linear'
434        else:
435            self.scale = 'log'
436        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
437                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
438        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
439       
440       
441       
442       
443       
Note: See TracBrowser for help on using the repository browser.