source: sasview/guiframe/local_perspectives/plotting/Plotter2D.py @ d1dd9d4

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

boxaveraging still bugging on set_params

  • Property mode set to 100644
File size: 16.4 KB
RevLine 
[1bf33c1]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
[ef0c170]31BIN_WIDTH = 1.0
[1bf33c1]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
[ac9a5f6]63        self.data =data2d.data
[1bf33c1]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
[ef0c170]83        #print "panel2D qmax",self.qmax,
84       
[1bf33c1]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
[4b91fd1]103           
104            #TODO: this name should be changed to something more appropriate
105            # Don't forget that changing this name will mean changing code
106            # in plotting.py
107             
[1bf33c1]108            @param event: data event
109        """
110        #TODO: Check for existence of plot attribute
[ab8f936]111
[1bf33c1]112        # Check whether this is a replot. If we ask for a replot
113        # and the plottable no longer exists, ignore the event.
114        if hasattr(event, "update") and event.update==True \
115            and event.plot.name not in self.plots.keys():
116            return
[ab8f936]117       
[1bf33c1]118        if hasattr(event, "reset"):
119            self._reset()
120        is_new = True
121        if event.plot.name in self.plots.keys():
122            # Check whether the class of plottable changed
123            if not event.plot.__class__==self.plots[event.plot.name].__class__:
[ab8f936]124                #overwrite a plottable using the same name
[1bf33c1]125                self.graph.delete(self.plots[event.plot.name])
126            else:
[ab8f936]127                # plottable is already draw on the panel
[1bf33c1]128                is_new = False
[ab8f936]129           
130        if is_new:
131            # a new plottable overwrites a plotted one  using the same id
132            for plottable in self.plots.itervalues():
133                if event.plot.id==plottable.id :
134                    self.graph.delete(plottable)
135           
136            self.plots[event.plot.name] = event.plot
137            self.graph.add(self.plots[event.plot.name])
138        else:
[4b91fd1]139            # Update the plottable with the new data
140           
141            #TODO: we should have a method to do this,
142            #      something along the lines of:
143            #      plottable1.update_data_from_plottable(plottable2)
144           
145            self.plots[event.plot.name].xmin = event.plot.xmin
146            self.plots[event.plot.name].xmax = event.plot.xmax
147            self.plots[event.plot.name].ymin = event.plot.ymin
148            self.plots[event.plot.name].ymax = event.plot.ymax
149            self.plots[event.plot.name].data = event.plot.data
150            self.plots[event.plot.name].err_data = event.plot.err_data
[ac9a5f6]151            # update qmax with the new xmax of data plotted
152            self.qmax= event.plot.xmax
[4b91fd1]153           
[ac9a5f6]154        self.slicer= None
[1bf33c1]155        # Check axis labels
156        #TODO: Should re-factor this
157        #if event.plot._xunit != self.graph.prop["xunit"]:
158        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
[ab8f936]159           
[1bf33c1]160        #if event.plot._yunit != self.graph.prop["yunit"]:
161        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
[ab8f936]162     
[1bf33c1]163        self.graph.render(self)
164        self.subplot.figure.canvas.draw_idle()
165
166
167    def onContextMenu(self, event):
168        """
169            2D plot context menu
170            @param event: wx context event
171        """
172       
173        #slicerpop = wx.Menu()
174        slicerpop = PanelMenu()
175        slicerpop.set_plots(self.plots)
176        slicerpop.set_graph(self.graph)
177               
178        # Option to save the data displayed
179   
180        # Various plot options
181        id = wx.NewId()
182        slicerpop.Append(id,'&Save image', 'Save image as PNG')
183        wx.EVT_MENU(self, id, self.onSaveImage)
184       
185       
186        item_list = self.parent.get_context_menu(self.graph)
187        if (not item_list==None) and (not len(item_list)==0):
188                slicerpop.AppendSeparator()
189                for item in item_list:
190                    try:
191                        id = wx.NewId()
192                        slicerpop.Append(id, item[0], item[1])
193                        wx.EVT_MENU(self, id, item[2])
194                    except:
195                        print sys.exc_value
196                        print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
197       
198        slicerpop.AppendSeparator()
199       
200        id = wx.NewId()
201        slicerpop.Append(id, '&Perform circular average')
202        wx.EVT_MENU(self, id, self.onCircular) 
203       
204        id = wx.NewId()
[ef0c170]205        slicerpop.Append(id, '&Sector [Q view]')
[1bf33c1]206        wx.EVT_MENU(self, id, self.onSectorQ) 
207       
208        id = wx.NewId()
[ef0c170]209        slicerpop.Append(id, '&Annulus [Phi view ]')
[1bf33c1]210        wx.EVT_MENU(self, id, self.onSectorPhi) 
[92c2345]211       
[7ab9241]212        id = wx.NewId()
213        slicerpop.Append(id, '&Box Sum')
214        wx.EVT_MENU(self, id, self.onBoxSum) 
215       
[38224f10]216        id = wx.NewId()
217        slicerpop.Append(id, '&Box averaging')
218        wx.EVT_MENU(self, id, self.onBoxavg) 
[92c2345]219        if self.slicer !=None:
220            id = wx.NewId()
221            slicerpop.Append(id, '&Clear slicer')
222            wx.EVT_MENU(self, id,  self.onClearSlicer) 
[1bf33c1]223       
224       
[92c2345]225            id = wx.NewId()
226            slicerpop.Append(id, '&Edit Slicer Parameters')
227            wx.EVT_MENU(self, id, self._onEditSlicer) 
[1bf33c1]228       
229        slicerpop.AppendSeparator()
230       
231        id = wx.NewId()
232        slicerpop.Append(id, '&Save image')
233        wx.EVT_MENU(self, id, self.onSaveImage) 
234     
235        id = wx.NewId()
236        slicerpop.Append(id, '&Toggle Linear/Log scale')
237        wx.EVT_MENU(self, id, self._onToggleScale) 
238         
239        pos = event.GetPosition()
240        pos = self.ScreenToClient(pos)
241        self.PopupMenu(slicerpop, pos)
242   
243    def _setSlicer(self, slicer):
244        # Clear current slicer
245        #printEVT("Plotter2D._setSlicer %s" % slicer)
246       
247        if not self.slicer == None: 
248            self.slicer.clear()           
249           
250        self.slicer_z += 1
251        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
252        self.subplot.set_ylim(-self.qmax, self.qmax)
253        self.subplot.set_xlim(-self.qmax, self.qmax)
254        self.update()
255        self.slicer.update()
256       
257       
258    def get_corrected_data(self):
259        # Protect against empty data set
260        if self.data == None:
261            return None
262        import copy
263        output = copy.deepcopy(self.data)
264        return output
265    def freeze_axes(self):
266        self.axes_frozen = True
267       
268    def thaw_axes(self):
269        self.axes_frozen = False
270       
271    def onMouseMotion(self,event):
272        pass
273    def onWheel(self, event):
274        pass   
275    def update(self, draw=True):
276        """
277            Respond to changes in the model by recalculating the
278            profiles and resetting the widgets.
279        """
280        #self.slicer.update()
281        self.draw()
282       
283       
284    def _getEmptySlicerEvent(self):
285        return SlicerEvent(type=None,
286                           params=None,
287                           obj_class=None)
288    def _onEVT_INTERNAL(self, event):
289        """
290            I don't understand why Unbind followed by a Bind
291            using a modified self.slicer doesn't work.
292            For now, I post a clear event followed by
293            a new slicer event...
294        """
295        self._setSlicer(event.slicer)
296           
297    def _setSlicer(self, slicer):
298        # Clear current slicer
299        #printEVT("Plotter2D._setSlicer %s" % slicer)
300       
301        if not self.slicer == None: 
302            self.slicer.clear()           
303           
304        self.slicer_z += 1
305        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
306        self.subplot.set_ylim(-self.qmax, self.qmax)
307        self.subplot.set_xlim(-self.qmax, self.qmax)
308        self.update()
309        self.slicer.update()
310       
311        # Post slicer event
312        event = self._getEmptySlicerEvent()
313        event.type = self.slicer.__class__.__name__
[92c2345]314        print "event.type",event.type
[1bf33c1]315        event.obj_class = self.slicer.__class__
316        event.params = self.slicer.get_params()
[92c2345]317        try:
318            event.result= self.slicer.get_result()
319        except:
320            event.result= None
321        print "event.result", event.result
[1bf33c1]322        wx.PostEvent(self.parent, event)
323
324    def onCircular(self, event):
325        """
326            perform circular averaging on Data2D
327        """
328       
329        from DataLoader.manipulations import CircularAverage
[ef0c170]330        import math
331        self.radius= math.sqrt( math.pow(self.qmax,2)+math.pow(self.qmax,2)) 
332        print "radius?",self.radius
[c73d871]333        # bin_width = self.qmax -self.qmin/nbins
334        #nbins= 30
335        bin_width = (self.qmax +self.qmax)/30
336       
337        Circle = CircularAverage( r_min=0, r_max=self.radius, bin_width=bin_width)
338       
[1bf33c1]339        circ = Circle(self.data2D)
340        from sans.guiframe.dataFitting import Data1D
341        if hasattr(circ,"dxl"):
342            dxl= circ.dxl
343        else:
344            dxl= None
345        if hasattr(circ,"dxw"):
346            dxw= circ.dxw
347        else:
348            dxw= None
[ef0c170]349       
[1bf33c1]350        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
351        new_plot.name = "Circ avg "+ self.data2D.name
352        new_plot.source=self.data2D.source
353        new_plot.info=self.data2D.info
354        new_plot.interactive = True
355        #print "loader output.detector",output.source
356        new_plot.detector =self.data2D.detector
357       
358        # If the data file does not tell us what the axes are, just assume...
359        new_plot.xaxis("\\rm{q}","A^{-1}")
360        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
361        new_plot.group_id = "Circ avg "+ self.data2D.name
362        self.scale = 'log'
[ef0c170]363       
[1bf33c1]364        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
[ef0c170]365       
[1bf33c1]366    def _onEditSlicer(self, event):
367        if self.slicer !=None:
368            from SlicerParameters import SlicerParameterPanel
369            dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
370            dialog.set_slicer(self.slicer.__class__.__name__,
371                            self.slicer.get_params())
372            if dialog.ShowModal() == wx.ID_OK:
373                dialog.Destroy() 
374       
375    def onSectorQ(self, event):
376        """
377            Perform sector averaging on Q
378        """
[ac9a5f6]379        print "onsector self.data2Dxmax",self.data2D.xmax
[ef0c170]380        from SectorSlicer import SectorInteractor
[1bf33c1]381        self.onClearSlicer(event)
[ef0c170]382        wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractor))
[1bf33c1]383       
384    def onSectorPhi(self, event):
385        """
386            Perform sector averaging on Phi
387        """
[ef0c170]388        from AnnulusSlicer import AnnulusInteractor
[1bf33c1]389        self.onClearSlicer(event)
[ef0c170]390        wx.PostEvent(self.parent, InternalEvent(slicer= AnnulusInteractor))
[1bf33c1]391       
[7ab9241]392    def onBoxSum(self,event):
393        from boxSum import BoxSum
394        self.onClearSlicer(event)
395        wx.PostEvent(self.parent, InternalEvent(slicer= BoxSum))
[0f6d05f8]396        from SlicerParameters import SlicerParameterPanel
[7ab9241]397       
398        dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
[92c2345]399       
[7ab9241]400        if dialog.ShowModal() == wx.ID_OK:
401            dialog.Destroy()
[92c2345]402           
[38224f10]403    def onBoxavg(self,event):
404        from boxSlicer import BoxInteractor
405        self.onClearSlicer(event)
[3426077]406        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
407        """
408        self.onClearSlicer(event)
[b319def8]409        self.slicer=BoxInteractor
410        from SlicerParameters import SlicerParameterPanel
[3426077]411       
[b319def8]412        dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
413        dialog.set_slicer(self.slicer.__name__,
414                        self.slicer.get_params())
415        if dialog.ShowModal() == wx.ID_OK:
416            dialog.Destroy()
[38224f10]417        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
418        print "onboxavg",self.slicer
[3426077]419        """
[b319def8]420       
[1bf33c1]421    def onClearSlicer(self, event):
422        """
423            Clear the slicer on the plot
424        """
425        if not self.slicer==None:
426            self.slicer.clear()
427            self.subplot.figure.canvas.draw()
428            self.slicer = None
429       
430            # Post slicer None event
431            event = self._getEmptySlicerEvent()
432            wx.PostEvent(self.parent, event)
433         
434    def _onEditDetector(self, event):
435        print "on parameter"
436       
437       
438    def _onToggleScale(self, event):
439        """
440            toggle pixel scale and replot image
441        """
442        if self.scale == 'log':
443            self.scale = 'linear'
444        else:
445            self.scale = 'log'
446        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
447                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
448        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
449       
[0f6d05f8]450        """     
451            #TODO: this name should be changed to something more appropriate
452            # Don't forget that changing this name will mean changing code
453            # in plotting.py
454             
455            # Update the plottable with the new data
456           
457            #TODO: we should have a method to do this,
458            #      something along the lines of:
459            #      plottable1.update_data_from_plottable(plottable2)
460           
461            self.plots[event.plot.name].xmin = event.plot.xmin
462            self.plots[event.plot.name].xmax = event.plot.xmax
463            self.plots[event.plot.name].ymin = event.plot.ymin
464            self.plots[event.plot.name].ymax = event.plot.ymax
465            self.plots[event.plot.name].data = event.plot.data
466            self.plots[event.plot.name].err_data = event.plot.err_data
467        """
Note: See TracBrowser for help on using the repository browser.