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

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

fixed 1d 2d mixed in 1d plot

  • Property mode set to 100644
File size: 29.8 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        if data.__class__.__name__ == 'Data1D':
188            return
189        ## Update self.data2d with the current plot
190        self.data2D = data
191        if data.id in self.plots.keys():
192            #replace
193            xlo, xhi = self.subplot.get_xlim()
194            ylo, yhi = self.subplot.get_ylim()
195            self.graph.replace(data)
196            self.plots[data.id] = data
197        else:
198            self.plots[data.id] = data
199            self.graph.add(self.plots[data.id]) 
200            # update qmax with the new xmax of data plotted
201            self.qmax = data.xmax
202           
203        self.slicer = None
204        # Check axis labels
205        #TODO: Should re-factor this
206        ## render the graph with its new content
207               
208        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
209        if len(data.detector) < 1: 
210            if len(data._xunit) < 1 and len(data._yunit) < 1:
211                data._xaxis = '\\rm{x}'
212                data._yaxis = '\\rm{y}'
213                data._xunit = 'pixel'
214                data._yunit = 'pixel'
215       
216        # graph properties
217        self.graph.xaxis(data._xaxis, data._xunit)
218        self.graph.yaxis(data._yaxis, data._yunit)
219        if self._is_changed_legend_label:   
220                data.label = self.title_label
221       
222        if data.label == None:
223            data.label = data.name
224           
225        if not self.title_font:
226            self.graph.title(data.label)
227            self.graph.render(self)
228            # Set the axis labels on subplot
229            self._set_axis_labels()
230            self.draw_plot()
231        else:
232            self.graph.render(self)
233            self.draw_plot()
234            self.subplot.set_title(label=data.label,
235                                   fontproperties=self.title_font,
236                                   color=self.title_color)
237            self.subplot.figure.canvas.draw_idle() 
238       
239       
240        ## store default value of zmin and zmax
241        self.default_zmin_ctl = self.zmin_2D
242        self.default_zmax_ctl = self.zmax_2D
243        # Check if zoomed
244        toolbar_zoomed = self.toolbar.GetToolEnabled(self.toolbar._NTB2_BACK)
245        if not self.is_zoomed and not toolbar_zoomed:
246            return
247       
248        # Recover the x,y limits
249        if (xlo and xhi and ylo and yhi) != None:
250            if (xlo > data.xmin and xhi < data.xmax and\
251                        ylo > data.ymin and yhi < data.ymax):
252                self.subplot.set_xlim((xlo, xhi))     
253                self.subplot.set_ylim((ylo, yhi)) 
254            else: 
255                self.toolbar.update()
256                self._is_zoomed = False
257               
258        # Update Graph menu and help string       
259        pos = self.parent._window_menu.FindItem(self.window_caption)
260        helpString = 'Show/Hide Graph: '
261        helpString += (' ' + str(data.label) +';')
262        self.parent._window_menu.SetHelpString(pos, helpString)
263
264    def _set_axis_labels(self):
265        """
266        Set axis labels
267        """
268        data = self.data2D
269        # control axis labels from the panel itself
270        yname, yunits = data.get_yaxis()
271        if self.yaxis_label != None:
272            yname = self.yaxis_label
273            yunits = self.yaxis_unit
274        else:
275            self.yaxis_label = yname
276            self.yaxis_unit = yunits
277        xname, xunits = data.get_xaxis()
278        if self.xaxis_label != None:
279            xname = self.xaxis_label
280            xunits = self.xaxis_unit
281        else:
282            self.xaxis_label = xname
283            self.xaxis_unit = xunits
284        self.xaxis(xname, xunits, self.xaxis_font, self.xaxis_color)
285        self.yaxis(yname, yunits, self.yaxis_font, self.yaxis_color)
286       
287    def onContextMenu(self, event):
288        """
289        2D plot context menu
290       
291        :param event: wx context event
292       
293        """
294        slicerpop = PanelMenu()
295        slicerpop.set_plots(self.plots)
296        slicerpop.set_graph(self.graph)
297             
298        id = wx.NewId()
299        slicerpop.Append(id, '&Save Image')
300        wx.EVT_MENU(self, id, self.onSaveImage)
301       
302        id = wx.NewId()
303        slicerpop.Append(id,'&Print Image', 'Print image')
304        wx.EVT_MENU(self, id, self.onPrint)
305       
306        id = wx.NewId()
307        slicerpop.Append(id,'&Print Preview', 'Print preview')
308        wx.EVT_MENU(self, id, self.onPrinterPreview)
309
310        id = wx.NewId()
311        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
312        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
313        slicerpop.AppendSeparator()
314        # saving data
315        plot = self.data2D
316        id = wx.NewId()
317        name = plot.name
318        slicerpop.Append(id, "&Save as a File (DAT)" )
319        self.action_ids[str(id)] = plot
320        wx.EVT_MENU(self, id, self._onSave)
321
322        slicerpop.AppendSeparator()
323        if len(self.data2D.detector) == 1:       
324           
325            item_list = self.parent.get_context_menu(self)
326            if (not item_list == None) and (not len(item_list) == 0) and\
327                self.data2D.name.split(" ")[0] != 'Residuals': 
328                # The line above; Not for trunk
329                for item in item_list:
330                    try:
331                        id = wx.NewId()
332                        slicerpop.Append(id, item[0], item[1])
333                        wx.EVT_MENU(self, id, item[2])
334                    except:
335                        msg = "ModelPanel1D.onContextMenu: "
336                        msg += "bad menu item  %s"%sys.exc_value
337                        wx.PostEvent(self.parent, StatusEvent(status=msg))
338                        pass
339                slicerpop.AppendSeparator()
340           
341            id = wx.NewId()
342            slicerpop.Append(id, '&Perform Circular Average')
343            wx.EVT_MENU(self, id, self.onCircular) \
344            # For Masked Data
345            if not plot.mask.all():
346                id = wx.NewId()
347                slicerpop.Append(id, '&Masked Circular Average')
348                wx.EVT_MENU(self, id, self.onMaskedCircular) 
349            id = wx.NewId()
350            slicerpop.Append(id, '&Sector [Q View]')
351            wx.EVT_MENU(self, id, self.onSectorQ) 
352            id = wx.NewId()
353            slicerpop.Append(id, '&Annulus [Phi View ]')
354            wx.EVT_MENU(self, id, self.onSectorPhi) 
355            id = wx.NewId()
356            slicerpop.Append(id, '&Box Sum')
357            wx.EVT_MENU(self, id, self.onBoxSum) 
358            id = wx.NewId()
359            slicerpop.Append(id, '&Box Averaging in Qx')
360            wx.EVT_MENU(self, id, self.onBoxavgX) 
361            id = wx.NewId()
362            slicerpop.Append(id, '&Box Averaging in Qy')
363            wx.EVT_MENU(self, id, self.onBoxavgY) 
364            if self.slicer != None:
365                id = wx.NewId()
366                slicerpop.Append(id, '&Clear Slicer')
367                wx.EVT_MENU(self, id,  self.onClearSlicer) 
368                if self.slicer.__class__.__name__  != "BoxSum":
369                    id = wx.NewId()
370                    slicerpop.Append(id, '&Edit Slicer Parameters')
371                    wx.EVT_MENU(self, id, self._onEditSlicer) 
372            slicerpop.AppendSeparator() 
373           
374        id = wx.NewId()
375        slicerpop.Append(id, '&Edit Graph Label', 'Edit Graph Label')
376        wx.EVT_MENU(self, id, self.onEditLabels)
377        slicerpop.AppendSeparator()
378       
379        id = wx.NewId()
380        slicerpop.Append(id, '&Edit Y Axis Label')
381        wx.EVT_MENU(self, id, self._on_yaxis_label)     
382        id = wx.NewId()
383        slicerpop.Append(id, '&Edit X Axis Label')
384        wx.EVT_MENU(self, id, self._on_xaxis_label)
385        id = wx.NewId()
386        slicerpop.Append(id, '&Toggle Grid On/Off', 'Toggle Grid On/Off')
387        wx.EVT_MENU(self, id, self.onGridOnOff)
388        slicerpop.AppendSeparator()
389       
390        id = wx.NewId()
391        slicerpop.Append(id, '&2D Color Map')
392        wx.EVT_MENU(self, id, self._onEditDetector)
393        slicerpop.AppendSeparator()
394       
395        id = wx.NewId()
396        slicerpop.Append(id, '&Toggle Linear/Log Scale')
397        wx.EVT_MENU(self, id, self._onToggleScale) 
398       
399       
400        slicerpop.AppendSeparator()
401        id = wx.NewId()
402        slicerpop.Append(id, '&Window Title')
403        wx.EVT_MENU(self, id, self.onChangeCaption)
404       
405        try:
406            pos_evt = event.GetPosition()
407            pos = self.ScreenToClient(pos_evt)
408        except:
409            pos_x, pos_y = self.toolbar.GetPositionTuple()
410            pos = (pos_x, pos_y + 5)
411        self.PopupMenu(slicerpop, pos)
412       
413           
414    def onEditLabels(self, event):
415        """
416        Edit legend label
417        """
418        selected_plot = self.plots[self.graph.selected_plottable]
419        label = selected_plot.label
420        dial = TextDialog(None, -1, 'Change Label', label)
421        if dial.ShowModal() == wx.ID_OK:
422            try:
423                FONT = FontProperties()
424                newlabel = dial.getText()
425                font = FONT.copy()
426                font.set_size(dial.getSize())
427                font.set_family(dial.getFamily())
428                font.set_style(dial.getStyle())
429                font.set_weight(dial.getWeight())
430                colour = dial.getColor()
431                if len(newlabel) > 0:
432                    # update Label
433                    selected_plot.label = newlabel
434                    self.graph.title(newlabel)
435                    self.title_label = selected_plot.label
436                    self.title_font = font
437                    self.title_color = colour
438                    ## render the graph
439                    self.subplot.set_title(label=self.title_label,
440                                           fontproperties=self.title_font,
441                                           color=self.title_color)
442                    self._is_changed_legend_label = True
443                    self.subplot.figure.canvas.draw_idle() 
444            except:
445                if self.parent != None:
446                    from sans.guiframe.events import StatusEvent
447                    msg= "Add Text: Error. Check your property values..."
448                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
449                else:
450                    raise
451        dial.Destroy()
452       
453        # Update Graph menu and help string
454        if self.title_label != None:     
455            pos = self.parent._window_menu.FindItem(self.window_caption)
456            helpString = 'Show/Hide Graph: '
457            helpString += (' ' + str(self.title_label) +';')
458            self.parent._window_menu.SetHelpString(pos, helpString)
459
460       
461    def _onEditDetector(self, event):
462        """
463        Allow to view and edits  detector parameters
464       
465        :param event: wx.menu event
466       
467        """
468        import detector_dialog
469        dialog = detector_dialog.DetectorDialog(self, -1,base=self.parent,
470                       reset_zmin_ctl =self.default_zmin_ctl,
471                       reset_zmax_ctl = self.default_zmax_ctl,cmap=self.cmap)
472        ## info of current detector and data2D
473        xnpts = len(self.data2D.x_bins)
474        ynpts = len(self.data2D.y_bins)
475        xmax = max(self.data2D.xmin, self.data2D.xmax)
476        ymax = max(self.data2D.ymin, self.data2D.ymax)
477        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
478        beam = self.data2D.xmin
479        ## set dialog window content
480        dialog.setContent(xnpts=xnpts,ynpts=ynpts,qmax=qmax,
481                           beam=self.data2D.xmin,
482                           zmin = self.zmin_2D,
483                          zmax = self.zmax_2D)
484        if dialog.ShowModal() == wx.ID_OK:
485            evt = dialog.getContent()
486            self.zmin_2D = evt.zmin
487            self.zmax_2D = evt.zmax
488            self.cmap = evt.cmap
489        dialog.Destroy()
490        ## Redraw the current image
491        self.image(data=self.data2D.data,
492                   qx_data=self.data2D.qx_data,
493                   qy_data=self.data2D.qy_data,
494                   xmin= self.data2D.xmin,
495                   xmax= self.data2D.xmax,
496                   ymin= self.data2D.ymin,
497                   ymax= self.data2D.ymax,
498                   zmin= self.zmin_2D,
499                   zmax= self.zmax_2D,
500                   cmap= self.cmap,
501                   color=0, symbol=0, label=self.data2D.name)
502        self.subplot.figure.canvas.draw_idle()
503       
504    def freeze_axes(self):
505        """
506        """
507        self.axes_frozen = True
508       
509    def thaw_axes(self):
510        """
511        """
512        self.axes_frozen = False
513       
514    def onMouseMotion(self,event):
515        """
516        """
517        pass
518   
519    def onWheel(self, event):
520        """
521        """
522        pass 
523     
524    def update(self, draw=True):
525        """
526        Respond to changes in the model by recalculating the
527        profiles and resetting the widgets.
528        """
529        self.draw_plot()
530       
531    def _getEmptySlicerEvent(self):
532        """
533        create an empty slicervent
534        """
535        return SlicerEvent(type=None, params=None, obj_class=None)
536       
537    def _onEVT_INTERNAL(self, event):
538        """
539        Draw the slicer
540       
541        :param event: wx.lib.newevent (SlicerEvent) containing slicer
542            parameter
543           
544        """
545        self._setSlicer(event.slicer)
546           
547    def _setSlicer(self, slicer):
548        """
549        Clear the previous slicer and create a new one.Post an internal
550        event.
551       
552        :param slicer: slicer class to create
553       
554        """
555        ## Clear current slicer
556        if not self.slicer == None: 
557            self.slicer.clear()           
558        ## Create a new slicer   
559        self.slicer_z += 1
560        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
561        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
562        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
563        ## Draw slicer
564        self.update()
565        self.slicer.update()
566        msg = "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__
567        wx.PostEvent(self.parent, StatusEvent(status=msg))
568        # Post slicer event
569        event = self._getEmptySlicerEvent()
570        event.type = self.slicer.__class__.__name__
571        event.obj_class = self.slicer.__class__
572        event.params = self.slicer.get_params()
573        wx.PostEvent(self, event)
574       
575    def onMaskedCircular(self, event):
576        """
577        perform circular averaging on Data2D with mask if it exists
578       
579        :param event: wx.menu event
580       
581        """
582        self.onCircular(event, True)
583       
584    def onCircular(self, event, ismask=False):
585        """
586        perform circular averaging on Data2D
587       
588        :param event: wx.menu event
589       
590        """
591        # Find the best number of bins
592        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
593        npt = math.floor(npt)
594        from sans.dataloader.manipulations import CircularAverage
595        ## compute the maximum radius of data2D
596        self.qmax = max(math.fabs(self.data2D.xmax), 
597                        math.fabs(self.data2D.xmin))
598        self.ymax = max(math.fabs(self.data2D.ymax),
599                        math.fabs(self.data2D.ymin))
600        self.radius = math.sqrt(math.pow(self.qmax, 2)+ math.pow(self.ymax, 2)) 
601        ##Compute beam width
602        bin_width = (self.qmax + self.qmax)/npt
603        ## Create data1D circular average of data2D
604        Circle = CircularAverage(r_min=0, r_max=self.radius, 
605                                 bin_width=bin_width)
606        circ = Circle(self.data2D, ismask=ismask)
607        from sans.guiframe.dataFitting import Data1D
608        if hasattr(circ, "dxl"):
609            dxl = circ.dxl
610        else:
611            dxl = None
612        if hasattr(circ, "dxw"):
613            dxw = circ.dxw
614        else:
615            dxw = None
616
617        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
618        new_plot.dxl = dxl
619        new_plot.dxw = dxw
620        new_plot.name = "Circ avg " + self.data2D.name
621        new_plot.source = self.data2D.source
622        #new_plot.info = self.data2D.info
623        new_plot.interactive = True
624        new_plot.detector = self.data2D.detector
625       
626        ## If the data file does not tell us what the axes are, just assume...
627        new_plot.xaxis("\\rm{Q}", "A^{-1}")
628        if hasattr(self.data2D, "scale") and \
629                    self.data2D.scale == 'linear':
630            new_plot.ytransform = 'y'
631            new_plot.yaxis("\\rm{Residuals} ", "normalized")
632        else:
633            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
634
635        new_plot.group_id = "Circ avg " + self.data2D.name
636        new_plot.id = "Circ avg " + self.data2D.name
637        new_plot.is_data = True
638        self.parent.update_theory(data_id=self.data2D, \
639                                       theory=new_plot)
640        wx.PostEvent(self.parent, 
641                     NewPlotEvent(plot=new_plot, title=new_plot.name))
642       
643    def _onEditSlicer(self, event):
644        """
645        Is available only when a slicer is drawn.Create a dialog
646        window where the user can enter value to reset slicer
647        parameters.
648       
649        :param event: wx.menu event
650       
651        """
652        if self.slicer != None:
653            from SlicerParameters import SlicerParameterPanel
654            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
655            dialog.set_slicer(self.slicer.__class__.__name__,
656                            self.slicer.get_params())
657            if dialog.ShowModal() == wx.ID_OK:
658                dialog.Destroy() 
659       
660    def onSectorQ(self, event):
661        """
662        Perform sector averaging on Q and draw sector slicer
663        """
664        from SectorSlicer import SectorInteractor
665        self.onClearSlicer(event)
666        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
667       
668    def onSectorPhi(self, event):
669        """
670        Perform sector averaging on Phi and draw annulus slicer
671        """
672        from AnnulusSlicer import AnnulusInteractor
673        self.onClearSlicer(event)
674        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
675       
676    def onBoxSum(self, event):
677        """
678        """
679        from boxSum import BoxSum
680        self.onClearSlicer(event)
681        self.slicer_z += 1
682        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
683        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
684        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
685        self.update()
686        self.slicer.update()
687        ## Value used to initially set the slicer panel
688        type = self.slicer.__class__.__name__
689        params = self.slicer.get_params()
690        ## Create a new panel to display results of summation of Data2D
691        from slicerpanel import SlicerPanel
692        new_panel = SlicerPanel(parent=self.parent, id=-1,
693                                    base=self, type=type,
694                                    params=params, style=wx.RAISED_BORDER)
695       
696        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
697                                    str(self.data2D.name)
698        new_panel.window_name = self.slicer.__class__.__name__+ " " + \
699                                    str(self.data2D.name)
700        ## Store a reference of the new created panel
701        self.panel_slicer = new_panel
702        ## save the window_caption of the new panel in the current slicer
703        self.slicer.set_panel_name(name=new_panel.window_caption)
704        ## post slicer panel to guiframe to display it
705        from sans.guiframe.events import SlicerPanelEvent
706        wx.PostEvent(self.parent, SlicerPanelEvent(panel=self.panel_slicer,
707                                                    main_panel=self))
708
709    def onBoxavgX(self,event):
710        """
711        Perform 2D data averaging on Qx
712        Create a new slicer .
713       
714        :param event: wx.menu event
715        """
716        from boxSlicer import BoxInteractorX
717        self.onClearSlicer(event)
718        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
719       
720    def onBoxavgY(self,event):
721        """
722        Perform 2D data averaging on Qy
723        Create a new slicer .
724       
725        :param event: wx.menu event
726       
727        """
728        from boxSlicer import BoxInteractorY
729        self.onClearSlicer(event)
730        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
731       
732    def onClearSlicer(self, event):
733        """
734        Clear the slicer on the plot
735        """
736        if not self.slicer == None:
737            self.slicer.clear()
738            self.subplot.figure.canvas.draw()
739            self.slicer = None
740            # Post slicer None event
741            event = self._getEmptySlicerEvent()
742            wx.PostEvent(self, event)
743           
744    def _onSave(self, evt):
745        """
746        Save a data set to a dat(text) file
747       
748        :param evt: Menu event
749       
750        """
751        id = str(evt.GetId())
752        if self.parent != None:
753            self._default_save_location = self.parent._default_save_location
754        default_name = self.plots[self.graph.selected_plottable].label
755        if default_name.count('.') > 0:
756            default_name = default_name.split('.')[0]
757        default_name += "_out"
758        if id in self.action_ids:         
759           
760            path = None
761            wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
762            dlg = wx.FileDialog(self, "Choose a file",
763                                self._default_save_location,
764                                default_name, wildcard , wx.SAVE)
765           
766            if dlg.ShowModal() == wx.ID_OK:
767                path = dlg.GetPath()
768                # ext_num = 0 for .txt, ext_num = 1 for .xml
769                # This is MAC Fix
770                ext_num = dlg.GetFilterIndex()
771                if ext_num == 0:
772                    format = '.dat'
773                else:
774                    format = ''
775                path = os.path.splitext(path)[0] + format
776                mypath = os.path.basename(path)
777               
778                #TODO: This is bad design. The DataLoader is designed
779                #to recognize extensions.
780                # It should be a simple matter of calling the .
781                #save(file, data, '.xml') method
782                # of the DataLoader.loader.Loader class.
783                from sans.dataloader.loader import  Loader
784                #Instantiate a loader
785                loader = Loader() 
786                data = self.data2D
787
788                format = ".dat"
789                if os.path.splitext(mypath)[1].lower() == format:
790                    # Make sure the ext included in the file name
791                    # especially on MAC
792                    fName = os.path.splitext(path)[0] + format
793                    loader.save(fName, data, format)
794                try:
795                    self._default_save_location = os.path.dirname(path)
796                    self.parent._default_save_location = \
797                                            self._default_save_location
798                except:
799                    pass   
800            dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.