source: sasview/guiframe/local_perspectives/plotting/DataPanel.py @ f39511b

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

small changes circular averaging

  • Property mode set to 100644
File size: 25.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()
26DEFAULT_QMAX = 0.05
27
28DEFAULT_QSTEP = 0.001
29DEFAULT_BEAM = 0.005
30
31import pylab
32
33class PanelMenu(wx.Menu):
34    plots = None
35    graph = None
36   
37    def set_plots(self, plots):
38        self.plots = plots
39   
40    def set_graph(self, graph):
41        self.graph = graph
42class View1DPanel1D(PlotPanel):
43    """
44        Plot panel for use with the GUI manager
45    """
46   
47    ## Internal name for the AUI manager
48    window_name = "plotpanel"
49    ## Title to appear on top of the window
50    window_caption = "Plot Panel"
51    ## Flag to tell the GUI manager that this panel is not
52    #  tied to any perspective
53    ALWAYS_ON = True
54    ## Group ID
55    group_id = None
56   
57    def __init__(self, parent, id = -1, color = None,\
58        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
59        """
60            Initialize the panel
61        """
62        PlotPanel.__init__(self, parent, id = id, style = style, **kwargs)
63       
64        ## Reference to the parent window
65        self.parent = parent
66        ## Plottables
67        self.plots = {}
68       
69        ## Unique ID (from gui_manager)
70        self.uid = None
71       
72        ## Action IDs for internal call-backs
73        self.action_ids = {}
74       
75        ## Graph       
76        self.graph = Graph()
77        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
78        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
79        self.graph.render(self)
80   
81    def _reset(self):
82        """
83            Resets internal data and graph
84        """   
85        self.graph.reset()
86        self.plots      = {}
87        self.action_ids = {}
88   
89    def _onEVT_1DREPLOT(self, event):
90        """
91            Data is ready to be displayed
92            @param event: data event
93        """
94        #TODO: Check for existence of plot attribute
95
96        # Check whether this is a replot. If we ask for a replot
97        # and the plottable no longer exists, ignore the event.
98        if hasattr(event, "update") and event.update==True \
99            and event.plot.name not in self.plots.keys():
100            return
101       
102        if hasattr(event, "reset"):
103            self._reset()
104       
105        is_new = True
106        print "model panel name",event.plot.name
107        if event.plot.name in self.plots.keys():
108            # Check whether the class of plottable changed
109            print "model panel",event.plot.name,event.plot.__class__
110            if not event.plot.__class__==self.plots[event.plot.name].__class__:
111                self.graph.delete(self.plots[event.plot.name])
112            else:
113                is_new = False
114       
115        if is_new:
116            self.plots[event.plot.name] = event.plot
117            self.graph.add(self.plots[event.plot.name])
118        else:
119            self.plots[event.plot.name].x = event.plot.x   
120            self.plots[event.plot.name].y = event.plot.y   
121            self.plots[event.plot.name].dy = event.plot.dy 
122            if hasattr(event.plot, 'dx') and hasattr(self.plots[event.plot.name], 'dx'):
123                self.plots[event.plot.name].dx = event.plot.dx   
124 
125       
126        # Check axis labels
127        #TODO: Should re-factor this
128        #if event.plot._xunit != self.graph.prop["xunit"]:
129        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
130           
131        #if event.plot._yunit != self.graph.prop["yunit"]:
132        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
133     
134        # Set the view scale for all plots
135        self._onEVT_FUNC_PROPERTY()
136     
137        self.graph.render(self)
138        self.subplot.figure.canvas.draw_idle()
139
140    def onLeftDown(self,event): 
141        """ left button down and ready to drag"""
142           
143        PlotPanel.onLeftDown(self, event)
144        ax = event.inaxes
145        if ax != None:
146            position = "x: %8.3g    y: %8.3g" % (event.xdata, event.ydata)
147            wx.PostEvent(self.parent, StatusEvent(status=position))
148
149    def _onRemove(self, event):
150        """
151        """
152        if not self.graph.selected_plottable == None:
153            print self.graph.selected_plottable
154           
155           
156            self.graph.delete(self.plots[self.graph.selected_plottable])
157            del self.plots[self.graph.selected_plottable]
158            self.graph.render(self)
159            self.subplot.figure.canvas.draw_idle()   
160           
161
162    def onContextMenu(self, event):
163        """
164            1D plot context menu
165            @param event: wx context event
166        """
167        #slicerpop = wx.Menu()
168        slicerpop = PanelMenu()
169        slicerpop.set_plots(self.plots)
170        slicerpop.set_graph(self.graph)
171               
172        # Option to save the data displayed
173       
174        #for plot in self.graph.plottables:
175        if self.graph.selected_plottable in self.plots:
176            plot = self.plots[self.graph.selected_plottable]
177            id = wx.NewId()
178            name = plot.name
179            slicerpop.Append(id, "&Save %s points" % name)
180            self.action_ids[str(id)] = plot
181            wx.EVT_MENU(self, id, self._onSave)
182               
183            # Option to delete plottable
184            id = wx.NewId()
185            slicerpop.Append(id, "Remove %s curve" % name)
186            self.action_ids[str(id)] = plot
187            wx.EVT_MENU(self, id, self._onRemove)
188           
189            # Option to hide
190            #TODO: implement functionality to hide a plottable (legend click)
191            slicerpop.AppendSeparator()
192               
193        # Various plot options
194        id = wx.NewId()
195        slicerpop.Append(id,'&Save image', 'Save image as PNG')
196        wx.EVT_MENU(self, id, self.onSaveImage)
197       
198       
199        item_list = self.parent.get_context_menu(self.graph)
200        if (not item_list==None) and (not len(item_list)==0):
201                slicerpop.AppendSeparator()
202                for item in item_list:
203                    try:
204                        id = wx.NewId()
205                        slicerpop.Append(id, item[0], item[1])
206                        wx.EVT_MENU(self, id, item[2])
207                    except:
208                        print sys.exc_value
209                        print RuntimeError, "View1DPanel.onContextMenu: bad menu item"
210       
211        slicerpop.AppendSeparator()
212       
213        if self.graph.selected_plottable in self.plots:
214            if self.plots[self.graph.selected_plottable].__class__.__name__=="Theory1D":
215                id = wx.NewId()
216                slicerpop.Append(id, '&Add errors to data')
217                wx.EVT_MENU(self, id, self._on_add_errors)
218            else:
219                id = wx.NewId()
220                slicerpop.Append(id, '&Linear fit')
221                wx.EVT_MENU(self, id, self.onFitting)
222               
223       
224
225        id = wx.NewId()
226        slicerpop.Append(id, '&Change scale')
227        wx.EVT_MENU(self, id, self._onProperties)
228       
229        id = wx.NewId()
230        #slicerpop.AppendSeparator()
231        slicerpop.Append(id, '&Reset Graph')
232        wx.EVT_MENU(self, id, self.onResetGraph)       
233
234        pos = event.GetPosition()
235        pos = self.ScreenToClient(pos)
236        self.PopupMenu(slicerpop, pos)
237   
238   
239    def _on_add_errors(self, evt):
240        """
241            Compute reasonable errors for a data set without
242            errors and transorm the plottable to a Data1D
243        """
244        import math
245        import numpy
246        import time
247       
248        if not self.graph.selected_plottable == None:
249            length = len(self.plots[self.graph.selected_plottable].x)
250            dy = numpy.zeros(length)
251            for i in range(length):
252                dy[i] = math.sqrt(self.plots[self.graph.selected_plottable].y[i])
253               
254            new_plot = Data1D(self.plots[self.graph.selected_plottable].x,
255                              self.plots[self.graph.selected_plottable].y,
256                              dy=dy)
257            new_plot.interactive = True
258            new_plot.name = self.plots[self.graph.selected_plottable].name
259            if hasattr(self.plots[self.graph.selected_plottable], "group_id"):
260                new_plot.group_id = self.plots[self.graph.selected_plottable].group_id
261            else:
262                new_plot.group_id = str(time.time())
263           
264            label, unit = self.plots[self.graph.selected_plottable].get_xaxis()
265            new_plot.xaxis(label, unit)
266            label, unit = self.plots[self.graph.selected_plottable].get_yaxis()
267            new_plot.yaxis(label, unit)
268           
269            self.graph.delete(self.plots[self.graph.selected_plottable])
270           
271            self.graph.add(new_plot)
272            self.plots[self.graph.selected_plottable]=new_plot
273           
274            self.graph.render(self)
275            self.subplot.figure.canvas.draw_idle()   
276   
277    def _onSave(self, evt):
278        """
279            Save a data set to a text file
280            @param evt: Menu event
281        """
282        import os
283        id = str(evt.GetId())
284        if id in self.action_ids:         
285           
286            path = None
287            dlg = wx.FileDialog(self, "Choose a file", os.getcwd(), "", "*.txt", wx.SAVE)
288            if dlg.ShowModal() == wx.ID_OK:
289                path = dlg.GetPath()
290                mypath = os.path.basename(path)
291                print path
292            dlg.Destroy()
293           
294            if not path == None:
295                out = open(path, 'w')
296                has_errors = True
297                if self.action_ids[id].dy==None or self.action_ids[id].dy==[]:
298                    has_errors = False
299                   
300                # Sanity check
301                if has_errors:
302                    try:
303                        if len(self.action_ids[id].y) != len(self.action_ids[id].dy):
304                            print "Y and dY have different lengths"
305                            has_errors = False
306                    except:
307                        has_errors = False
308               
309                if has_errors:
310                    out.write("<X>   <Y>   <dY>\n")
311                else:
312                    out.write("<X>   <Y>\n")
313                   
314                for i in range(len(self.action_ids[id].x)):
315                    if has_errors:
316                        out.write("%g  %g  %g\n" % (self.action_ids[id].x[i], 
317                                                    self.action_ids[id].y[i],
318                                                    self.action_ids[id].dy[i]))
319                    else:
320                        out.write("%g  %g\n" % (self.action_ids[id].x[i], 
321                                                self.action_ids[id].y[i]))
322                       
323                out.close()
324   
325   
326    def _onToggleScale(self, event):
327        if self.get_yscale() == 'log':
328            self.set_yscale('linear')
329        else:
330            self.set_yscale('log')
331        self.subplot.figure.canvas.draw_idle()   
332       
333class View1DPanel2D( View1DPanel1D):
334    """
335        Plot panel for use with the GUI manager
336    """
337   
338    ## Internal name for the AUI manager
339    window_name = "plotpanel"
340    ## Title to appear on top of the window
341    window_caption = "Plot Panel"
342    ## Flag to tell the GUI manager that this panel is not
343    #  tied to any perspective
344    ALWAYS_ON = True
345    ## Group ID
346    group_id = None
347   
348    def __init__(self, parent, id = -1,data2d=None, color = None,\
349        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
350        """
351            Initialize the panel
352        """
353        View1DPanel1D.__init__(self, parent, id = id, style = style, **kwargs)
354       
355        ## Reference to the parent window
356        self.parent = parent
357        ## Plottables
358        self.plots = {}
359        self.data2D= data2d
360        self.data = data2d.data
361        ## Unique ID (from gui_manager)
362        self.uid = None
363       
364        ## Action IDs for internal call-backs
365        self.action_ids = {}
366        self.connect = BindArtist(self.subplot.figure)
367       
368        # Beam stop
369        self.beamstop_radius = DEFAULT_BEAM
370        # Slicer
371       
372        self.qmax = data2d.xmax
373        self.imax= data2d.ymax
374        self.qstep = DEFAULT_QSTEP
375        self.x = pylab.arange(-self.qmax, self.qmax+self.qstep*0.01, self.qstep)
376        self.y = pylab.arange(-self.imax, self.imax+self.qstep*0.01, self.qstep)
377
378        self.slicer_z = 5
379        self.slicer = None
380        self.parent.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
381        self.axes_frozen = False
382        ## Graph       
383        self.graph = Graph()
384        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
385        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
386        self.graph.render(self)
387 
388    def _onEVT_1DREPLOT(self, event):
389        """
390            Data is ready to be displayed
391            @param event: data event
392        """
393        #TODO: Check for existence of plot attribute
394        # Check whether this is a replot. If we ask for a replot
395        # and the plottable no longer exists, ignore the event.
396        if hasattr(event, "update") and event.update==True \
397            and event.plot.name not in self.plots.keys():
398            return
399        if hasattr(event, "reset"):
400            self._reset()
401        is_new = True
402        if event.plot.name in self.plots.keys():
403            # Check whether the class of plottable changed
404            if not event.plot.__class__==self.plots[event.plot.name].__class__:
405                self.graph.delete(self.plots[event.plot.name])
406            else:
407                is_new = False
408        self.plots[event.plot.name] = event.plot
409        #if is_new:
410        self.graph.add(self.plots[event.plot.name])
411       
412
413        # Check axis labels
414        #TODO: Should re-factor this
415        #if event.plot._xunit != self.graph.prop["xunit"]:
416       
417        self.graph.xaxis(event.plot._xaxis, event.plot._xunit)
418        #if event.plot._yunit != self.graph.prop["yunit"]:
419        self.graph.yaxis(event.plot._yaxis, event.plot._yunit)
420        self.graph.render(self)
421        self.subplot.figure.canvas.draw_idle()
422
423
424    def onContextMenu(self, event):
425        """
426            2D plot context menu
427            @param event: wx context event
428        """
429       
430        #slicerpop = wx.Menu()
431        slicerpop = PanelMenu()
432        slicerpop.set_plots(self.plots)
433        slicerpop.set_graph(self.graph)
434               
435        # Option to save the data displayed
436   
437        # Various plot options
438        id = wx.NewId()
439        slicerpop.Append(id,'&Save image', 'Save image as PNG')
440        wx.EVT_MENU(self, id, self.onSaveImage)
441       
442       
443        item_list = self.parent.get_context_menu(self.graph)
444        if (not item_list==None) and (not len(item_list)==0):
445                slicerpop.AppendSeparator()
446                for item in item_list:
447                    try:
448                        id = wx.NewId()
449                        slicerpop.Append(id, item[0], item[1])
450                        wx.EVT_MENU(self, id, item[2])
451                    except:
452                        print sys.exc_value
453                        print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
454       
455        slicerpop.AppendSeparator()
456       
457        id = wx.NewId()
458        slicerpop.Append(id, '&Perform circular average')
459        wx.EVT_MENU(self, id, self.onCircular) 
460       
461        id = wx.NewId()
462        slicerpop.Append(id, '&Sector Q')
463        wx.EVT_MENU(self, id, self.onSectorQ) 
464       
465        id = wx.NewId()
466        slicerpop.Append(id, '&Sector Phi')
467        wx.EVT_MENU(self, id, self.onSectorPhi) 
468     
469       
470        id = wx.NewId()
471        slicerpop.Append(id, '&Clear slicer')
472        wx.EVT_MENU(self, id,  self.onClearSlicer) 
473       
474        id = wx.NewId()
475        slicerpop.Append(id, '&Edit Parameters')
476        wx.EVT_MENU(self, id, self._onEditDetector) 
477       
478        slicerpop.AppendSeparator()
479       
480        id = wx.NewId()
481        slicerpop.Append(id, '&Save image')
482        wx.EVT_MENU(self, id, self.onSaveImage) 
483     
484        id = wx.NewId()
485        slicerpop.Append(id, '&Toggle Linear/Log scale')
486        wx.EVT_MENU(self, id, self._onToggleScale) 
487         
488        pos = event.GetPosition()
489        pos = self.ScreenToClient(pos)
490        self.PopupMenu(slicerpop, pos)
491   
492    def _setSlicer(self, slicer):
493        # Clear current slicer
494        #printEVT("Plotter2D._setSlicer %s" % slicer)
495       
496        if not self.slicer == None: 
497            self.slicer.clear()           
498           
499        self.slicer_z += 1
500        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
501        self.subplot.set_ylim(-self.qmax, self.qmax)
502        self.subplot.set_xlim(-self.qmax, self.qmax)
503        self.update()
504        self.slicer.update()
505       
506       
507    def get_corrected_data(self):
508        # Protect against empty data set
509        if self.data == None:
510            return None
511        import copy
512        output = copy.deepcopy(self.data)
513        return output
514    def freeze_axes(self):
515        self.axes_frozen = True
516       
517    def thaw_axes(self):
518        self.axes_frozen = False
519       
520    def onMouseMotion(self,event):
521        pass
522    def onWheel(self, event):
523        pass   
524    def update(self, draw=True):
525        """
526            Respond to changes in the model by recalculating the
527            profiles and resetting the widgets.
528        """
529        #self.slicer.update()
530        self.draw()
531       
532       
533    def _getEmptySlicerEvent(self):
534        return SlicerEvent(type=None,
535                           params=None,
536                           obj_class=None)
537    def _onEVT_INTERNAL(self, event):
538        """
539            I don't understand why Unbind followed by a Bind
540            using a modified self.slicer doesn't work.
541            For now, I post a clear event followed by
542            a new slicer event...
543        """
544        self._setSlicer(event.slicer)
545           
546    def _setSlicer(self, slicer):
547        # Clear current slicer
548        #printEVT("Plotter2D._setSlicer %s" % slicer)
549       
550        if not self.slicer == None: 
551            self.slicer.clear()           
552           
553        self.slicer_z += 1
554        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
555        self.subplot.set_ylim(-self.qmax, self.qmax)
556        self.subplot.set_xlim(-self.qmax, self.qmax)
557        self.update()
558        self.slicer.update()
559       
560        # Post slicer event
561        event = self._getEmptySlicerEvent()
562        event.type = self.slicer.__class__.__name__
563        event.obj_class = self.slicer.__class__
564        event.params = self.slicer.get_params()
565        wx.PostEvent(self.parent, event)
566
567    def onCircular(self, event):
568        """
569            perform circular averaging on Data2D
570        """
571       
572        from DataLoader.manipulations import CircularAverage
573        Circle = CircularAverage( r_min= -self.qmax, r_max= self.qmax, bin_width=0.001)
574        circ = Circle(self.data2D)
575        from sans.guiframe.dataFitting import Data1D
576        if hasattr(circ,"dxl"):
577            dxl= circ.dxl
578        else:
579            dxl= None
580        if hasattr(circ,"dxw"):
581            dxw= circ.dxw
582        else:
583            dxw= None
584           
585        new_plot = Data1D(x=circ.x,y=circ.y,dy=circ.dy,dxl=dxl,dxw=dxw)
586        new_plot.name = "Circ avg "+ self.data2D.name
587        new_plot.source=self.data2D.source
588        new_plot.info=self.data2D.info
589        new_plot.interactive = True
590        #print "loader output.detector",output.source
591        new_plot.detector =self.data2D.detector
592       
593        # If the data file does not tell us what the axes are, just assume...
594        new_plot.xaxis("\\rm{q}","A^{-1}")
595        new_plot.yaxis("\\rm{Intensity} ","cm^{-1}")
596        new_plot.group_id = "Circ avg "+ self.data2D.name
597        self.scale = 'log'
598        wx.PostEvent(self.parent, NewPlotEvent(plot=new_plot, title=new_plot.name))
599       
600       
601       
602    def onSectorQ(self, event):
603        """
604            Perform sector averaging on Q
605        """
606        from SectorSlicer import SectorInteractorQ
607             
608        self.slicer_z += 1
609        self.slicer = SectorInteractorQ(self, self.subplot, zorder=self.slicer_z)
610        self.subplot.set_ylim(-self.qmax, self.qmax)
611        self.subplot.set_xlim(-self.qmax, self.qmax)
612        self.update()
613        self.slicer.update()
614       
615       
616    def onSectorPhi(self, event):
617        """
618            Perform sector averaging on Phi
619        """
620        from SectorSlicer import SectorInteractor
621             
622        self.slicer_z += 1
623        self.slicer = SectorInteractor(self, self.subplot, zorder=self.slicer_z)
624        self.subplot.set_ylim(-self.qmax, self.qmax)
625        self.subplot.set_xlim(-self.qmax, self.qmax)
626        self.update()
627        self.slicer.update()
628       
629       
630    def onClearSlicer(self, event):
631        """
632            Clear the slicer on the plot
633        """
634        if not self.slicer==None:
635            self.slicer.clear()
636            self.subplot.figure.canvas.draw()
637            self.slicer = None
638       
639            # Post slicer None event
640            event = self._getEmptySlicerEvent()
641            wx.PostEvent(self.parent, event)
642         
643    def _onEditDetector(self, event):
644        print "on parameter"
645       
646       
647    def _onToggleScale(self, event):
648        """
649            toggle pixel scale and replot image
650        """
651        if self.scale == 'log':
652            self.scale = 'linear'
653        else:
654            self.scale = 'log'
655        self.image(self.data,self.xmin_2D,self.xmax_2D,self.ymin_2D,
656                   self.ymax_2D,self.zmin_2D ,self.zmax_2D )
657        wx.PostEvent(self.parent, StatusEvent(status="Image is in %s scale"%self.scale))
658       
659       
660       
661       
662       
663       
664class View1DModelPanel2D( View1DPanel2D):
665    """
666        Plot panel for use with the GUI manager
667    """
668   
669    ## Internal name for the AUI manager
670    window_name = "plotpanel"
671    ## Title to appear on top of the window
672    window_caption = "Plot Panel"
673    ## Flag to tell the GUI manager that this panel is not
674    #  tied to any perspective
675    ALWAYS_ON = True
676    ## Group ID
677    group_id = None
678   
679    def __init__(self, parent, id = -1,color = None,\
680        dpi = None, style = wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
681        """
682            Initialize the panel
683        """
684        View1DPanel2D.__init__(self, parent, id = id, style = style, **kwargs)
685        ## Reference to the parent window
686        self.parent = parent
687        ## Plottables
688        self.plots = {}
689        print "Model 2d panel"
690       
691        ## Unique ID (from gui_manager)
692        self.uid = None
693       
694        ## Action IDs for internal call-backs
695        self.action_ids = {}
696       
697        ## Graph       
698        self.graph = Graph()
699        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
700        self.graph.yaxis("\\rm{Intensity} ","cm^{-1}")
701        self.graph.render(self)
702    def onContextMenu(self, event):
703        # Slicer plot popup menu
704         #slicerpop = wx.Menu()
705        slicerpop = PanelMenu()
706        slicerpop.set_plots(self.plots)
707        slicerpop.set_graph(self.graph)
708               
709        # Option to save the data displayed
710   
711        # Various plot options
712        id = wx.NewId()
713        slicerpop.Append(id,'&Save image', 'Save image as PNG')
714        wx.EVT_MENU(self, id, self.onSaveImage)
715       
716       
717        item_list = self.parent.get_context_menu(self.graph)
718        if (not item_list==None) and (not len(item_list)==0):
719                slicerpop.AppendSeparator()
720                for item in item_list:
721                    try:
722                        id = wx.NewId()
723                        slicerpop.Append(id, item[0], item[1])
724                        wx.EVT_MENU(self, id, item[2])
725                    except:
726                        print sys.exc_value
727                        print RuntimeError, "View1DPanel2D.onContextMenu: bad menu item"
728       
729        slicerpop.AppendSeparator()
730     
731        id = wx.NewId()
732        slicerpop.Append(id, '&sector averaging')
733        wx.EVT_MENU(self, id, self.onSectorSlicer) 
734       
735   
736       
737        pos = event.GetPosition()
738        pos = self.ScreenToClient(pos)
739        self.PopupMenu(slicerpop, pos)
740   
741
742       
743       
Note: See TracBrowser for help on using the repository browser.