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

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

override a plot update —> model can be plotted with unik name

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