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

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

plotter1d and plotter2d file created

  • Property mode set to 100644
File size: 12.3 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
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        self.x = pylab.arange(-1*self.qmax, self.qmax+self.qstep*0.01, self.qstep)
85        self.y = pylab.arange(-1*self.imax, self.imax+self.qstep*0.01, self.qstep)
86
87        self.slicer_z = 5
88        self.slicer = None
89        self.parent.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
90        self.axes_frozen = False
91       
92       
93        ## Graph       
94        self.graph = Graph()
95        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
96        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
97        self.graph.render(self)
98 
99    def _onEVT_1DREPLOT(self, event):
100        """
101            Data is ready to be displayed
102            @param event: data event
103        """
104        #TODO: Check for existence of plot attribute
105        # Check whether this is a replot. If we ask for a replot
106        # and the plottable no longer exists, ignore the event.
107        if hasattr(event, "update") and event.update==True \
108            and event.plot.name not in self.plots.keys():
109            return
110        if hasattr(event, "reset"):
111            self._reset()
112        is_new = True
113        if event.plot.name in self.plots.keys():
114            # Check whether the class of plottable changed
115            if not event.plot.__class__==self.plots[event.plot.name].__class__:
116                self.graph.delete(self.plots[event.plot.name])
117            else:
118                is_new = False
119        self.plots[event.plot.name] = event.plot
120        #if is_new:
121        self.graph.add(self.plots[event.plot.name])
122       
123
124        # Check axis labels
125        #TODO: Should re-factor this
126        #if event.plot._xunit != self.graph.prop["xunit"]:
127       
128        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
129        #if event.plot._yunit != self.graph.prop["yunit"]:
130        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
131        self.graph.render(self)
132        self.subplot.figure.canvas.draw_idle()
133
134
135    def onContextMenu(self, event):
136        """
137            2D plot context menu
138            @param event: wx context event
139        """
140       
141        #slicerpop = wx.Menu()
142        slicerpop = PanelMenu()
143        slicerpop.set_plots(self.plots)
144        slicerpop.set_graph(self.graph)
145               
146        # Option to save the data displayed
147   
148        # Various plot options
149        id = wx.NewId()
150        slicerpop.Append(id,'&Save image', 'Save image as PNG')
151        wx.EVT_MENU(self, id, self.onSaveImage)
152       
153       
154        item_list = self.parent.get_context_menu(self.graph)
155        if (not item_list==None) and (not len(item_list)==0):
156                slicerpop.AppendSeparator()
157                for item in item_list:
158                    try:
159                        id = wx.NewId()
160                        slicerpop.Append(id, item[0], item[1])
161                        wx.EVT_MENU(self, id, item[2])
162                    except:
163                        print sys.exc_value
164                        print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
165       
166        slicerpop.AppendSeparator()
167       
168        id = wx.NewId()
169        slicerpop.Append(id, '&Perform circular average')
170        wx.EVT_MENU(self, id, self.onCircular) 
171       
172        id = wx.NewId()
173        slicerpop.Append(id, '&Sector Q')
174        wx.EVT_MENU(self, id, self.onSectorQ) 
175       
176        id = wx.NewId()
177        slicerpop.Append(id, '&Sector Phi')
178        wx.EVT_MENU(self, id, self.onSectorPhi) 
179     
180       
181        id = wx.NewId()
182        slicerpop.Append(id, '&Clear slicer')
183        wx.EVT_MENU(self, id,  self.onClearSlicer) 
184       
185        id = wx.NewId()
186        slicerpop.Append(id, '&Edit Slicer Parameters')
187        wx.EVT_MENU(self, id, self._onEditSlicer) 
188       
189        slicerpop.AppendSeparator()
190       
191        id = wx.NewId()
192        slicerpop.Append(id, '&Save image')
193        wx.EVT_MENU(self, id, self.onSaveImage) 
194     
195        id = wx.NewId()
196        slicerpop.Append(id, '&Toggle Linear/Log scale')
197        wx.EVT_MENU(self, id, self._onToggleScale) 
198         
199        pos = event.GetPosition()
200        pos = self.ScreenToClient(pos)
201        self.PopupMenu(slicerpop, pos)
202   
203    def _setSlicer(self, slicer):
204        # Clear current slicer
205        #printEVT("Plotter2D._setSlicer %s" % slicer)
206       
207        if not self.slicer == None: 
208            self.slicer.clear()           
209           
210        self.slicer_z += 1
211        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
212        self.subplot.set_ylim(-self.qmax, self.qmax)
213        self.subplot.set_xlim(-self.qmax, self.qmax)
214        self.update()
215        self.slicer.update()
216       
217       
218    def get_corrected_data(self):
219        # Protect against empty data set
220        if self.data == None:
221            return None
222        import copy
223        output = copy.deepcopy(self.data)
224        return output
225    def freeze_axes(self):
226        self.axes_frozen = True
227       
228    def thaw_axes(self):
229        self.axes_frozen = False
230       
231    def onMouseMotion(self,event):
232        pass
233    def onWheel(self, event):
234        pass   
235    def update(self, draw=True):
236        """
237            Respond to changes in the model by recalculating the
238            profiles and resetting the widgets.
239        """
240        #self.slicer.update()
241        self.draw()
242       
243       
244    def _getEmptySlicerEvent(self):
245        return SlicerEvent(type=None,
246                           params=None,
247                           obj_class=None)
248    def _onEVT_INTERNAL(self, event):
249        """
250            I don't understand why Unbind followed by a Bind
251            using a modified self.slicer doesn't work.
252            For now, I post a clear event followed by
253            a new slicer event...
254        """
255        self._setSlicer(event.slicer)
256           
257    def _setSlicer(self, slicer):
258        # Clear current slicer
259        #printEVT("Plotter2D._setSlicer %s" % slicer)
260       
261        if not self.slicer == None: 
262            self.slicer.clear()           
263           
264        self.slicer_z += 1
265        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
266        self.subplot.set_ylim(-self.qmax, self.qmax)
267        self.subplot.set_xlim(-self.qmax, self.qmax)
268        self.update()
269        self.slicer.update()
270       
271        # Post slicer event
272        event = self._getEmptySlicerEvent()
273        event.type = self.slicer.__class__.__name__
274        event.obj_class = self.slicer.__class__
275        event.params = self.slicer.get_params()
276        wx.PostEvent(self.parent, event)
277
278    def onCircular(self, event):
279        """
280            perform circular averaging on Data2D
281        """
282       
283        from DataLoader.manipulations import CircularAverage
284        Circle = CircularAverage( r_min= 0, r_max= self.qmax, bin_width=BIN_WIDTH )
285        #Circle = CircularAverage( r_min= -1, r_max= 1, bin_width=0.001 )
286        circ = Circle(self.data2D)
287        from sans.guiframe.dataFitting import Data1D
288        if hasattr(circ,"dxl"):
289            dxl= circ.dxl
290        else:
291            dxl= None
292        if hasattr(circ,"dxw"):
293            dxw= circ.dxw
294        else:
295            dxw= None
296           
297        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
298        new_plot.name = "Circ avg "+ self.data2D.name
299        new_plot.source=self.data2D.source
300        new_plot.info=self.data2D.info
301        new_plot.interactive = True
302        #print "loader output.detector",output.source
303        new_plot.detector =self.data2D.detector
304       
305        # If the data file does not tell us what the axes are, just assume...
306        new_plot.xaxis("\\rm{q}","A^{-1}")
307        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
308        new_plot.group_id = "Circ avg "+ self.data2D.name
309        self.scale = 'log'
310        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
311       
312       
313    def _onEditSlicer(self, event):
314        if self.slicer !=None:
315            from SlicerParameters import SlicerParameterPanel
316            dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
317            dialog.set_slicer(self.slicer.__class__.__name__,
318                            self.slicer.get_params())
319            if dialog.ShowModal() == wx.ID_OK:
320                dialog.Destroy() 
321       
322    def onSectorQ(self, event):
323        """
324            Perform sector averaging on Q
325        """
326       
327        from SectorSlicer import SectorInteractorQ
328        self.onClearSlicer(event)
329        wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractorQ))
330       
331    def onSectorPhi(self, event):
332        """
333            Perform sector averaging on Phi
334        """
335        from SectorSlicer import SectorInteractorPhi
336        self.onClearSlicer(event)
337        wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractorPhi))
338       
339       
340    def onClearSlicer(self, event):
341        """
342            Clear the slicer on the plot
343        """
344        if not self.slicer==None:
345            self.slicer.clear()
346            self.subplot.figure.canvas.draw()
347            self.slicer = None
348       
349            # Post slicer None event
350            event = self._getEmptySlicerEvent()
351            wx.PostEvent(self.parent, event)
352         
353    def _onEditDetector(self, event):
354        print "on parameter"
355       
356       
357    def _onToggleScale(self, event):
358        """
359            toggle pixel scale and replot image
360        """
361        if self.scale == 'log':
362            self.scale = 'linear'
363        else:
364            self.scale = 'log'
365        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
366                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
367        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
368       
369       
370       
371       
372       
Note: See TracBrowser for help on using the repository browser.