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

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

minor fix in saving as data

  • Property mode set to 100644
File size: 29.7 KB
Line 
1
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################################################################################
11
12
13import wx
14import sys
15import os
16import math
17import numpy
18import pylab
19import danse.common.plottools
20from danse.common.plottools.PlotPanel import PlotPanel
21from danse.common.plottools.plottables import Graph
22from danse.common.plottools.TextDialog import TextDialog
23from sans.guiframe.events import EVT_NEW_PLOT
24from sans.guiframe.events import EVT_SLICER_PARS
25from sans.guiframe.events import StatusEvent
26from sans.guiframe.events import NewPlotEvent
27from sans.guiframe.events import PanelOnFocusEvent
28from sans.guiframe.events import SlicerEvent
29from sans.guiframe.utils import PanelMenu
30from binder import BindArtist
31from Plotter1D import ModelPanel1D
32from danse.common.plottools.toolbar import NavigationToolBar
33from sans.guiframe.dataFitting import Data1D
34from matplotlib.font_manager import FontProperties
35(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
36
37DEFAULT_QMAX = 0.05
38DEFAULT_QSTEP = 0.001
39DEFAULT_BEAM = 0.005
40BIN_WIDTH = 1.0
41
42
43class NavigationToolBar2D(NavigationToolBar):
44    """
45    """
46    def __init__(self, canvas, parent=None):
47        NavigationToolBar.__init__(self, canvas=canvas, parent=parent)
48       
49    def delete_option(self):
50        """
51        remove default toolbar item
52        """
53        #delete reset button
54        self.DeleteToolByPos(0) 
55        #delete dragging
56        self.DeleteToolByPos(2) 
57        #delete unwanted button that configures subplot parameters
58        self.DeleteToolByPos(4)
59       
60    def add_option(self):
61        """
62        add item to the toolbar
63        """
64        #add button
65        id_context = wx.NewId()
66        context_tip = 'Graph Menu'
67        context =  wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_TOOLBAR)
68        self.InsertSimpleTool(0, id_context, context, 
69                                   context_tip, context_tip)
70        wx.EVT_TOOL(self, id_context,  self.parent.onToolContextMenu)
71        self.InsertSeparator(1)
72        #add print button
73        id_print = wx.NewId()
74        print_bmp =  wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_TOOLBAR)
75        self.AddSimpleTool(id_print, print_bmp,
76                           'Print', 'Activate printing')
77        wx.EVT_TOOL(self, id_print, self.on_print)
78       
79       
80class ModelPanel2D(ModelPanel1D):
81    """
82    Plot panel for use with the GUI manager
83    """
84   
85    ## Internal name for the AUI manager
86    window_name = "plotpanel"
87    ## Title to appear on top of the window
88    window_caption = "Plot Panel"
89    ## Flag to tell the GUI manager that this panel is not
90    #  tied to any perspective
91    ALWAYS_ON = True
92    ## Group ID
93    group_id = None
94   
95   
96    def __init__(self, parent, id=-1, data2d=None, color = None,
97                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
98        """
99        Initialize the panel
100        """
101        ModelPanel1D.__init__(self, parent, id=id, style=style, **kwargs)
102       
103        ## Reference to the parent window
104        self.parent = parent
105        ## Dictionary containing Plottables
106        self.plots = {}
107        ## Save reference of the current plotted
108        self.data2D = data2d
109        ## Unique ID (from gui_manager)
110        self.uid = None
111        ## Action IDs for internal call-backs
112        self.action_ids = {}
113        ## Create Artist and bind it
114        self.connect = BindArtist(self.subplot.figure)
115        ## Beam stop
116        self.beamstop_radius = DEFAULT_BEAM
117        ## to set the order of lines drawn first.
118        self.slicer_z = 5
119        ## Reference to the current slicer
120        self.slicer = None
121        ## event to send slicer info
122        self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
123       
124        self.axes_frozen = False
125        ## panel that contains result from slicer motion (ex: Boxsum info)
126        self.panel_slicer = None
127        self.title_label = None
128        self.title_font = None
129        self.title_color = 'black'
130        ## Graph       
131        self.graph = Graph()
132        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
133        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
134        self.graph.render(self)
135        ## store default value of zmin and zmax
136        self.default_zmin_ctl = self.zmin_2D
137        self.default_zmax_ctl = self.zmax_2D
138       
139    def onLeftDown(self, event): 
140        """
141        left button down and ready to drag
142       
143        """
144        # Check that the LEFT button was pressed
145        PlotPanel.onLeftDown(self, event)   
146        ax = event.inaxes
147        if ax != None:
148            # data coordinate position
149            pos_x = "%8.3g"% event.xdata
150            pos_y = "%8.3g"% event.ydata
151            position = "x: %s    y: %s" % (pos_x, pos_y)
152            wx.PostEvent(self.parent, StatusEvent(status=position))
153        self.plottable_selected(self.data2D.id)
154        self._manager.set_panel_on_focus(self)
155        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
156       
157    def add_toolbar(self):
158        """
159        add toolbar
160        """
161        self.enable_toolbar = True
162        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
163        self.toolbar.Realize()
164        # On Windows platform, default window size is incorrect, so set
165        # toolbar width to figure width.
166        tw, th = self.toolbar.GetSizeTuple()
167        fw, fh = self.canvas.GetSizeTuple()
168        self.toolbar.SetSize(wx.Size(fw, th))
169        self.sizer.Add(self.toolbar, 0, wx.LEFT|wx.EXPAND)
170        # update the axes menu on the toolbar
171        self.toolbar.update()
172         
173    def plot_data(self, data):
174        """
175        Data is ready to be displayed
176       
177        :TODO: this name should be changed to something more appropriate
178             Don't forget that changing this name will mean changing code
179             in plotting.py
180         
181        :param event: data event
182        """
183        xlo = None
184        xhi = None
185        ylo = None 
186        yhi = None
187        ## Update self.data2d with the current plot
188        self.data2D = data
189        if data.id in self.plots.keys():
190            #replace
191            xlo, xhi = self.subplot.get_xlim()
192            ylo, yhi = self.subplot.get_ylim()
193            self.graph.replace(data)
194            self.plots[data.id] = data
195        else:
196            self.plots[data.id] = data
197            self.graph.add(self.plots[data.id]) 
198            # update qmax with the new xmax of data plotted
199            self.qmax = data.xmax
200           
201        self.slicer = None
202        # Check axis labels
203        #TODO: Should re-factor this
204        ## render the graph with its new content
205               
206        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
207        if len(data.detector) < 1: 
208            if len(data._xunit) < 1 and len(data._yunit) < 1:
209                data._xaxis = '\\rm{x}'
210                data._yaxis = '\\rm{y}'
211                data._xunit = 'pixel'
212                data._yunit = 'pixel'
213       
214        # graph properties
215        self.graph.xaxis(data._xaxis, data._xunit)
216        self.graph.yaxis(data._yaxis, data._yunit)
217        if self._is_changed_legend_label:   
218                data.label = self.title_label
219       
220        if data.label == None:
221            data.label = data.name
222           
223        if not self.title_font:
224            self.graph.title(data.label)
225            self.graph.render(self)
226            # Set the axis labels on subplot
227            self._set_axis_labels()
228            self.draw_plot()
229        else:
230            self.graph.render(self)
231            self.draw_plot()
232            self.subplot.set_title(label=data.label,
233                                   fontproperties=self.title_font,
234                                   color=self.title_color)
235            self.subplot.figure.canvas.draw_idle() 
236       
237       
238        ## store default value of zmin and zmax
239        self.default_zmin_ctl = self.zmin_2D
240        self.default_zmax_ctl = self.zmax_2D
241        # Check if zoomed
242        toolbar_zoomed = self.toolbar.GetToolEnabled(self.toolbar._NTB2_BACK)
243        if not self.is_zoomed and not toolbar_zoomed:
244            return
245       
246        # Recover the x,y limits
247        if (xlo and xhi and ylo and yhi) != None:
248            if (xlo > data.xmin and xhi < data.xmax and\
249                        ylo > data.ymin and yhi < data.ymax):
250                self.subplot.set_xlim((xlo, xhi))     
251                self.subplot.set_ylim((ylo, yhi)) 
252            else: 
253                self.toolbar.update()
254                self._is_zoomed = False
255               
256        # Update Graph menu and help string       
257        pos = self.parent._window_menu.FindItem(self.window_caption)
258        helpString = 'Show/Hide Graph: '
259        helpString += (' ' + data.label +';')
260        self.parent._window_menu.SetHelpString(pos, helpString)
261       
262    def _set_axis_labels(self):
263        """
264        Set axis labels
265        """
266        data = self.data2D
267        # control axis labels from the panel itself
268        yname, yunits = data.get_yaxis()
269        if self.yaxis_label != None:
270            yname = self.yaxis_label
271            yunits = self.yaxis_unit
272        else:
273            self.yaxis_label = yname
274            self.yaxis_unit = yunits
275        xname, xunits = data.get_xaxis()
276        if self.xaxis_label != None:
277            xname = self.xaxis_label
278            xunits = self.xaxis_unit
279        else:
280            self.xaxis_label = xname
281            self.xaxis_unit = xunits
282        self.xaxis(xname, xunits, self.xaxis_font, self.xaxis_color)
283        self.yaxis(yname, yunits, self.yaxis_font, self.yaxis_color)
284       
285    def onContextMenu(self, event):
286        """
287        2D plot context menu
288       
289        :param event: wx context event
290       
291        """
292        slicerpop = PanelMenu()
293        slicerpop.set_plots(self.plots)
294        slicerpop.set_graph(self.graph)
295             
296        id = wx.NewId()
297        slicerpop.Append(id, '&Save Image')
298        wx.EVT_MENU(self, id, self.onSaveImage)
299       
300        id = wx.NewId()
301        slicerpop.Append(id,'&Print Image', 'Print image')
302        wx.EVT_MENU(self, id, self.onPrint)
303       
304        id = wx.NewId()
305        slicerpop.Append(id,'&Print Preview', 'Print preview')
306        wx.EVT_MENU(self, id, self.onPrinterPreview)
307
308        id = wx.NewId()
309        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
310        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
311        slicerpop.AppendSeparator()
312        # saving data
313        plot = self.data2D
314        id = wx.NewId()
315        name = plot.name
316        slicerpop.Append(id, "&Save as a File (DAT)" )
317        self.action_ids[str(id)] = plot
318        wx.EVT_MENU(self, id, self._onSave)
319
320        slicerpop.AppendSeparator()
321        if len(self.data2D.detector) == 1:       
322           
323            item_list = self.parent.get_context_menu(self)
324            if (not item_list == None) and (not len(item_list) == 0) and\
325                self.data2D.name.split(" ")[0] != 'Residuals': 
326                # The line above; Not for trunk
327                for item in item_list:
328                    try:
329                        id = wx.NewId()
330                        slicerpop.Append(id, item[0], item[1])
331                        wx.EVT_MENU(self, id, item[2])
332                    except:
333                        msg = "ModelPanel1D.onContextMenu: "
334                        msg += "bad menu item  %s"%sys.exc_value
335                        wx.PostEvent(self.parent, StatusEvent(status=msg))
336                        pass
337                slicerpop.AppendSeparator()
338           
339            id = wx.NewId()
340            slicerpop.Append(id, '&Perform Circular Average')
341            wx.EVT_MENU(self, id, self.onCircular) \
342            # For Masked Data
343            if not plot.mask.all():
344                id = wx.NewId()
345                slicerpop.Append(id, '&Masked Circular Average')
346                wx.EVT_MENU(self, id, self.onMaskedCircular) 
347            id = wx.NewId()
348            slicerpop.Append(id, '&Sector [Q View]')
349            wx.EVT_MENU(self, id, self.onSectorQ) 
350            id = wx.NewId()
351            slicerpop.Append(id, '&Annulus [Phi View ]')
352            wx.EVT_MENU(self, id, self.onSectorPhi) 
353            id = wx.NewId()
354            slicerpop.Append(id, '&Box Sum')
355            wx.EVT_MENU(self, id, self.onBoxSum) 
356            id = wx.NewId()
357            slicerpop.Append(id, '&Box Averaging in Qx')
358            wx.EVT_MENU(self, id, self.onBoxavgX) 
359            id = wx.NewId()
360            slicerpop.Append(id, '&Box Averaging in Qy')
361            wx.EVT_MENU(self, id, self.onBoxavgY) 
362            if self.slicer != None:
363                id = wx.NewId()
364                slicerpop.Append(id, '&Clear Slicer')
365                wx.EVT_MENU(self, id,  self.onClearSlicer) 
366                if self.slicer.__class__.__name__  != "BoxSum":
367                    id = wx.NewId()
368                    slicerpop.Append(id, '&Edit Slicer Parameters')
369                    wx.EVT_MENU(self, id, self._onEditSlicer) 
370            slicerpop.AppendSeparator() 
371           
372        id = wx.NewId()
373        slicerpop.Append(id, '&Edit Graph Label', 'Edit Graph Label')
374        wx.EVT_MENU(self, id, self.onEditLabels)
375        slicerpop.AppendSeparator()
376       
377        id = wx.NewId()
378        slicerpop.Append(id, '&Edit Y Axis Label')
379        wx.EVT_MENU(self, id, self._on_yaxis_label)     
380        id = wx.NewId()
381        slicerpop.Append(id, '&Edit X Axis Label')
382        wx.EVT_MENU(self, id, self._on_xaxis_label)
383        id = wx.NewId()
384        slicerpop.Append(id, '&Toggle Grid On/Off', 'Toggle Grid On/Off')
385        wx.EVT_MENU(self, id, self.onGridOnOff)
386        slicerpop.AppendSeparator()
387       
388        id = wx.NewId()
389        slicerpop.Append(id, '&2D Color Map')
390        wx.EVT_MENU(self, id, self._onEditDetector)
391        slicerpop.AppendSeparator()
392       
393        id = wx.NewId()
394        slicerpop.Append(id, '&Toggle Linear/Log Scale')
395        wx.EVT_MENU(self, id, self._onToggleScale) 
396       
397       
398        slicerpop.AppendSeparator()
399        id = wx.NewId()
400        slicerpop.Append(id, '&Window Title')
401        wx.EVT_MENU(self, id, self.onChangeCaption)
402       
403        try:
404            pos_evt = event.GetPosition()
405            pos = self.ScreenToClient(pos_evt)
406        except:
407            pos_x, pos_y = self.toolbar.GetPositionTuple()
408            pos = (pos_x, pos_y + 5)
409        self.PopupMenu(slicerpop, pos)
410       
411           
412    def onEditLabels(self, event):
413        """
414        Edit legend label
415        """
416        selected_plot = self.plots[self.graph.selected_plottable]
417        label = selected_plot.label
418        dial = TextDialog(None, -1, 'Change Label', label)
419        if dial.ShowModal() == wx.ID_OK:
420            try:
421                FONT = FontProperties()
422                newlabel = dial.getText()
423                font = FONT.copy()
424                font.set_size(dial.getSize())
425                font.set_family(dial.getFamily())
426                font.set_style(dial.getStyle())
427                font.set_weight(dial.getWeight())
428                colour = dial.getColor()
429                if len(newlabel) > 0:
430                    # update Label
431                    selected_plot.label = newlabel
432                    self.graph.title(newlabel)
433                    self.title_label = selected_plot.label
434                    self.title_font = font
435                    self.title_color = colour
436                    ## render the graph
437                    self.subplot.set_title(label=self.title_label,
438                                           fontproperties=self.title_font,
439                                           color=self.title_color)
440                    self._is_changed_legend_label = True
441                    self.subplot.figure.canvas.draw_idle() 
442            except:
443                if self.parent != None:
444                    from sans.guiframe.events import StatusEvent
445                    msg= "Add Text: Error. Check your property values..."
446                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
447                else:
448                    raise
449        dial.Destroy()
450       
451        # Update Graph menu and help string
452        if self.title_label != None:     
453            pos = self.parent._window_menu.FindItem(self.window_caption)
454            helpString = 'Show/Hide Graph: '
455            helpString += (' ' + self.title_label +';')
456            self.parent._window_menu.SetHelpString(pos, helpString)
457
458       
459    def _onEditDetector(self, event):
460        """
461        Allow to view and edits  detector parameters
462       
463        :param event: wx.menu event
464       
465        """
466        import detector_dialog
467        dialog = detector_dialog.DetectorDialog(self, -1,base=self.parent,
468                       reset_zmin_ctl =self.default_zmin_ctl,
469                       reset_zmax_ctl = self.default_zmax_ctl,cmap=self.cmap)
470        ## info of current detector and data2D
471        xnpts = len(self.data2D.x_bins)
472        ynpts = len(self.data2D.y_bins)
473        xmax = max(self.data2D.xmin, self.data2D.xmax)
474        ymax = max(self.data2D.ymin, self.data2D.ymax)
475        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
476        beam = self.data2D.xmin
477        ## set dialog window content
478        dialog.setContent(xnpts=xnpts,ynpts=ynpts,qmax=qmax,
479                           beam=self.data2D.xmin,
480                           zmin = self.zmin_2D,
481                          zmax = self.zmax_2D)
482        if dialog.ShowModal() == wx.ID_OK:
483            evt = dialog.getContent()
484            self.zmin_2D = evt.zmin
485            self.zmax_2D = evt.zmax
486            self.cmap = evt.cmap
487        dialog.Destroy()
488        ## Redraw the current image
489        self.image(data=self.data2D.data,
490                   qx_data=self.data2D.qx_data,
491                   qy_data=self.data2D.qy_data,
492                   xmin= self.data2D.xmin,
493                   xmax= self.data2D.xmax,
494                   ymin= self.data2D.ymin,
495                   ymax= self.data2D.ymax,
496                   zmin= self.zmin_2D,
497                   zmax= self.zmax_2D,
498                   cmap= self.cmap,
499                   color=0, symbol=0, label=self.data2D.name)
500        self.subplot.figure.canvas.draw_idle()
501       
502    def freeze_axes(self):
503        """
504        """
505        self.axes_frozen = True
506       
507    def thaw_axes(self):
508        """
509        """
510        self.axes_frozen = False
511       
512    def onMouseMotion(self,event):
513        """
514        """
515        pass
516   
517    def onWheel(self, event):
518        """
519        """
520        pass 
521     
522    def update(self, draw=True):
523        """
524        Respond to changes in the model by recalculating the
525        profiles and resetting the widgets.
526        """
527        self.draw_plot()
528       
529    def _getEmptySlicerEvent(self):
530        """
531        create an empty slicervent
532        """
533        return SlicerEvent(type=None, params=None, obj_class=None)
534       
535    def _onEVT_INTERNAL(self, event):
536        """
537        Draw the slicer
538       
539        :param event: wx.lib.newevent (SlicerEvent) containing slicer
540            parameter
541           
542        """
543        self._setSlicer(event.slicer)
544           
545    def _setSlicer(self, slicer):
546        """
547        Clear the previous slicer and create a new one.Post an internal
548        event.
549       
550        :param slicer: slicer class to create
551       
552        """
553        ## Clear current slicer
554        if not self.slicer == None: 
555            self.slicer.clear()           
556        ## Create a new slicer   
557        self.slicer_z += 1
558        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
559        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
560        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
561        ## Draw slicer
562        self.update()
563        self.slicer.update()
564        msg = "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__
565        wx.PostEvent(self.parent, StatusEvent(status=msg))
566        # Post slicer event
567        event = self._getEmptySlicerEvent()
568        event.type = self.slicer.__class__.__name__
569        event.obj_class = self.slicer.__class__
570        event.params = self.slicer.get_params()
571        wx.PostEvent(self, event)
572       
573    def onMaskedCircular(self, event):
574        """
575        perform circular averaging on Data2D with mask if it exists
576       
577        :param event: wx.menu event
578       
579        """
580        self.onCircular(event, True)
581       
582    def onCircular(self, event, ismask=False):
583        """
584        perform circular averaging on Data2D
585       
586        :param event: wx.menu event
587       
588        """
589        # Find the best number of bins
590        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
591        npt = math.floor(npt)
592        from sans.dataloader.manipulations import CircularAverage
593        ## compute the maximum radius of data2D
594        self.qmax = max(math.fabs(self.data2D.xmax), 
595                        math.fabs(self.data2D.xmin))
596        self.ymax = max(math.fabs(self.data2D.ymax),
597                        math.fabs(self.data2D.ymin))
598        self.radius = math.sqrt(math.pow(self.qmax, 2)+ math.pow(self.ymax, 2)) 
599        ##Compute beam width
600        bin_width = (self.qmax + self.qmax)/npt
601        ## Create data1D circular average of data2D
602        Circle = CircularAverage(r_min=0, r_max=self.radius, 
603                                 bin_width=bin_width)
604        circ = Circle(self.data2D, ismask=ismask)
605        from sans.guiframe.dataFitting import Data1D
606        if hasattr(circ, "dxl"):
607            dxl = circ.dxl
608        else:
609            dxl = None
610        if hasattr(circ, "dxw"):
611            dxw = circ.dxw
612        else:
613            dxw = None
614
615        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
616        new_plot.dxl = dxl
617        new_plot.dxw = dxw
618        new_plot.name = "Circ avg " + self.data2D.name
619        new_plot.source = self.data2D.source
620        #new_plot.info = self.data2D.info
621        new_plot.interactive = True
622        new_plot.detector = self.data2D.detector
623       
624        ## If the data file does not tell us what the axes are, just assume...
625        new_plot.xaxis("\\rm{Q}", "A^{-1}")
626        if hasattr(self.data2D, "scale") and \
627                    self.data2D.scale == 'linear':
628            new_plot.ytransform = 'y'
629            new_plot.yaxis("\\rm{Residuals} ", "normalized")
630        else:
631            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
632
633        new_plot.group_id = "Circ avg " + self.data2D.name
634        new_plot.id = "Circ avg " + self.data2D.name
635        new_plot.is_data = True
636        self.parent.update_theory(data_id=self.data2D, \
637                                       theory=new_plot)
638        wx.PostEvent(self.parent, 
639                     NewPlotEvent(plot=new_plot, title=new_plot.name))
640       
641    def _onEditSlicer(self, event):
642        """
643        Is available only when a slicer is drawn.Create a dialog
644        window where the user can enter value to reset slicer
645        parameters.
646       
647        :param event: wx.menu event
648       
649        """
650        if self.slicer != None:
651            from SlicerParameters import SlicerParameterPanel
652            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
653            dialog.set_slicer(self.slicer.__class__.__name__,
654                            self.slicer.get_params())
655            if dialog.ShowModal() == wx.ID_OK:
656                dialog.Destroy() 
657       
658    def onSectorQ(self, event):
659        """
660        Perform sector averaging on Q and draw sector slicer
661        """
662        from SectorSlicer import SectorInteractor
663        self.onClearSlicer(event)
664        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
665       
666    def onSectorPhi(self, event):
667        """
668        Perform sector averaging on Phi and draw annulus slicer
669        """
670        from AnnulusSlicer import AnnulusInteractor
671        self.onClearSlicer(event)
672        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
673       
674    def onBoxSum(self, event):
675        """
676        """
677        from boxSum import BoxSum
678        self.onClearSlicer(event)
679        self.slicer_z += 1
680        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
681        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
682        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
683        self.update()
684        self.slicer.update()
685        ## Value used to initially set the slicer panel
686        type = self.slicer.__class__.__name__
687        params = self.slicer.get_params()
688        ## Create a new panel to display results of summation of Data2D
689        from slicerpanel import SlicerPanel
690        new_panel = SlicerPanel(parent=self.parent, id=-1,
691                                    base=self, type=type,
692                                    params=params, style=wx.RAISED_BORDER)
693       
694        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
695                                    str(self.data2D.name)
696        new_panel.window_name = self.slicer.__class__.__name__+ " " + \
697                                    str(self.data2D.name)
698        ## Store a reference of the new created panel
699        self.panel_slicer = new_panel
700        ## save the window_caption of the new panel in the current slicer
701        self.slicer.set_panel_name(name=new_panel.window_caption)
702        ## post slicer panel to guiframe to display it
703        from sans.guiframe.events import SlicerPanelEvent
704        wx.PostEvent(self.parent, SlicerPanelEvent(panel=self.panel_slicer,
705                                                    main_panel=self))
706
707    def onBoxavgX(self,event):
708        """
709        Perform 2D data averaging on Qx
710        Create a new slicer .
711       
712        :param event: wx.menu event
713        """
714        from boxSlicer import BoxInteractorX
715        self.onClearSlicer(event)
716        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
717       
718    def onBoxavgY(self,event):
719        """
720        Perform 2D data averaging on Qy
721        Create a new slicer .
722       
723        :param event: wx.menu event
724       
725        """
726        from boxSlicer import BoxInteractorY
727        self.onClearSlicer(event)
728        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
729       
730    def onClearSlicer(self, event):
731        """
732        Clear the slicer on the plot
733        """
734        if not self.slicer == None:
735            self.slicer.clear()
736            self.subplot.figure.canvas.draw()
737            self.slicer = None
738            # Post slicer None event
739            event = self._getEmptySlicerEvent()
740            wx.PostEvent(self, event)
741           
742    def _onSave(self, evt):
743        """
744        Save a data set to a dat(text) file
745       
746        :param evt: Menu event
747       
748        """
749        id = str(evt.GetId())
750        if self.parent != None:
751            self._default_save_location = self.parent._default_save_location
752        default_name = self.plots[self.graph.selected_plottable].label
753        if default_name.count('.') > 0:
754            default_name = default_name.split('.')[0]
755        default_name += "_out"
756        if id in self.action_ids:         
757           
758            path = None
759            wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
760            dlg = wx.FileDialog(self, "Choose a file",
761                                self._default_save_location,
762                                default_name, wildcard , wx.SAVE)
763           
764            if dlg.ShowModal() == wx.ID_OK:
765                path = dlg.GetPath()
766                # ext_num = 0 for .txt, ext_num = 1 for .xml
767                # This is MAC Fix
768                ext_num = dlg.GetFilterIndex()
769                if ext_num == 0:
770                    format = '.dat'
771                else:
772                    format = ''
773                path = os.path.splitext(path)[0] + format
774                mypath = os.path.basename(path)
775               
776                #TODO: This is bad design. The DataLoader is designed
777                #to recognize extensions.
778                # It should be a simple matter of calling the .
779                #save(file, data, '.xml') method
780                # of the DataLoader.loader.Loader class.
781                from sans.dataloader.loader import  Loader
782                #Instantiate a loader
783                loader = Loader() 
784                data = self.data2D
785
786                format = ".dat"
787                if os.path.splitext(mypath)[1].lower() == format:
788                    # Make sure the ext included in the file name
789                    # especially on MAC
790                    fName = os.path.splitext(path)[0] + format
791                    loader.save(fName, data, format)
792                try:
793                    self._default_save_location = os.path.dirname(path)
794                    self.parent._default_save_location = \
795                                            self._default_save_location
796                except:
797                    pass   
798            dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.