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

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

print stament removed

  • Property mode set to 100644
File size: 18.0 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 pylab
15
16import danse.common.plottools
17from danse.common.plottools.PlotPanel import PlotPanel
18from danse.common.plottools.plottables import Graph,Data1D
19from sans.guicomm.events import EVT_NEW_PLOT,EVT_SLICER_PARS_UPDATE
20from sans.guicomm.events import EVT_SLICER_PARS
21from sans.guicomm.events import StatusEvent ,NewPlotEvent,SlicerEvent
22from sans.guiframe.utils import PanelMenu
23from binder import BindArtist
24from Plotter1D import ModelPanel1D
25(InternalEvent, EVT_INTERNAL)   = wx.lib.newevent.NewEvent()
26
27
28
29DEFAULT_QMAX = 0.05
30DEFAULT_QSTEP = 0.001
31DEFAULT_BEAM = 0.005
32BIN_WIDTH = 1.0
33
34
35
36
37class ModelPanel2D( ModelPanel1D):
38    """
39        Plot panel for use with the GUI manager
40    """
41   
42    ## Internal name for the AUI manager
43    window_name = "plotpanel"
44    ## Title to appear on top of the window
45    window_caption = "Plot Panel"
46    ## Flag to tell the GUI manager that this panel is not
47    #  tied to any perspective
48    ALWAYS_ON = True
49    ## Group ID
50    group_id = None
51   
52   
53    def __init__(self, parent, id = -1,data2d=None, color = None,\
54        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
55        """
56            Initialize the panel
57        """
58        ModelPanel1D.__init__(self, parent, id = id, style = style, **kwargs)
59       
60        ## Reference to the parent window
61        self.parent = parent
62        ## Plottables
63        self.plots = {}
64        self.data2D= data2d
65        self.data =data2d.data
66        ## Unique ID (from gui_manager)
67        self.uid = None
68       
69        ## Action IDs for internal call-backs
70        self.action_ids = {}
71        self.connect = BindArtist(self.subplot.figure)
72       
73        # Beam stop
74        self.beamstop_radius = DEFAULT_BEAM
75       
76        self.slicer_z = 5
77        self.slicer = None
78        #self.parent.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
79        self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
80        self.axes_frozen = False
81       
82        self.panel_slicer=None
83        #self.parent.Bind(EVT_SLICER_PARS, self.onParamChange)
84        ## Graph       
85        self.graph = Graph()
86        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
87        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
88        self.graph.render(self)
89        #self.Bind(boxSum.EVT_SLICER_PARS_UPDATE, self._onEVT_SLICER_PARS)
90        self.Bind(EVT_SLICER_PARS, self._onEVT_SLICER_PARS)
91        self.Bind(EVT_SLICER_PARS_UPDATE, self._onEVT_SLICER_PANEL)
92       
93       
94    def _onEVT_SLICER_PARS(self, event):
95        #print "paramaters entered on slicer panel", event.type, event.params
96        self.slicer.set_params(event.params)
97        from sans.guicomm.events import SlicerPanelEvent
98        wx.PostEvent(self.parent, SlicerPanelEvent (panel= self.panel_slicer))
99       
100       
101    def _onEVT_SLICER_PANEL(self, event):
102        #print "box move plotter2D", event.type, event.params
103        self.panel_slicer.set_slicer(event.type, event.params)
104        from sans.guicomm.events import SlicerPanelEvent
105        wx.PostEvent(self.parent, SlicerPanelEvent (panel= self.panel_slicer)) 
106       
107    def _onEVT_1DREPLOT(self, event):
108        """
109            Data is ready to be displayed
110           
111            #TODO: this name should be changed to something more appropriate
112            # Don't forget that changing this name will mean changing code
113            # in plotting.py
114             
115            @param event: data event
116        """
117             
118        self.data2D= event.plot
119        self.data =event.plot.data
120        #TODO: Check for existence of plot attribute
121
122        # Check whether this is a replot. If we ask for a replot
123        # and the plottable no longer exists, ignore the event.
124        if hasattr(event, "update") and event.update==True \
125            and event.plot.name not in self.plots.keys():
126            return
127       
128        if hasattr(event, "reset"):
129            self._reset()
130        is_new = True
131        if event.plot.name in self.plots.keys():
132            # Check whether the class of plottable changed
133            if not event.plot.__class__==self.plots[event.plot.name].__class__:
134                #overwrite a plottable using the same name
135                self.graph.delete(self.plots[event.plot.name])
136            else:
137                # plottable is already draw on the panel
138                is_new = False
139           
140        if is_new:
141            # a new plottable overwrites a plotted one  using the same id
142            for plottable in self.plots.itervalues():
143                if event.plot.id==plottable.id :
144                    self.graph.delete(plottable)
145           
146            self.plots[event.plot.name] = event.plot
147            self.graph.add(self.plots[event.plot.name])
148        else:
149            # Update the plottable with the new data
150           
151            #TODO: we should have a method to do this,
152            #      something along the lines of:
153            #      plottable1.update_data_from_plottable(plottable2)
154           
155            self.plots[event.plot.name].xmin = event.plot.xmin
156            self.plots[event.plot.name].xmax = event.plot.xmax
157            self.plots[event.plot.name].ymin = event.plot.ymin
158            self.plots[event.plot.name].ymax = event.plot.ymax
159            self.plots[event.plot.name].data = event.plot.data
160            self.plots[event.plot.name].err_data = event.plot.err_data
161            # update qmax with the new xmax of data plotted
162            self.qmax= event.plot.xmax
163           
164        self.slicer= None
165       
166        # Check axis labels
167        #TODO: Should re-factor this
168        #if event.plot._xunit != self.graph.prop["xunit"]:
169        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
170           
171        #if event.plot._yunit != self.graph.prop["yunit"]:
172        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
173        self.graph.title(self.data2D.name)
174        self.graph.render(self)
175        self.subplot.figure.canvas.draw_idle()
176
177
178    def onContextMenu(self, event):
179        """
180            2D plot context menu
181            @param event: wx context event
182        """
183       
184        #slicerpop = wx.Menu()
185        slicerpop = PanelMenu()
186        slicerpop.set_plots(self.plots)
187        slicerpop.set_graph(self.graph)
188   
189        item_list = self.parent.get_context_menu(self.graph)
190        if (not item_list==None) and (not len(item_list)==0):
191               
192                for item in item_list:
193                    try:
194                        id = wx.NewId()
195                        slicerpop.Append(id, item[0], item[1])
196                        wx.EVT_MENU(self, id, item[2])
197                    except:
198                        pass
199                        #print sys.exc_value
200                        #print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
201       
202        slicerpop.AppendSeparator()
203       
204        id = wx.NewId()
205        slicerpop.Append(id, '&Perform circular average')
206        wx.EVT_MENU(self, id, self.onCircular) 
207       
208        id = wx.NewId()
209        slicerpop.Append(id, '&Sector [Q view]')
210        wx.EVT_MENU(self, id, self.onSectorQ) 
211       
212        id = wx.NewId()
213        slicerpop.Append(id, '&Annulus [Phi view ]')
214        wx.EVT_MENU(self, id, self.onSectorPhi) 
215       
216        id = wx.NewId()
217        slicerpop.Append(id, '&Box Sum')
218        wx.EVT_MENU(self, id, self.onBoxSum) 
219       
220        id = wx.NewId()
221        slicerpop.Append(id, '&Box averaging in Qx')
222        wx.EVT_MENU(self, id, self.onBoxavgX) 
223       
224        id = wx.NewId()
225        slicerpop.Append(id, '&Box averaging in Qy')
226        wx.EVT_MENU(self, id, self.onBoxavgY) 
227        if self.slicer !=None:
228            id = wx.NewId()
229            slicerpop.Append(id, '&Clear slicer')
230            wx.EVT_MENU(self, id,  self.onClearSlicer) 
231       
232            id = wx.NewId()
233            slicerpop.Append(id, '&Edit Slicer Parameters')
234            wx.EVT_MENU(self, id, self._onEditSlicer) 
235        slicerpop.AppendSeparator() 
236           
237        id = wx.NewId()
238        slicerpop.Append(id, '&Save image')
239        wx.EVT_MENU(self, id, self.onSaveImage) 
240       
241        # Option to save the data displayed
242        id = wx.NewId()
243        slicerpop.Append(id,'&Printer setup', 'Set image size')
244        wx.EVT_MENU(self, id, self.onPrinterSetup)
245       
246        id = wx.NewId()
247        slicerpop.Append(id,'&Printer Preview', 'Set image size')
248        wx.EVT_MENU(self, id, self.onPrinterPreview)
249   
250        id = wx.NewId()
251        slicerpop.Append(id,'&Print image', 'Print image ')
252        wx.EVT_MENU(self, id, self.onPrint)
253        slicerpop.AppendSeparator()
254        id = wx.NewId()
255        slicerpop.Append(id, '&Toggle Linear/Log scale')
256        wx.EVT_MENU(self, id, self._onToggleScale) 
257                 
258     
259        pos = event.GetPosition()
260        pos = self.ScreenToClient(pos)
261        self.PopupMenu(slicerpop, pos)
262       
263   
264       
265       
266    def get_corrected_data(self):
267        # Protect against empty data set
268        if self.data == None:
269            return None
270        import copy
271        output = copy.deepcopy(self.data)
272        return output
273    def freeze_axes(self):
274        self.axes_frozen = True
275       
276    def thaw_axes(self):
277        self.axes_frozen = False
278       
279    def onMouseMotion(self,event):
280        pass
281    def onWheel(self, event):
282        pass   
283    def update(self, draw=True):
284        """
285            Respond to changes in the model by recalculating the
286            profiles and resetting the widgets.
287        """
288        #self.slicer.update()
289        self.draw()
290       
291       
292    def _getEmptySlicerEvent(self):
293        return SlicerEvent(type=None,
294                           params=None,
295                           obj_class=None)
296    def _onEVT_INTERNAL(self, event):
297        """
298            I don't understand why Unbind followed by a Bind
299            using a modified self.slicer doesn't work.
300            For now, I post a clear event followed by
301            a new slicer event...
302        """
303        self._setSlicer(event.slicer)
304           
305    def _setSlicer(self, slicer):
306        # Clear current slicer
307        #printEVT("Plotter2D._setSlicer %s" % slicer)
308       
309        if not self.slicer == None: 
310            self.slicer.clear()           
311           
312        self.slicer_z += 1
313        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
314        #print "come here"
315        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
316        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
317       
318        self.update()
319        self.slicer.update()
320       
321        # Post slicer event
322        event = self._getEmptySlicerEvent()
323        event.type = self.slicer.__class__.__name__
324       
325        event.obj_class = self.slicer.__class__
326        event.params = self.slicer.get_params()
327        #print "Plotter2D: event.type",event.type,event.params, self.parent
328       
329        #wx.PostEvent(self.parent, event)
330        wx.PostEvent(self, event)
331
332    def onCircular(self, event):
333        """
334            perform circular averaging on Data2D
335        """
336       
337        from DataLoader.manipulations import CircularAverage
338        import math
339        self.qmax= self.data2D.xmax
340        self.radius= math.sqrt( math.pow(self.qmax,2)+math.pow(self.qmax,2)) 
341        #print "radius?",self.radius
342        # bin_width = self.qmax -self.qmin/nbins
343        #nbins= 30
344        bin_width = (self.qmax +self.qmax)/30
345       
346        Circle = CircularAverage( r_min=0, r_max=self.radius, bin_width=bin_width)
347       
348        circ = Circle(self.data2D)
349        from sans.guiframe.dataFitting import Data1D
350        if hasattr(circ,"dxl"):
351            dxl= circ.dxl
352        else:
353            dxl= None
354        if hasattr(circ,"dxw"):
355            dxw= circ.dxw
356        else:
357            dxw= None
358       
359        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
360        new_plot.name = "Circ avg "+ self.data2D.name
361        new_plot.source=self.data2D.source
362        #new_plot.info=self.data2D.info
363        new_plot.interactive = True
364        #print "loader output.detector",output.source
365        new_plot.detector =self.data2D.detector
366       
367        # If the data file does not tell us what the axes are, just assume...
368        new_plot.xaxis("\\rm{q}","A^{-1}")
369        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
370        new_plot.group_id = "Circ avg "+ self.data2D.name
371        self.scale = 'log'
372       
373        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
374       
375    def _onEditSlicer(self, event):
376        if self.slicer !=None:
377            from SlicerParameters import SlicerParameterPanel
378            dialog = SlicerParameterPanel(self.parent, -1, "Slicer Parameters")
379            dialog.set_slicer(self.slicer.__class__.__name__,
380                            self.slicer.get_params())
381            if dialog.ShowModal() == wx.ID_OK:
382                dialog.Destroy() 
383       
384    def onSectorQ(self, event):
385        """
386            Perform sector averaging on Q
387        """
388        #print "onsector self.data2Dxmax",self.data2D.xmax, self.parent
389        from SectorSlicer import SectorInteractor
390        self.onClearSlicer(event)
391        #wx.PostEvent(self.parent, InternalEvent(slicer= SectorInteractor))
392        wx.PostEvent(self, InternalEvent(slicer= SectorInteractor))
393       
394    def onSectorPhi(self, event):
395        """
396            Perform sector averaging on Phi
397        """
398        from AnnulusSlicer import AnnulusInteractor
399        self.onClearSlicer(event)
400        #wx.PostEvent(self.parent, InternalEvent(slicer= AnnulusInteractor))
401        wx.PostEvent(self, InternalEvent(slicer= AnnulusInteractor))
402       
403    def onBoxSum(self,event):
404        from boxSum import BoxSum
405        self.onClearSlicer(event)
406        #wx.PostEvent(self.parent, InternalEvent(slicer= BoxSum))
407        if not self.slicer == None: 
408            self.slicer.clear()             
409        self.slicer_z += 1
410        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
411        #print "come here"
412        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
413        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
414       
415        self.update()
416        self.slicer.update()
417       
418        # Post slicer event
419        event = self._getEmptySlicerEvent()
420        event.type = self.slicer.__class__.__name__
421       
422       
423        event.obj_class = self.slicer.__class__
424        event.params = self.slicer.get_params()
425        #print "Plotter2D: event.type",event.type,event.params, self.parent
426       
427        from slicerpanel import SlicerPanel
428        new_panel = SlicerPanel(parent= self.parent,id= -1,base= self,type=event.type,
429                                 params=event.params, style=wx.RAISED_BORDER)
430        #new_panel.set_slicer(self.slicer.__class__.__name__,
431        new_panel.window_caption=self.slicer.__class__.__name__+" "+ str(self.data2D.name)
432       
433        self.panel_slicer= new_panel
434       
435        wx.PostEvent(self.panel_slicer, event)
436        from sans.guicomm.events import SlicerPanelEvent
437        wx.PostEvent(self.parent, SlicerPanelEvent (panel= self.panel_slicer))
438        #print "finish box sum"
439       
440    def onBoxavgX(self,event):
441        from boxSlicer import BoxInteractorX
442        self.onClearSlicer(event)
443        #wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractorX))
444        wx.PostEvent(self, InternalEvent(slicer= BoxInteractorX))
445       
446       
447    def onBoxavgY(self,event):
448        from boxSlicer import BoxInteractorY
449        self.onClearSlicer(event)
450        wx.PostEvent(self, InternalEvent(slicer= BoxInteractorY))
451        #wx.PostEvent(self.parent, InternalEvent(slicer= BoxInteractorY))
452       
453    def onClearSlicer(self, event):
454        """
455            Clear the slicer on the plot
456        """
457        if not self.slicer==None:
458            self.slicer.clear()
459            self.subplot.figure.canvas.draw()
460            self.slicer = None
461       
462            # Post slicer None event
463            event = self._getEmptySlicerEvent()
464            #wx.PostEvent(self.parent, event)
465            wx.PostEvent(self, event)
466         
467    def _onEditDetector(self, event):
468        print "on parameter"
469       
470       
471    def _onToggleScale(self, event):
472        """
473            toggle pixel scale and replot image
474        """
475        if self.scale == 'log':
476            self.scale = 'linear'
477        else:
478            self.scale = 'log'
479        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
480                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
481        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
482       
483        """     
484            #TODO: this name should be changed to something more appropriate
485            # Don't forget that changing this name will mean changing code
486            # in plotting.py
487             
488            # Update the plottable with the new data
489           
490            #TODO: we should have a method to do this,
491            #      something along the lines of:
492            #      plottable1.update_data_from_plottable(plottable2)
493           
494            self.plots[event.plot.name].xmin = event.plot.xmin
495            self.plots[event.plot.name].xmax = event.plot.xmax
496            self.plots[event.plot.name].ymin = event.plot.ymin
497            self.plots[event.plot.name].ymax = event.plot.ymax
498            self.plots[event.plot.name].data = event.plot.data
499            self.plots[event.plot.name].err_data = event.plot.err_data
500        """
Note: See TracBrowser for help on using the repository browser.