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
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        # 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       
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
335       
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'
349       
350        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
351       
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       
366        from SectorSlicer import SectorInteractor
367        self.onClearSlicer(event)
368        wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractor))
369       
370    def onSectorPhi(self, event):
371        """
372            Perform sector averaging on Phi
373        """
374        from AnnulusSlicer import AnnulusInteractor
375        self.onClearSlicer(event)
376        wx.PostEvent(self.parent, InternalEvent(slicer= AnnulusInteractor))
377       
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        """ 
395    def onBoxavg(self,event):
396        from boxSlicer import BoxInteractor
397        self.onClearSlicer(event)
398        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
399        """
400        self.onClearSlicer(event)
401        self.slicer=BoxInteractor
402        from SlicerParameters import SlicerParameterPanel
403       
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()
409        wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractor))
410        print "onboxavg",self.slicer
411        """
412       
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.