source: sasview/guiframe/local_perspectives/plotting/Plotter2D.py @ 626a1f9

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 626a1f9 was 626a1f9, checked in by Jae Cho <jhjcho@…>, 13 years ago

temp commit for mac event 2D click

  • Property mode set to 100644
File size: 23.0 KB
RevLine 
[1bf33c1]1
[d955bf19]2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2008, University of Tennessee
10################################################################################
[1bf33c1]11
12
13import wx
[32c0841]14import sys
[ed8ad21]15import os
[32c0841]16import math
[003fa4e]17import numpy
[0d9dae8]18import pylab
[1bf33c1]19import danse.common.plottools
20from danse.common.plottools.PlotPanel import PlotPanel
[4ac8556]21from danse.common.plottools.plottables import Graph
[55a0dc1]22from sans.guiframe.events import EVT_NEW_PLOT
23from sans.guiframe.events import EVT_SLICER_PARS
24from sans.guiframe.events import StatusEvent
25from sans.guiframe.events import NewPlotEvent
[a07e72f]26from sans.guiframe.events import PanelOnFocusEvent
[55a0dc1]27from sans.guiframe.events import SlicerEvent
[0d9dae8]28from sans.guiframe.utils import PanelMenu
[1bf33c1]29from binder import BindArtist
30from Plotter1D import ModelPanel1D
[32c0841]31from danse.common.plottools.toolbar import NavigationToolBar
[4ac8556]32from sans.guiframe.dataFitting import Data1D
[32c0841]33(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
[0d9dae8]34
35DEFAULT_QMAX = 0.05
[1bf33c1]36DEFAULT_QSTEP = 0.001
37DEFAULT_BEAM = 0.005
[ef0c170]38BIN_WIDTH = 1.0
[32c0841]39
[d955bf19]40
[ac8671e]41class NavigationToolBar2D(NavigationToolBar):
[d955bf19]42    """
43    """
[ac8671e]44    def __init__(self, canvas, parent=None):
45        NavigationToolBar.__init__(self, canvas=canvas, parent=parent)
46       
47    def delete_option(self):
48        """
[d955bf19]49        remove default toolbar item
[ac8671e]50        """
51        #delete reset button
52        self.DeleteToolByPos(0) 
53        #delete dragging
[88ca6db]54        self.DeleteToolByPos(2) 
[ac8671e]55        #delete unwanted button that configures subplot parameters
56        self.DeleteToolByPos(4)
57       
58    def add_option(self):
59        """
[d955bf19]60        add item to the toolbar
[ac8671e]61        """
62        #add print button
63        id_print = wx.NewId()
64        print_bmp =  wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR)
65        self.AddSimpleTool(id_print, print_bmp,
66                           'Print', 'Activate printing')
67        wx.EVT_TOOL(self, id_print, self.on_print)
68       
69       
70class ModelPanel2D(ModelPanel1D):
[1bf33c1]71    """
[d955bf19]72    Plot panel for use with the GUI manager
[1bf33c1]73    """
74   
75    ## Internal name for the AUI manager
76    window_name = "plotpanel"
77    ## Title to appear on top of the window
78    window_caption = "Plot Panel"
79    ## Flag to tell the GUI manager that this panel is not
80    #  tied to any perspective
81    ALWAYS_ON = True
82    ## Group ID
83    group_id = None
84   
85   
[32c0841]86    def __init__(self, parent, id=-1, data2d=None, color = None,
87                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
[1bf33c1]88        """
[d955bf19]89        Initialize the panel
[1bf33c1]90        """
[32c0841]91        ModelPanel1D.__init__(self, parent, id=id, style=style, **kwargs)
[1bf33c1]92       
93        ## Reference to the parent window
94        self.parent = parent
[6c0568b]95        ## Dictionary containing Plottables
[1bf33c1]96        self.plots = {}
[6c0568b]97        ## Save reference of the current plotted
98        self.data2D = data2d
[1bf33c1]99        ## Unique ID (from gui_manager)
100        self.uid = None
101        ## Action IDs for internal call-backs
102        self.action_ids = {}
[6c0568b]103        ## Create Artist and bind it
[1bf33c1]104        self.connect = BindArtist(self.subplot.figure)
[6c0568b]105        ## Beam stop
[1bf33c1]106        self.beamstop_radius = DEFAULT_BEAM
[6c0568b]107        ## to set the order of lines drawn first.
[f15ed33]108        self.slicer_z = 5
[6c0568b]109        ## Reference to the current slicer
[1bf33c1]110        self.slicer = None
[6c0568b]111        ## event to send slicer info
[d468daa]112        self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
[1bf33c1]113       
[6c0568b]114        self.axes_frozen = False
115        ## panel that contains result from slicer motion (ex: Boxsum info)
[32c0841]116        self.panel_slicer = None
[1bf33c1]117        ## Graph       
118        self.graph = Graph()
119        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
[32c0841]120        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
[1bf33c1]121        self.graph.render(self)
[8dfdd20]122        ## store default value of zmin and zmax
123        self.default_zmin_ctl = self.zmin_2D
124        self.default_zmax_ctl = self.zmax_2D
[ac8671e]125       
[a07e72f]126    def onLeftDown(self, event): 
127        """
128        left button down and ready to drag
129       
130        """
131        # Check that the LEFT button was pressed
132        if event.button == 1:
133            self.leftdown = True
134            ax = event.inaxes
135            if ax != None:
136                self.xInit, self.yInit = event.xdata, event.ydata
[626a1f9]137        print "self.data2D.id=", self.data2D.id, "button=", event.button
[a07e72f]138        self.plottable_selected(self.data2D.id)
139       
140        self._manager.set_panel_on_focus(self)
141        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
142       
[ac8671e]143    def add_toolbar(self):
144        """
[d955bf19]145        add toolbar
[ac8671e]146        """
147        self.enable_toolbar = True
[32c0841]148        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
[ac8671e]149        self.toolbar.Realize()
150        # On Windows platform, default window size is incorrect, so set
151        # toolbar width to figure width.
152        tw, th = self.toolbar.GetSizeTuple()
153        fw, fh = self.canvas.GetSizeTuple()
154        self.toolbar.SetSize(wx.Size(fw, th))
[32c0841]155        self.sizer.Add(self.toolbar, 0, wx.LEFT|wx.EXPAND)
[ac8671e]156        # update the axes menu on the toolbar
157        self.toolbar.update()
158         
[a07e72f]159    def plot_data(self, data):
[1bf33c1]160        """
[d955bf19]161        Data is ready to be displayed
162       
163        :TODO: this name should be changed to something more appropriate
164             Don't forget that changing this name will mean changing code
165             in plotting.py
166         
167        :param event: data event
[1bf33c1]168        """
[6c0568b]169        ## Update self.data2d with the current plot
[a07e72f]170        self.data2D = data
171        if data.id in self.plots.keys():
172            #replace
173            self.graph.replace(data)
174            self.plots[data.id] = data
[ab8f936]175        else:
[a07e72f]176            self.plots[data.id] = data
177            self.graph.add(self.plots[data.id]) 
[ac9a5f6]178            # update qmax with the new xmax of data plotted
[a07e72f]179            self.qmax = data.xmax
[4b91fd1]180           
[32c0841]181        self.slicer = None
[1bf33c1]182        # Check axis labels
183        #TODO: Should re-factor this
[6c0568b]184        ## render the graph with its new content
[7fff5cd]185               
186        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
187        if len(self.data2D.detector) < 1: 
[a07e72f]188            if len(data._xunit) < 1 and len(data._yunit) < 1:
189                data._xaxis = '\\rm{x}'
190                data._yaxis = '\\rm{y}'
191                data._xunit = 'pixel'
192                data._yunit = 'pixel'
193        self.graph.xaxis(data._xaxis, data._xunit)
194        self.graph.yaxis(data._yaxis, data._yunit)
[0690e1d]195        self.graph.title(self.data2D.name)
[1bf33c1]196        self.graph.render(self)
[6d727ae]197        self.draw_plot()
198        #self.subplot.figure.canvas.draw_idle()
[8dfdd20]199        ## store default value of zmin and zmax
200        self.default_zmin_ctl = self.zmin_2D
201        self.default_zmax_ctl = self.zmax_2D
[1bf33c1]202
203    def onContextMenu(self, event):
204        """
[d955bf19]205        2D plot context menu
206       
207        :param event: wx context event
[15550f4]208       
[d955bf19]209        """
[1bf33c1]210        slicerpop = PanelMenu()
211        slicerpop.set_plots(self.plots)
212        slicerpop.set_graph(self.graph)
[9a585d0]213             
214        id = wx.NewId()
[6d727ae]215        slicerpop.Append(id, '&Save Image')
[9a585d0]216        wx.EVT_MENU(self, id, self.onSaveImage)
217       
218        id = wx.NewId()
[6d727ae]219        slicerpop.Append(id,'&Print Image', 'Print image')
[9a585d0]220        wx.EVT_MENU(self, id, self.onPrint)
221       
[1ce365f8]222        id = wx.NewId()
[6d727ae]223        slicerpop.Append(id,'&Print Preview', 'Print preview')
[1ce365f8]224        wx.EVT_MENU(self, id, self.onPrinterPreview)
[003fa4e]225
226        id = wx.NewId()
227        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
228        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
[c5a769e]229        slicerpop.AppendSeparator()
[ed8ad21]230        # saving data
231        plot = self.data2D
232        id = wx.NewId()
233        name = plot.name
234        slicerpop.Append(id, "&Save as a file (DAT)" )
235        self.action_ids[str(id)] = plot
236        wx.EVT_MENU(self, id, self._onSave)
237
[9a585d0]238        slicerpop.AppendSeparator()
[7fff5cd]239        if len(self.data2D.detector) == 1:       
[0e13148]240           
[a07e72f]241            item_list = self.parent.get_context_menu(self)
[6d727ae]242            if (not item_list == None) and (not len(item_list) == 0) and\
243                self.data2D.name.split(" ")[0] != 'Residuals': 
244                # The line above; Not for trunk
[32c0841]245                for item in item_list:
246                    try:
247                        id = wx.NewId()
248                        slicerpop.Append(id, item[0], item[1])
249                        wx.EVT_MENU(self, id, item[2])
250                    except:
251                        msg = "ModelPanel1D.onContextMenu: "
252                        msg += "bad menu item  %s"%sys.exc_value
253                        wx.PostEvent(self.parent, StatusEvent(status=msg))
254                        pass
255                slicerpop.AppendSeparator()
[0e13148]256           
[15550f4]257            id = wx.NewId()
258            slicerpop.Append(id, '&Perform circular average')
[6d727ae]259            wx.EVT_MENU(self, id, self.onCircular) \
260            # For Masked Data
261            if not plot.mask.all():
262                id = wx.NewId()
263                slicerpop.Append(id, '&Masked circular average')
264                wx.EVT_MENU(self, id, self.onMaskedCircular) 
[15550f4]265            id = wx.NewId()
266            slicerpop.Append(id, '&Sector [Q view]')
267            wx.EVT_MENU(self, id, self.onSectorQ) 
268            id = wx.NewId()
269            slicerpop.Append(id, '&Annulus [Phi view ]')
270            wx.EVT_MENU(self, id, self.onSectorPhi) 
[92c2345]271            id = wx.NewId()
[15550f4]272            slicerpop.Append(id, '&Box Sum')
273            wx.EVT_MENU(self, id, self.onBoxSum) 
274            id = wx.NewId()
275            slicerpop.Append(id, '&Box averaging in Qx')
276            wx.EVT_MENU(self, id, self.onBoxavgX) 
277            id = wx.NewId()
278            slicerpop.Append(id, '&Box averaging in Qy')
279            wx.EVT_MENU(self, id, self.onBoxavgY) 
[32c0841]280            if self.slicer != None:
[eba08f1a]281                id = wx.NewId()
[15550f4]282                slicerpop.Append(id, '&Clear slicer')
283                wx.EVT_MENU(self, id,  self.onClearSlicer) 
[32c0841]284                if self.slicer.__class__.__name__  != "BoxSum":
[15550f4]285                    id = wx.NewId()
286                    slicerpop.Append(id, '&Edit Slicer Parameters')
287                    wx.EVT_MENU(self, id, self._onEditSlicer) 
288            slicerpop.AppendSeparator() 
[0e13148]289        id = wx.NewId()
[52f3c98]290        slicerpop.Append(id, '&2D Color Map')
[32c0841]291        wx.EVT_MENU(self, id, self._onEditDetector)
[1bf33c1]292        id = wx.NewId()
293        slicerpop.Append(id, '&Toggle Linear/Log scale')
294        wx.EVT_MENU(self, id, self._onToggleScale) 
295        pos = event.GetPosition()
296        pos = self.ScreenToClient(pos)
297        self.PopupMenu(slicerpop, pos)
[8bd764d]298   
[ea290ee]299    def _onEditDetector(self, event):
[6d920cd]300        """
[d955bf19]301        Allow to view and edits  detector parameters
302       
303        :param event: wx.menu event
304       
[6d920cd]305        """
[ea290ee]306        import detector_dialog
[8dfdd20]307        dialog = detector_dialog.DetectorDialog(self, -1,base=self.parent,
308                       reset_zmin_ctl =self.default_zmin_ctl,
309                       reset_zmax_ctl = self.default_zmax_ctl,cmap=self.cmap)
[6c0568b]310        ## info of current detector and data2D
[ea290ee]311        xnpts = len(self.data2D.x_bins)
312        ynpts = len(self.data2D.y_bins)
313        xmax = max(self.data2D.xmin, self.data2D.xmax)
314        ymax = max(self.data2D.ymin, self.data2D.ymax)
[32c0841]315        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
[ea290ee]316        beam = self.data2D.xmin
[6c0568b]317        ## set dialog window content
[ea290ee]318        dialog.setContent(xnpts=xnpts,ynpts=ynpts,qmax=qmax,
319                           beam=self.data2D.xmin,
320                           zmin = self.zmin_2D,
321                          zmax = self.zmax_2D)
322        if dialog.ShowModal() == wx.ID_OK:
323            evt = dialog.getContent()
324            self.zmin_2D = evt.zmin
325            self.zmax_2D = evt.zmax
[32c0841]326            self.cmap = evt.cmap
[ea290ee]327        dialog.Destroy()
[6c0568b]328        ## Redraw the current image
[32c0841]329        self.image(data=self.data2D.data,
[20b6760]330                   qx_data=self.data2D.qx_data,
331                   qy_data=self.data2D.qy_data,
[ea290ee]332                   xmin= self.data2D.xmin,
333                   xmax= self.data2D.xmax,
334                   ymin= self.data2D.ymin,
335                   ymax= self.data2D.ymax,
336                   zmin= self.zmin_2D,
337                   zmax= self.zmax_2D,
[8dfdd20]338                   cmap= self.cmap,
[32c0841]339                   color=0, symbol=0, label=self.data2D.name)
[ea290ee]340        self.subplot.figure.canvas.draw_idle()
[1bf33c1]341       
342    def freeze_axes(self):
[d955bf19]343        """
344        """
[1bf33c1]345        self.axes_frozen = True
346       
347    def thaw_axes(self):
[d955bf19]348        """
349        """
[1bf33c1]350        self.axes_frozen = False
351       
352    def onMouseMotion(self,event):
[d955bf19]353        """
354        """
[1bf33c1]355        pass
[d955bf19]356   
[1bf33c1]357    def onWheel(self, event):
[d955bf19]358        """
359        """
[6c0568b]360        pass 
361     
[1bf33c1]362    def update(self, draw=True):
363        """
[d955bf19]364        Respond to changes in the model by recalculating the
365        profiles and resetting the widgets.
[1bf33c1]366        """
[6d727ae]367        self.draw_plot()
[1bf33c1]368       
369    def _getEmptySlicerEvent(self):
[6c0568b]370        """
[d955bf19]371        create an empty slicervent
[6c0568b]372        """
[32c0841]373        return SlicerEvent(type=None, params=None, obj_class=None)
[d955bf19]374       
[1bf33c1]375    def _onEVT_INTERNAL(self, event):
376        """
[d955bf19]377        Draw the slicer
378       
379        :param event: wx.lib.newevent (SlicerEvent) containing slicer
[6c0568b]380            parameter
[d955bf19]381           
[1bf33c1]382        """
383        self._setSlicer(event.slicer)
384           
385    def _setSlicer(self, slicer):
[6c0568b]386        """
[d955bf19]387        Clear the previous slicer and create a new one.Post an internal
388        event.
389       
390        :param slicer: slicer class to create
391       
[6c0568b]392        """
393        ## Clear current slicer
[1bf33c1]394        if not self.slicer == None: 
395            self.slicer.clear()           
[6c0568b]396        ## Create a new slicer   
[1bf33c1]397        self.slicer_z += 1
398        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
[240c805]399        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
400        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
[6c0568b]401        ## Draw slicer
[1bf33c1]402        self.update()
403        self.slicer.update()
[32c0841]404        msg = "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__
405        wx.PostEvent(self.parent, StatusEvent(status=msg))
[1bf33c1]406        # Post slicer event
407        event = self._getEmptySlicerEvent()
408        event.type = self.slicer.__class__.__name__
409        event.obj_class = self.slicer.__class__
410        event.params = self.slicer.get_params()
[d468daa]411        wx.PostEvent(self, event)
[6d727ae]412       
413    def onMaskedCircular(self, event):
414        """
415        perform circular averaging on Data2D with mask if it exists
416       
417        :param event: wx.menu event
418       
419        """
420        self.onCircular(event, True)
421       
422    def onCircular(self, event, ismask=False):
[1bf33c1]423        """
[d955bf19]424        perform circular averaging on Data2D
425       
426        :param event: wx.menu event
427       
[1bf33c1]428        """
[003fa4e]429        # Find the best number of bins
430        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
431        npt = math.floor(npt)
[1bf33c1]432        from DataLoader.manipulations import CircularAverage
[6c0568b]433        ## compute the maximum radius of data2D
[32c0841]434        self.qmax = max(math.fabs(self.data2D.xmax), 
435                        math.fabs(self.data2D.xmin))
436        self.ymax = max(math.fabs(self.data2D.ymax),
437                        math.fabs(self.data2D.ymin))
438        self.radius = math.sqrt(math.pow(self.qmax, 2)+ math.pow(self.ymax, 2)) 
[6c0568b]439        ##Compute beam width
[003fa4e]440        bin_width = (self.qmax + self.qmax)/npt
[6c0568b]441        ## Create data1D circular average of data2D
[32c0841]442        Circle = CircularAverage(r_min=0, r_max=self.radius, 
443                                 bin_width=bin_width)
[6d727ae]444        circ = Circle(self.data2D, ismask=ismask)
[1bf33c1]445        from sans.guiframe.dataFitting import Data1D
[32c0841]446        if hasattr(circ, "dxl"):
447            dxl = circ.dxl
[1bf33c1]448        else:
[32c0841]449            dxl = None
450        if hasattr(circ, "dxw"):
451            dxw = circ.dxw
[1bf33c1]452        else:
[32c0841]453            dxw = None
[003fa4e]454
455        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
[32c0841]456        new_plot.dxl = dxl
457        new_plot.dxw = dxw
458        new_plot.name = "Circ avg " + self.data2D.name
459        new_plot.source = self.data2D.source
460        #new_plot.info = self.data2D.info
[1bf33c1]461        new_plot.interactive = True
[32c0841]462        new_plot.detector = self.data2D.detector
[6d727ae]463       
[6c0568b]464        ## If the data file does not tell us what the axes are, just assume...
[32c0841]465        new_plot.xaxis("\\rm{Q}", "A^{-1}")
[2ca51f44]466        if hasattr(self.data2D, "scale") and \
467                    self.data2D.scale == 'linear':
468            new_plot.ytransform = 'y'
469            new_plot.yaxis("\\rm{Residuals} ", "normalized")
[6d727ae]470        else:
471            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
472
[32c0841]473        new_plot.group_id = "Circ avg " + self.data2D.name
474        new_plot.id = "Circ avg " + self.data2D.name
475        new_plot.is_data = True
476        wx.PostEvent(self.parent, 
477                     NewPlotEvent(plot=new_plot, title=new_plot.name))
[ef0c170]478       
[1bf33c1]479    def _onEditSlicer(self, event):
[6c0568b]480        """
[d955bf19]481        Is available only when a slicer is drawn.Create a dialog
482        window where the user can enter value to reset slicer
483        parameters.
484       
485        :param event: wx.menu event
486       
[6c0568b]487        """
[32c0841]488        if self.slicer != None:
[1bf33c1]489            from SlicerParameters import SlicerParameterPanel
[4f8a00c]490            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
[1bf33c1]491            dialog.set_slicer(self.slicer.__class__.__name__,
492                            self.slicer.get_params())
493            if dialog.ShowModal() == wx.ID_OK:
494                dialog.Destroy() 
495       
496    def onSectorQ(self, event):
497        """
[d955bf19]498        Perform sector averaging on Q and draw sector slicer
[1bf33c1]499        """
[ef0c170]500        from SectorSlicer import SectorInteractor
[1bf33c1]501        self.onClearSlicer(event)
[32c0841]502        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
[1bf33c1]503       
504    def onSectorPhi(self, event):
505        """
[d955bf19]506        Perform sector averaging on Phi and draw annulus slicer
[1bf33c1]507        """
[ef0c170]508        from AnnulusSlicer import AnnulusInteractor
[1bf33c1]509        self.onClearSlicer(event)
[32c0841]510        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
[1bf33c1]511       
[d955bf19]512    def onBoxSum(self, event):
513        """
514        """
[7ab9241]515        from boxSum import BoxSum
516        self.onClearSlicer(event)
[54cc36a]517        self.slicer_z += 1
518        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
519        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
520        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
521        self.update()
522        self.slicer.update()
[6c0568b]523        ## Value used to initially set the slicer panel
524        type = self.slicer.__class__.__name__
525        params = self.slicer.get_params()
526        ## Create a new panel to display results of summation of Data2D
[8a7a21b]527        from slicerpanel import SlicerPanel
[32c0841]528        new_panel = SlicerPanel(parent=self.parent, id=-1,
529                                    base=self, type=type,
530                                    params=params, style=wx.RAISED_BORDER)
531       
532        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
533                                    str(self.data2D.name)
534        new_panel.window_name = self.slicer.__class__.__name__+ " " + \
535                                    str(self.data2D.name)
[6c0568b]536        ## Store a reference of the new created panel
[32c0841]537        self.panel_slicer = new_panel
[6c0568b]538        ## save the window_caption of the new panel in the current slicer
[32c0841]539        self.slicer.set_panel_name(name=new_panel.window_caption)
[6c0568b]540        ## post slicer panel to guiframe to display it
[55a0dc1]541        from sans.guiframe.events import SlicerPanelEvent
[32c0841]542        wx.PostEvent(self.parent, SlicerPanelEvent(panel=self.panel_slicer,
543                                                    main_panel=self))
[6c0568b]544
[8a7a21b]545    def onBoxavgX(self,event):
[6c0568b]546        """
[d955bf19]547        Perform 2D data averaging on Qx
548        Create a new slicer .
549       
550        :param event: wx.menu event
[6c0568b]551        """
[8a7a21b]552        from boxSlicer import BoxInteractorX
[38224f10]553        self.onClearSlicer(event)
[32c0841]554        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
[d468daa]555       
[8a7a21b]556    def onBoxavgY(self,event):
[6c0568b]557        """
[d955bf19]558        Perform 2D data averaging on Qy
559        Create a new slicer .
560       
561        :param event: wx.menu event
562       
[6c0568b]563        """
[8a7a21b]564        from boxSlicer import BoxInteractorY
565        self.onClearSlicer(event)
[32c0841]566        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
[6c0568b]567       
[1bf33c1]568    def onClearSlicer(self, event):
569        """
[d955bf19]570        Clear the slicer on the plot
[1bf33c1]571        """
[32c0841]572        if not self.slicer == None:
[1bf33c1]573            self.slicer.clear()
574            self.subplot.figure.canvas.draw()
575            self.slicer = None
576            # Post slicer None event
577            event = self._getEmptySlicerEvent()
[d468daa]578            wx.PostEvent(self, event)
[ed8ad21]579           
580    def _onSave(self, evt):
581        """
582        Save a data set to a dat(text) file
583       
584        :param evt: Menu event
585       
586        """
587        id = str(evt.GetId())
588        if id in self.action_ids:         
589           
590            path = None
591            wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
592            dlg = wx.FileDialog(self, "Choose a file",
593                                self._default_save_location,
594                                 "", wildcard , wx.SAVE)
595           
596            if dlg.ShowModal() == wx.ID_OK:
597                path = dlg.GetPath()
[ad1e49c]598                # ext_num = 0 for .txt, ext_num = 1 for .xml
599                # This is MAC Fix
600                ext_num = dlg.GetFilterIndex()
601                if ext_num == 0:
602                    format = '.dat'
603                else:
604                    format = ''
605                path = os.path.splitext(path)[0] + format
[ed8ad21]606                mypath = os.path.basename(path)
607               
608                #TODO: This is bad design. The DataLoader is designed
609                #to recognize extensions.
610                # It should be a simple matter of calling the .
611                #save(file, data, '.xml') method
612                # of the DataLoader.loader.Loader class.
613                from DataLoader.loader import  Loader
614                #Instantiate a loader
615                loader = Loader() 
616                data = self.data2D
617
618                format = ".dat"
619                if os.path.splitext(mypath)[1].lower() == format:
[959981b]620                    # Make sure the ext included in the file name
621                    # especially on MAC
622                    fName = os.path.splitext(path)[0] + format
623                    loader.save(fName, data, format)
[ed8ad21]624                try:
625                    self._default_save_location = os.path.dirname(path)
626                except:
627                    pass   
628            dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.