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

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

working on slicer

  • Property mode set to 100644
File size: 13.7 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       
206        id = wx.NewId()
207        slicerpop.Append(id, '&Clear slicer')
208        wx.EVT_MENU(self, id,  self.onClearSlicer) 
209       
210        id = wx.NewId()
211        slicerpop.Append(id, '&Edit Slicer Parameters')
212        wx.EVT_MENU(self, id, self._onEditSlicer) 
213       
214        slicerpop.AppendSeparator()
215       
216        id = wx.NewId()
217        slicerpop.Append(id, '&Save image')
218        wx.EVT_MENU(self, id, self.onSaveImage) 
219     
220        id = wx.NewId()
221        slicerpop.Append(id, '&Toggle Linear/Log scale')
222        wx.EVT_MENU(self, id, self._onToggleScale) 
223         
224        pos = event.GetPosition()
225        pos = self.ScreenToClient(pos)
226        self.PopupMenu(slicerpop, pos)
227   
228    def _setSlicer(self, slicer):
229        # Clear current slicer
230        #printEVT("Plotter2D._setSlicer %s" % slicer)
231       
232        if not self.slicer == None: 
233            self.slicer.clear()           
234           
235        self.slicer_z += 1
236        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
237        self.subplot.set_ylim(-self.qmax, self.qmax)
238        self.subplot.set_xlim(-self.qmax, self.qmax)
239        self.update()
240        self.slicer.update()
241       
242       
243    def get_corrected_data(self):
244        # Protect against empty data set
245        if self.data == None:
246            return None
247        import copy
248        output = copy.deepcopy(self.data)
249        return output
250    def freeze_axes(self):
251        self.axes_frozen = True
252       
253    def thaw_axes(self):
254        self.axes_frozen = False
255       
256    def onMouseMotion(self,event):
257        pass
258    def onWheel(self, event):
259        pass   
260    def update(self, draw=True):
261        """
262            Respond to changes in the model by recalculating the
263            profiles and resetting the widgets.
264        """
265        #self.slicer.update()
266        self.draw()
267       
268       
269    def _getEmptySlicerEvent(self):
270        return SlicerEvent(type=None,
271                           params=None,
272                           obj_class=None)
273    def _onEVT_INTERNAL(self, event):
274        """
275            I don't understand why Unbind followed by a Bind
276            using a modified self.slicer doesn't work.
277            For now, I post a clear event followed by
278            a new slicer event...
279        """
280        self._setSlicer(event.slicer)
281           
282    def _setSlicer(self, slicer):
283        # Clear current slicer
284        #printEVT("Plotter2D._setSlicer %s" % slicer)
285       
286        if not self.slicer == None: 
287            self.slicer.clear()           
288           
289        self.slicer_z += 1
290        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
291        self.subplot.set_ylim(-self.qmax, self.qmax)
292        self.subplot.set_xlim(-self.qmax, self.qmax)
293        self.update()
294        self.slicer.update()
295       
296        # Post slicer event
297        event = self._getEmptySlicerEvent()
298        event.type = self.slicer.__class__.__name__
299        event.obj_class = self.slicer.__class__
300        event.params = self.slicer.get_params()
301        wx.PostEvent(self.parent, event)
302
303    def onCircular(self, event):
304        """
305            perform circular averaging on Data2D
306        """
307       
308        from DataLoader.manipulations import CircularAverage
309        import math
310        self.radius= math.sqrt( math.pow(self.qmax,2)+math.pow(self.qmax,2)) 
311        print "radius?",self.radius
312        Circle = CircularAverage( r_min=0, r_max=self.radius, bin_width=0.001)
313        #Circle = CircularAverage( r_min=0, r_max=13705.0, bin_width=BIN_WIDTH )
314        #Circle = CircularAverage( r_min= -1, r_max= 1, bin_width=0.001 )
315        #Circle = CircularAverage( r_min= -1*self.radius, r_max= self.radius, bin_width=0.001 )
316        circ = Circle(self.data2D)
317        from sans.guiframe.dataFitting import Data1D
318        if hasattr(circ,"dxl"):
319            dxl= circ.dxl
320        else:
321            dxl= None
322        if hasattr(circ,"dxw"):
323            dxw= circ.dxw
324        else:
325            dxw= None
326       
327        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
328        new_plot.name = "Circ avg "+ self.data2D.name
329        new_plot.source=self.data2D.source
330        new_plot.info=self.data2D.info
331        new_plot.interactive = True
332        #print "loader output.detector",output.source
333        new_plot.detector =self.data2D.detector
334       
335        # If the data file does not tell us what the axes are, just assume...
336        new_plot.xaxis("\\rm{q}","A^{-1}")
337        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
338        new_plot.group_id = "Circ avg "+ self.data2D.name
339        self.scale = 'log'
340       
341        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
342       
343    def _onEditSlicer(self, event):
344        if self.slicer !=None:
345            from SlicerParameters import SlicerParameterPanel
346            dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
347            dialog.set_slicer(self.slicer.__class__.__name__,
348                            self.slicer.get_params())
349            if dialog.ShowModal() == wx.ID_OK:
350                dialog.Destroy() 
351       
352    def onSectorQ(self, event):
353        """
354            Perform sector averaging on Q
355        """
356       
357        from SectorSlicer import SectorInteractor
358        self.onClearSlicer(event)
359        wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractor))
360       
361    def onSectorPhi(self, event):
362        """
363            Perform sector averaging on Phi
364        """
365        from AnnulusSlicer import AnnulusInteractor
366        self.onClearSlicer(event)
367        wx.PostEvent(self.parent, InternalEvent(slicer= AnnulusInteractor))
368       
369       
370    def onClearSlicer(self, event):
371        """
372            Clear the slicer on the plot
373        """
374        if not self.slicer==None:
375            self.slicer.clear()
376            self.subplot.figure.canvas.draw()
377            self.slicer = None
378       
379            # Post slicer None event
380            event = self._getEmptySlicerEvent()
381            wx.PostEvent(self.parent, event)
382         
383    def _onEditDetector(self, event):
384        print "on parameter"
385       
386       
387    def _onToggleScale(self, event):
388        """
389            toggle pixel scale and replot image
390        """
391        if self.scale == 'log':
392            self.scale = 'linear'
393        else:
394            self.scale = 'log'
395        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
396                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
397        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
398       
399       
400       
401       
402       
Note: See TracBrowser for help on using the repository browser.