source: sasview/sansguiframe/src/sans/guiframe/local_perspectives/plotting/Plotter2D.py @ e4a703a

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

keep the xylimit on update plot

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