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

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

working on boxslicer

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