source: sasview/guiframe/local_perspectives/plotting/Plotter2D.py @ 116da060

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

working on boxslicer

  • Property mode set to 100644
File size: 15.2 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
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
[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
103            @param event: data event
104        """
105        #TODO: Check for existence of plot attribute
[ab8f936]106
[1bf33c1]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
[ab8f936]112       
[1bf33c1]113        if hasattr(event, "reset"):
114            self._reset()
[ef0c170]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
[1bf33c1]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__:
[ab8f936]122                #overwrite a plottable using the same name
123                print "is deleting the new plottable"
[1bf33c1]124                self.graph.delete(self.plots[event.plot.name])
125            else:
[ab8f936]126                # plottable is already draw on the panel
[1bf33c1]127                is_new = False
128
[ab8f936]129           
130        if is_new:
131            # a new plottable overwrites a plotted one  using the same id
[ef0c170]132            #print "went here",self.plots.itervalues()
[ab8f936]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       
[1bf33c1]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)
[ab8f936]152           
[1bf33c1]153        #if event.plot._yunit != self.graph.prop["yunit"]:
154        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
[ab8f936]155     
[1bf33c1]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()
[ef0c170]198        slicerpop.Append(id, '&Sector [Q view]')
[1bf33c1]199        wx.EVT_MENU(self, id, self.onSectorQ) 
200       
201        id = wx.NewId()
[ef0c170]202        slicerpop.Append(id, '&Annulus [Phi view ]')
[1bf33c1]203        wx.EVT_MENU(self, id, self.onSectorPhi) 
[7ab9241]204       
205        id = wx.NewId()
206        slicerpop.Append(id, '&Box Sum')
207        wx.EVT_MENU(self, id, self.onBoxSum) 
208       
[38224f10]209        id = wx.NewId()
210        slicerpop.Append(id, '&Box averaging')
211        wx.EVT_MENU(self, id, self.onBoxavg) 
[1bf33c1]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
[ef0c170]316        import math
317        self.radius= math.sqrt( math.pow(self.qmax,2)+math.pow(self.qmax,2)) 
318        print "radius?",self.radius
[c73d871]319        # bin_width = self.qmax -self.qmin/nbins
320        #nbins= 30
321        bin_width = (self.qmax +self.qmax)/30
322       
323        Circle = CircularAverage( r_min=0, r_max=self.radius, bin_width=bin_width)
324       
[1bf33c1]325        circ = Circle(self.data2D)
326        from sans.guiframe.dataFitting import Data1D
327        if hasattr(circ,"dxl"):
328            dxl= circ.dxl
329        else:
330            dxl= None
331        if hasattr(circ,"dxw"):
332            dxw= circ.dxw
333        else:
334            dxw= None
[ef0c170]335       
[1bf33c1]336        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
337        new_plot.name = "Circ avg "+ self.data2D.name
338        new_plot.source=self.data2D.source
339        new_plot.info=self.data2D.info
340        new_plot.interactive = True
341        #print "loader output.detector",output.source
342        new_plot.detector =self.data2D.detector
343       
344        # If the data file does not tell us what the axes are, just assume...
345        new_plot.xaxis("\\rm{q}","A^{-1}")
346        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
347        new_plot.group_id = "Circ avg "+ self.data2D.name
348        self.scale = 'log'
[ef0c170]349       
[1bf33c1]350        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
[ef0c170]351       
[1bf33c1]352    def _onEditSlicer(self, event):
353        if self.slicer !=None:
354            from SlicerParameters import SlicerParameterPanel
355            dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
356            dialog.set_slicer(self.slicer.__class__.__name__,
357                            self.slicer.get_params())
358            if dialog.ShowModal() == wx.ID_OK:
359                dialog.Destroy() 
360       
361    def onSectorQ(self, event):
362        """
363            Perform sector averaging on Q
364        """
365       
[ef0c170]366        from SectorSlicer import SectorInteractor
[1bf33c1]367        self.onClearSlicer(event)
[ef0c170]368        wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractor))
[1bf33c1]369       
370    def onSectorPhi(self, event):
371        """
372            Perform sector averaging on Phi
373        """
[ef0c170]374        from AnnulusSlicer import AnnulusInteractor
[1bf33c1]375        self.onClearSlicer(event)
[ef0c170]376        wx.PostEvent(self.parent, InternalEvent(slicer= AnnulusInteractor))
[1bf33c1]377       
[7ab9241]378    def onBoxSum(self,event):
379        from boxSum import BoxSum
380        self.onClearSlicer(event)
381        wx.PostEvent(self.parent, InternalEvent(slicer= BoxSum))
382        """
383        self.onClearSlicer(event)
384        self.slicer=BoxInteractor
385        from SlicerParameters import SlicerParameterPanel
386       
387        dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
388        dialog.set_slicer(self.slicer.__name__,
389                        self.slicer.get_params())
390        if dialog.ShowModal() == wx.ID_OK:
391            dialog.Destroy()
392        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
393        print "onboxavg",self.slicer
394        """ 
[38224f10]395    def onBoxavg(self,event):
396        from boxSlicer import BoxInteractor
397        self.onClearSlicer(event)
[3426077]398        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
399        """
400        self.onClearSlicer(event)
[b319def8]401        self.slicer=BoxInteractor
402        from SlicerParameters import SlicerParameterPanel
[3426077]403       
[b319def8]404        dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
405        dialog.set_slicer(self.slicer.__name__,
406                        self.slicer.get_params())
407        if dialog.ShowModal() == wx.ID_OK:
408            dialog.Destroy()
[38224f10]409        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
410        print "onboxavg",self.slicer
[3426077]411        """
[b319def8]412       
[1bf33c1]413    def onClearSlicer(self, event):
414        """
415            Clear the slicer on the plot
416        """
417        if not self.slicer==None:
418            self.slicer.clear()
419            self.subplot.figure.canvas.draw()
420            self.slicer = None
421       
422            # Post slicer None event
423            event = self._getEmptySlicerEvent()
424            wx.PostEvent(self.parent, event)
425         
426    def _onEditDetector(self, event):
427        print "on parameter"
428       
429       
430    def _onToggleScale(self, event):
431        """
432            toggle pixel scale and replot image
433        """
434        if self.scale == 'log':
435            self.scale = 'linear'
436        else:
437            self.scale = 'log'
438        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
439                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
440        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
441       
442       
443       
444       
445       
Note: See TracBrowser for help on using the repository browser.