source: sasview/guiframe/local_perspectives/plotting/Plotter2D.py @ 1bf33c1

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 1bf33c1 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
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
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.