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

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

mac saving data fixes

  • Property mode set to 100644
File size: 22.9 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
137        self.plottable_selected(self.data2D.id)
138       
139        self._manager.set_panel_on_focus(self)
140        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
141       
[ac8671e]142    def add_toolbar(self):
143        """
[d955bf19]144        add toolbar
[ac8671e]145        """
146        self.enable_toolbar = True
[32c0841]147        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
[ac8671e]148        self.toolbar.Realize()
149        # On Windows platform, default window size is incorrect, so set
150        # toolbar width to figure width.
151        tw, th = self.toolbar.GetSizeTuple()
152        fw, fh = self.canvas.GetSizeTuple()
153        self.toolbar.SetSize(wx.Size(fw, th))
[32c0841]154        self.sizer.Add(self.toolbar, 0, wx.LEFT|wx.EXPAND)
[ac8671e]155        # update the axes menu on the toolbar
156        self.toolbar.update()
157         
[a07e72f]158    def plot_data(self, data):
[1bf33c1]159        """
[d955bf19]160        Data is ready to be displayed
161       
162        :TODO: this name should be changed to something more appropriate
163             Don't forget that changing this name will mean changing code
164             in plotting.py
165         
166        :param event: data event
[1bf33c1]167        """
[6c0568b]168        ## Update self.data2d with the current plot
[a07e72f]169        self.data2D = data
170        if data.id in self.plots.keys():
171            #replace
172            self.graph.replace(data)
173            self.plots[data.id] = data
[ab8f936]174        else:
[a07e72f]175            self.plots[data.id] = data
176            self.graph.add(self.plots[data.id]) 
[ac9a5f6]177            # update qmax with the new xmax of data plotted
[a07e72f]178            self.qmax = data.xmax
[4b91fd1]179           
[32c0841]180        self.slicer = None
[1bf33c1]181        # Check axis labels
182        #TODO: Should re-factor this
[6c0568b]183        ## render the graph with its new content
[7fff5cd]184               
185        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
186        if len(self.data2D.detector) < 1: 
[a07e72f]187            if len(data._xunit) < 1 and len(data._yunit) < 1:
188                data._xaxis = '\\rm{x}'
189                data._yaxis = '\\rm{y}'
190                data._xunit = 'pixel'
191                data._yunit = 'pixel'
192        self.graph.xaxis(data._xaxis, data._xunit)
193        self.graph.yaxis(data._yaxis, data._yunit)
[0690e1d]194        self.graph.title(self.data2D.name)
[1bf33c1]195        self.graph.render(self)
[6d727ae]196        self.draw_plot()
197        #self.subplot.figure.canvas.draw_idle()
[8dfdd20]198        ## store default value of zmin and zmax
199        self.default_zmin_ctl = self.zmin_2D
200        self.default_zmax_ctl = self.zmax_2D
[1bf33c1]201
202    def onContextMenu(self, event):
203        """
[d955bf19]204        2D plot context menu
205       
206        :param event: wx context event
[15550f4]207       
[d955bf19]208        """
[1bf33c1]209        slicerpop = PanelMenu()
210        slicerpop.set_plots(self.plots)
211        slicerpop.set_graph(self.graph)
[9a585d0]212             
213        id = wx.NewId()
[6d727ae]214        slicerpop.Append(id, '&Save Image')
[9a585d0]215        wx.EVT_MENU(self, id, self.onSaveImage)
216       
217        id = wx.NewId()
[6d727ae]218        slicerpop.Append(id,'&Print Image', 'Print image')
[9a585d0]219        wx.EVT_MENU(self, id, self.onPrint)
220       
[1ce365f8]221        id = wx.NewId()
[6d727ae]222        slicerpop.Append(id,'&Print Preview', 'Print preview')
[1ce365f8]223        wx.EVT_MENU(self, id, self.onPrinterPreview)
[003fa4e]224
225        id = wx.NewId()
226        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
227        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
[1ce365f8]228       
[ed8ad21]229        # saving data
230        plot = self.data2D
231        id = wx.NewId()
232        name = plot.name
233        slicerpop.Append(id, "&Save as a file (DAT)" )
234        self.action_ids[str(id)] = plot
235        wx.EVT_MENU(self, id, self._onSave)
236
[9a585d0]237        slicerpop.AppendSeparator()
[7fff5cd]238        if len(self.data2D.detector) == 1:       
[0e13148]239           
[a07e72f]240            item_list = self.parent.get_context_menu(self)
[6d727ae]241            if (not item_list == None) and (not len(item_list) == 0) and\
242                self.data2D.name.split(" ")[0] != 'Residuals': 
243                # The line above; Not for trunk
[32c0841]244                for item in item_list:
245                    try:
246                        id = wx.NewId()
247                        slicerpop.Append(id, item[0], item[1])
248                        wx.EVT_MENU(self, id, item[2])
249                    except:
250                        msg = "ModelPanel1D.onContextMenu: "
251                        msg += "bad menu item  %s"%sys.exc_value
252                        wx.PostEvent(self.parent, StatusEvent(status=msg))
253                        pass
254                slicerpop.AppendSeparator()
[0e13148]255           
[15550f4]256            id = wx.NewId()
257            slicerpop.Append(id, '&Perform circular average')
[6d727ae]258            wx.EVT_MENU(self, id, self.onCircular) \
259            # For Masked Data
260            if not plot.mask.all():
261                id = wx.NewId()
262                slicerpop.Append(id, '&Masked circular average')
263                wx.EVT_MENU(self, id, self.onMaskedCircular) 
[15550f4]264            id = wx.NewId()
265            slicerpop.Append(id, '&Sector [Q view]')
266            wx.EVT_MENU(self, id, self.onSectorQ) 
267            id = wx.NewId()
268            slicerpop.Append(id, '&Annulus [Phi view ]')
269            wx.EVT_MENU(self, id, self.onSectorPhi) 
[92c2345]270            id = wx.NewId()
[15550f4]271            slicerpop.Append(id, '&Box Sum')
272            wx.EVT_MENU(self, id, self.onBoxSum) 
273            id = wx.NewId()
274            slicerpop.Append(id, '&Box averaging in Qx')
275            wx.EVT_MENU(self, id, self.onBoxavgX) 
276            id = wx.NewId()
277            slicerpop.Append(id, '&Box averaging in Qy')
278            wx.EVT_MENU(self, id, self.onBoxavgY) 
[32c0841]279            if self.slicer != None:
[eba08f1a]280                id = wx.NewId()
[15550f4]281                slicerpop.Append(id, '&Clear slicer')
282                wx.EVT_MENU(self, id,  self.onClearSlicer) 
[32c0841]283                if self.slicer.__class__.__name__  != "BoxSum":
[15550f4]284                    id = wx.NewId()
285                    slicerpop.Append(id, '&Edit Slicer Parameters')
286                    wx.EVT_MENU(self, id, self._onEditSlicer) 
287            slicerpop.AppendSeparator() 
[0e13148]288        id = wx.NewId()
[52f3c98]289        slicerpop.Append(id, '&2D Color Map')
[32c0841]290        wx.EVT_MENU(self, id, self._onEditDetector)
[1bf33c1]291        id = wx.NewId()
292        slicerpop.Append(id, '&Toggle Linear/Log scale')
293        wx.EVT_MENU(self, id, self._onToggleScale) 
294        pos = event.GetPosition()
295        pos = self.ScreenToClient(pos)
296        self.PopupMenu(slicerpop, pos)
[8bd764d]297   
[ea290ee]298    def _onEditDetector(self, event):
[6d920cd]299        """
[d955bf19]300        Allow to view and edits  detector parameters
301       
302        :param event: wx.menu event
303       
[6d920cd]304        """
[ea290ee]305        import detector_dialog
[8dfdd20]306        dialog = detector_dialog.DetectorDialog(self, -1,base=self.parent,
307                       reset_zmin_ctl =self.default_zmin_ctl,
308                       reset_zmax_ctl = self.default_zmax_ctl,cmap=self.cmap)
[6c0568b]309        ## info of current detector and data2D
[ea290ee]310        xnpts = len(self.data2D.x_bins)
311        ynpts = len(self.data2D.y_bins)
312        xmax = max(self.data2D.xmin, self.data2D.xmax)
313        ymax = max(self.data2D.ymin, self.data2D.ymax)
[32c0841]314        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
[ea290ee]315        beam = self.data2D.xmin
[6c0568b]316        ## set dialog window content
[ea290ee]317        dialog.setContent(xnpts=xnpts,ynpts=ynpts,qmax=qmax,
318                           beam=self.data2D.xmin,
319                           zmin = self.zmin_2D,
320                          zmax = self.zmax_2D)
321        if dialog.ShowModal() == wx.ID_OK:
322            evt = dialog.getContent()
323            self.zmin_2D = evt.zmin
324            self.zmax_2D = evt.zmax
[32c0841]325            self.cmap = evt.cmap
[ea290ee]326        dialog.Destroy()
[6c0568b]327        ## Redraw the current image
[32c0841]328        self.image(data=self.data2D.data,
[20b6760]329                   qx_data=self.data2D.qx_data,
330                   qy_data=self.data2D.qy_data,
[ea290ee]331                   xmin= self.data2D.xmin,
332                   xmax= self.data2D.xmax,
333                   ymin= self.data2D.ymin,
334                   ymax= self.data2D.ymax,
335                   zmin= self.zmin_2D,
336                   zmax= self.zmax_2D,
[8dfdd20]337                   cmap= self.cmap,
[32c0841]338                   color=0, symbol=0, label=self.data2D.name)
[ea290ee]339        self.subplot.figure.canvas.draw_idle()
[1bf33c1]340       
341    def freeze_axes(self):
[d955bf19]342        """
343        """
[1bf33c1]344        self.axes_frozen = True
345       
346    def thaw_axes(self):
[d955bf19]347        """
348        """
[1bf33c1]349        self.axes_frozen = False
350       
351    def onMouseMotion(self,event):
[d955bf19]352        """
353        """
[1bf33c1]354        pass
[d955bf19]355   
[1bf33c1]356    def onWheel(self, event):
[d955bf19]357        """
358        """
[6c0568b]359        pass 
360     
[1bf33c1]361    def update(self, draw=True):
362        """
[d955bf19]363        Respond to changes in the model by recalculating the
364        profiles and resetting the widgets.
[1bf33c1]365        """
[6d727ae]366        self.draw_plot()
[1bf33c1]367       
368    def _getEmptySlicerEvent(self):
[6c0568b]369        """
[d955bf19]370        create an empty slicervent
[6c0568b]371        """
[32c0841]372        return SlicerEvent(type=None, params=None, obj_class=None)
[d955bf19]373       
[1bf33c1]374    def _onEVT_INTERNAL(self, event):
375        """
[d955bf19]376        Draw the slicer
377       
378        :param event: wx.lib.newevent (SlicerEvent) containing slicer
[6c0568b]379            parameter
[d955bf19]380           
[1bf33c1]381        """
382        self._setSlicer(event.slicer)
383           
384    def _setSlicer(self, slicer):
[6c0568b]385        """
[d955bf19]386        Clear the previous slicer and create a new one.Post an internal
387        event.
388       
389        :param slicer: slicer class to create
390       
[6c0568b]391        """
392        ## Clear current slicer
[1bf33c1]393        if not self.slicer == None: 
394            self.slicer.clear()           
[6c0568b]395        ## Create a new slicer   
[1bf33c1]396        self.slicer_z += 1
397        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
[240c805]398        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
399        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
[6c0568b]400        ## Draw slicer
[1bf33c1]401        self.update()
402        self.slicer.update()
[32c0841]403        msg = "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__
404        wx.PostEvent(self.parent, StatusEvent(status=msg))
[1bf33c1]405        # Post slicer event
406        event = self._getEmptySlicerEvent()
407        event.type = self.slicer.__class__.__name__
408        event.obj_class = self.slicer.__class__
409        event.params = self.slicer.get_params()
[d468daa]410        wx.PostEvent(self, event)
[6d727ae]411       
412    def onMaskedCircular(self, event):
413        """
414        perform circular averaging on Data2D with mask if it exists
415       
416        :param event: wx.menu event
417       
418        """
419        self.onCircular(event, True)
420       
421    def onCircular(self, event, ismask=False):
[1bf33c1]422        """
[d955bf19]423        perform circular averaging on Data2D
424       
425        :param event: wx.menu event
426       
[1bf33c1]427        """
[003fa4e]428        # Find the best number of bins
429        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
430        npt = math.floor(npt)
[1bf33c1]431        from DataLoader.manipulations import CircularAverage
[6c0568b]432        ## compute the maximum radius of data2D
[32c0841]433        self.qmax = max(math.fabs(self.data2D.xmax), 
434                        math.fabs(self.data2D.xmin))
435        self.ymax = max(math.fabs(self.data2D.ymax),
436                        math.fabs(self.data2D.ymin))
437        self.radius = math.sqrt(math.pow(self.qmax, 2)+ math.pow(self.ymax, 2)) 
[6c0568b]438        ##Compute beam width
[003fa4e]439        bin_width = (self.qmax + self.qmax)/npt
[6c0568b]440        ## Create data1D circular average of data2D
[32c0841]441        Circle = CircularAverage(r_min=0, r_max=self.radius, 
442                                 bin_width=bin_width)
[6d727ae]443        circ = Circle(self.data2D, ismask=ismask)
[1bf33c1]444        from sans.guiframe.dataFitting import Data1D
[32c0841]445        if hasattr(circ, "dxl"):
446            dxl = circ.dxl
[1bf33c1]447        else:
[32c0841]448            dxl = None
449        if hasattr(circ, "dxw"):
450            dxw = circ.dxw
[1bf33c1]451        else:
[32c0841]452            dxw = None
[003fa4e]453
454        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
[32c0841]455        new_plot.dxl = dxl
456        new_plot.dxw = dxw
457        new_plot.name = "Circ avg " + self.data2D.name
458        new_plot.source = self.data2D.source
459        #new_plot.info = self.data2D.info
[1bf33c1]460        new_plot.interactive = True
[32c0841]461        new_plot.detector = self.data2D.detector
[6d727ae]462       
[6c0568b]463        ## If the data file does not tell us what the axes are, just assume...
[32c0841]464        new_plot.xaxis("\\rm{Q}", "A^{-1}")
[2ca51f44]465        if hasattr(self.data2D, "scale") and \
466                    self.data2D.scale == 'linear':
467            new_plot.ytransform = 'y'
468            new_plot.yaxis("\\rm{Residuals} ", "normalized")
[6d727ae]469        else:
470            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
471
[32c0841]472        new_plot.group_id = "Circ avg " + self.data2D.name
473        new_plot.id = "Circ avg " + self.data2D.name
474        new_plot.is_data = True
475        wx.PostEvent(self.parent, 
476                     NewPlotEvent(plot=new_plot, title=new_plot.name))
[ef0c170]477       
[1bf33c1]478    def _onEditSlicer(self, event):
[6c0568b]479        """
[d955bf19]480        Is available only when a slicer is drawn.Create a dialog
481        window where the user can enter value to reset slicer
482        parameters.
483       
484        :param event: wx.menu event
485       
[6c0568b]486        """
[32c0841]487        if self.slicer != None:
[1bf33c1]488            from SlicerParameters import SlicerParameterPanel
[4f8a00c]489            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
[1bf33c1]490            dialog.set_slicer(self.slicer.__class__.__name__,
491                            self.slicer.get_params())
492            if dialog.ShowModal() == wx.ID_OK:
493                dialog.Destroy() 
494       
495    def onSectorQ(self, event):
496        """
[d955bf19]497        Perform sector averaging on Q and draw sector slicer
[1bf33c1]498        """
[ef0c170]499        from SectorSlicer import SectorInteractor
[1bf33c1]500        self.onClearSlicer(event)
[32c0841]501        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
[1bf33c1]502       
503    def onSectorPhi(self, event):
504        """
[d955bf19]505        Perform sector averaging on Phi and draw annulus slicer
[1bf33c1]506        """
[ef0c170]507        from AnnulusSlicer import AnnulusInteractor
[1bf33c1]508        self.onClearSlicer(event)
[32c0841]509        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
[1bf33c1]510       
[d955bf19]511    def onBoxSum(self, event):
512        """
513        """
[7ab9241]514        from boxSum import BoxSum
515        self.onClearSlicer(event)
[54cc36a]516        self.slicer_z += 1
517        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
518        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
519        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
520        self.update()
521        self.slicer.update()
[6c0568b]522        ## Value used to initially set the slicer panel
523        type = self.slicer.__class__.__name__
524        params = self.slicer.get_params()
525        ## Create a new panel to display results of summation of Data2D
[8a7a21b]526        from slicerpanel import SlicerPanel
[32c0841]527        new_panel = SlicerPanel(parent=self.parent, id=-1,
528                                    base=self, type=type,
529                                    params=params, style=wx.RAISED_BORDER)
530       
531        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
532                                    str(self.data2D.name)
533        new_panel.window_name = self.slicer.__class__.__name__+ " " + \
534                                    str(self.data2D.name)
[6c0568b]535        ## Store a reference of the new created panel
[32c0841]536        self.panel_slicer = new_panel
[6c0568b]537        ## save the window_caption of the new panel in the current slicer
[32c0841]538        self.slicer.set_panel_name(name=new_panel.window_caption)
[6c0568b]539        ## post slicer panel to guiframe to display it
[55a0dc1]540        from sans.guiframe.events import SlicerPanelEvent
[32c0841]541        wx.PostEvent(self.parent, SlicerPanelEvent(panel=self.panel_slicer,
542                                                    main_panel=self))
[6c0568b]543
[8a7a21b]544    def onBoxavgX(self,event):
[6c0568b]545        """
[d955bf19]546        Perform 2D data averaging on Qx
547        Create a new slicer .
548       
549        :param event: wx.menu event
[6c0568b]550        """
[8a7a21b]551        from boxSlicer import BoxInteractorX
[38224f10]552        self.onClearSlicer(event)
[32c0841]553        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
[d468daa]554       
[8a7a21b]555    def onBoxavgY(self,event):
[6c0568b]556        """
[d955bf19]557        Perform 2D data averaging on Qy
558        Create a new slicer .
559       
560        :param event: wx.menu event
561       
[6c0568b]562        """
[8a7a21b]563        from boxSlicer import BoxInteractorY
564        self.onClearSlicer(event)
[32c0841]565        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
[6c0568b]566       
[1bf33c1]567    def onClearSlicer(self, event):
568        """
[d955bf19]569        Clear the slicer on the plot
[1bf33c1]570        """
[32c0841]571        if not self.slicer == None:
[1bf33c1]572            self.slicer.clear()
573            self.subplot.figure.canvas.draw()
574            self.slicer = None
575            # Post slicer None event
576            event = self._getEmptySlicerEvent()
[d468daa]577            wx.PostEvent(self, event)
[ed8ad21]578           
579    def _onSave(self, evt):
580        """
581        Save a data set to a dat(text) file
582       
583        :param evt: Menu event
584       
585        """
586        id = str(evt.GetId())
587        if id in self.action_ids:         
588           
589            path = None
590            wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
591            dlg = wx.FileDialog(self, "Choose a file",
592                                self._default_save_location,
593                                 "", wildcard , wx.SAVE)
594           
595            if dlg.ShowModal() == wx.ID_OK:
596                path = dlg.GetPath()
[ad1e49c]597                # ext_num = 0 for .txt, ext_num = 1 for .xml
598                # This is MAC Fix
599                ext_num = dlg.GetFilterIndex()
600                if ext_num == 0:
601                    format = '.dat'
602                else:
603                    format = ''
604                path = os.path.splitext(path)[0] + format
[ed8ad21]605                mypath = os.path.basename(path)
606               
607                #TODO: This is bad design. The DataLoader is designed
608                #to recognize extensions.
609                # It should be a simple matter of calling the .
610                #save(file, data, '.xml') method
611                # of the DataLoader.loader.Loader class.
612                from DataLoader.loader import  Loader
613                #Instantiate a loader
614                loader = Loader() 
615                data = self.data2D
616
617                format = ".dat"
618                if os.path.splitext(mypath)[1].lower() == format:
[959981b]619                    # Make sure the ext included in the file name
620                    # especially on MAC
621                    fName = os.path.splitext(path)[0] + format
622                    loader.save(fName, data, format)
[ed8ad21]623                try:
624                    self._default_save_location = os.path.dirname(path)
625                except:
626                    pass   
627            dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.