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

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

Added Grid on/off

  • Property mode set to 100644
File size: 29.1 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           
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.subplot.figure.canvas.draw_idle() 
441            except:
442                if self.parent != None:
443                    from sans.guiframe.events import StatusEvent
444                    msg= "Add Text: Error. Check your property values..."
445                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
446                else:
447                    raise
448        dial.Destroy()
449       
450        # Update Graph menu and help string
451        if self.title_label != None:     
452            pos = self.parent._window_menu.FindItem(self.window_caption)
453            helpString = 'Show/Hide Graph: '
454            helpString += (' ' + self.title_label +';')
455            self.parent._window_menu.SetHelpString(pos, helpString)
456
457       
458    def _onEditDetector(self, event):
459        """
460        Allow to view and edits  detector parameters
461       
462        :param event: wx.menu event
463       
464        """
465        import detector_dialog
466        dialog = detector_dialog.DetectorDialog(self, -1,base=self.parent,
467                       reset_zmin_ctl =self.default_zmin_ctl,
468                       reset_zmax_ctl = self.default_zmax_ctl,cmap=self.cmap)
469        ## info of current detector and data2D
470        xnpts = len(self.data2D.x_bins)
471        ynpts = len(self.data2D.y_bins)
472        xmax = max(self.data2D.xmin, self.data2D.xmax)
473        ymax = max(self.data2D.ymin, self.data2D.ymax)
474        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
475        beam = self.data2D.xmin
476        ## set dialog window content
477        dialog.setContent(xnpts=xnpts,ynpts=ynpts,qmax=qmax,
478                           beam=self.data2D.xmin,
479                           zmin = self.zmin_2D,
480                          zmax = self.zmax_2D)
481        if dialog.ShowModal() == wx.ID_OK:
482            evt = dialog.getContent()
483            self.zmin_2D = evt.zmin
484            self.zmax_2D = evt.zmax
485            self.cmap = evt.cmap
486        dialog.Destroy()
487        ## Redraw the current image
488        self.image(data=self.data2D.data,
489                   qx_data=self.data2D.qx_data,
490                   qy_data=self.data2D.qy_data,
491                   xmin= self.data2D.xmin,
492                   xmax= self.data2D.xmax,
493                   ymin= self.data2D.ymin,
494                   ymax= self.data2D.ymax,
495                   zmin= self.zmin_2D,
496                   zmax= self.zmax_2D,
497                   cmap= self.cmap,
498                   color=0, symbol=0, label=self.data2D.name)
499        self.subplot.figure.canvas.draw_idle()
500       
501    def freeze_axes(self):
502        """
503        """
504        self.axes_frozen = True
505       
506    def thaw_axes(self):
507        """
508        """
509        self.axes_frozen = False
510       
511    def onMouseMotion(self,event):
512        """
513        """
514        pass
515   
516    def onWheel(self, event):
517        """
518        """
519        pass 
520     
521    def update(self, draw=True):
522        """
523        Respond to changes in the model by recalculating the
524        profiles and resetting the widgets.
525        """
526        self.draw_plot()
527       
528    def _getEmptySlicerEvent(self):
529        """
530        create an empty slicervent
531        """
532        return SlicerEvent(type=None, params=None, obj_class=None)
533       
534    def _onEVT_INTERNAL(self, event):
535        """
536        Draw the slicer
537       
538        :param event: wx.lib.newevent (SlicerEvent) containing slicer
539            parameter
540           
541        """
542        self._setSlicer(event.slicer)
543           
544    def _setSlicer(self, slicer):
545        """
546        Clear the previous slicer and create a new one.Post an internal
547        event.
548       
549        :param slicer: slicer class to create
550       
551        """
552        ## Clear current slicer
553        if not self.slicer == None: 
554            self.slicer.clear()           
555        ## Create a new slicer   
556        self.slicer_z += 1
557        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
558        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
559        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
560        ## Draw slicer
561        self.update()
562        self.slicer.update()
563        msg = "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__
564        wx.PostEvent(self.parent, StatusEvent(status=msg))
565        # Post slicer event
566        event = self._getEmptySlicerEvent()
567        event.type = self.slicer.__class__.__name__
568        event.obj_class = self.slicer.__class__
569        event.params = self.slicer.get_params()
570        wx.PostEvent(self, event)
571       
572    def onMaskedCircular(self, event):
573        """
574        perform circular averaging on Data2D with mask if it exists
575       
576        :param event: wx.menu event
577       
578        """
579        self.onCircular(event, True)
580       
581    def onCircular(self, event, ismask=False):
582        """
583        perform circular averaging on Data2D
584       
585        :param event: wx.menu event
586       
587        """
588        # Find the best number of bins
589        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
590        npt = math.floor(npt)
591        from sans.dataloader.manipulations import CircularAverage
592        ## compute the maximum radius of data2D
593        self.qmax = max(math.fabs(self.data2D.xmax), 
594                        math.fabs(self.data2D.xmin))
595        self.ymax = max(math.fabs(self.data2D.ymax),
596                        math.fabs(self.data2D.ymin))
597        self.radius = math.sqrt(math.pow(self.qmax, 2)+ math.pow(self.ymax, 2)) 
598        ##Compute beam width
599        bin_width = (self.qmax + self.qmax)/npt
600        ## Create data1D circular average of data2D
601        Circle = CircularAverage(r_min=0, r_max=self.radius, 
602                                 bin_width=bin_width)
603        circ = Circle(self.data2D, ismask=ismask)
604        from sans.guiframe.dataFitting import Data1D
605        if hasattr(circ, "dxl"):
606            dxl = circ.dxl
607        else:
608            dxl = None
609        if hasattr(circ, "dxw"):
610            dxw = circ.dxw
611        else:
612            dxw = None
613
614        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
615        new_plot.dxl = dxl
616        new_plot.dxw = dxw
617        new_plot.name = "Circ avg " + self.data2D.name
618        new_plot.source = self.data2D.source
619        #new_plot.info = self.data2D.info
620        new_plot.interactive = True
621        new_plot.detector = self.data2D.detector
622       
623        ## If the data file does not tell us what the axes are, just assume...
624        new_plot.xaxis("\\rm{Q}", "A^{-1}")
625        if hasattr(self.data2D, "scale") and \
626                    self.data2D.scale == 'linear':
627            new_plot.ytransform = 'y'
628            new_plot.yaxis("\\rm{Residuals} ", "normalized")
629        else:
630            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
631
632        new_plot.group_id = "Circ avg " + self.data2D.name
633        new_plot.id = "Circ avg " + self.data2D.name
634        new_plot.is_data = True
635        wx.PostEvent(self.parent, 
636                     NewPlotEvent(plot=new_plot, title=new_plot.name))
637       
638    def _onEditSlicer(self, event):
639        """
640        Is available only when a slicer is drawn.Create a dialog
641        window where the user can enter value to reset slicer
642        parameters.
643       
644        :param event: wx.menu event
645       
646        """
647        if self.slicer != None:
648            from SlicerParameters import SlicerParameterPanel
649            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
650            dialog.set_slicer(self.slicer.__class__.__name__,
651                            self.slicer.get_params())
652            if dialog.ShowModal() == wx.ID_OK:
653                dialog.Destroy() 
654       
655    def onSectorQ(self, event):
656        """
657        Perform sector averaging on Q and draw sector slicer
658        """
659        from SectorSlicer import SectorInteractor
660        self.onClearSlicer(event)
661        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
662       
663    def onSectorPhi(self, event):
664        """
665        Perform sector averaging on Phi and draw annulus slicer
666        """
667        from AnnulusSlicer import AnnulusInteractor
668        self.onClearSlicer(event)
669        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
670       
671    def onBoxSum(self, event):
672        """
673        """
674        from boxSum import BoxSum
675        self.onClearSlicer(event)
676        self.slicer_z += 1
677        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
678        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
679        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
680        self.update()
681        self.slicer.update()
682        ## Value used to initially set the slicer panel
683        type = self.slicer.__class__.__name__
684        params = self.slicer.get_params()
685        ## Create a new panel to display results of summation of Data2D
686        from slicerpanel import SlicerPanel
687        new_panel = SlicerPanel(parent=self.parent, id=-1,
688                                    base=self, type=type,
689                                    params=params, style=wx.RAISED_BORDER)
690       
691        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
692                                    str(self.data2D.name)
693        new_panel.window_name = self.slicer.__class__.__name__+ " " + \
694                                    str(self.data2D.name)
695        ## Store a reference of the new created panel
696        self.panel_slicer = new_panel
697        ## save the window_caption of the new panel in the current slicer
698        self.slicer.set_panel_name(name=new_panel.window_caption)
699        ## post slicer panel to guiframe to display it
700        from sans.guiframe.events import SlicerPanelEvent
701        wx.PostEvent(self.parent, SlicerPanelEvent(panel=self.panel_slicer,
702                                                    main_panel=self))
703
704    def onBoxavgX(self,event):
705        """
706        Perform 2D data averaging on Qx
707        Create a new slicer .
708       
709        :param event: wx.menu event
710        """
711        from boxSlicer import BoxInteractorX
712        self.onClearSlicer(event)
713        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
714       
715    def onBoxavgY(self,event):
716        """
717        Perform 2D data averaging on Qy
718        Create a new slicer .
719       
720        :param event: wx.menu event
721       
722        """
723        from boxSlicer import BoxInteractorY
724        self.onClearSlicer(event)
725        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
726       
727    def onClearSlicer(self, event):
728        """
729        Clear the slicer on the plot
730        """
731        if not self.slicer == None:
732            self.slicer.clear()
733            self.subplot.figure.canvas.draw()
734            self.slicer = None
735            # Post slicer None event
736            event = self._getEmptySlicerEvent()
737            wx.PostEvent(self, event)
738           
739    def _onSave(self, evt):
740        """
741        Save a data set to a dat(text) file
742       
743        :param evt: Menu event
744       
745        """
746        id = str(evt.GetId())
747        if id in self.action_ids:         
748           
749            path = None
750            wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
751            dlg = wx.FileDialog(self, "Choose a file",
752                                self._default_save_location,
753                                 "", wildcard , wx.SAVE)
754           
755            if dlg.ShowModal() == wx.ID_OK:
756                path = dlg.GetPath()
757                # ext_num = 0 for .txt, ext_num = 1 for .xml
758                # This is MAC Fix
759                ext_num = dlg.GetFilterIndex()
760                if ext_num == 0:
761                    format = '.dat'
762                else:
763                    format = ''
764                path = os.path.splitext(path)[0] + format
765                mypath = os.path.basename(path)
766               
767                #TODO: This is bad design. The DataLoader is designed
768                #to recognize extensions.
769                # It should be a simple matter of calling the .
770                #save(file, data, '.xml') method
771                # of the DataLoader.loader.Loader class.
772                from sans.dataloader.loader import  Loader
773                #Instantiate a loader
774                loader = Loader() 
775                data = self.data2D
776
777                format = ".dat"
778                if os.path.splitext(mypath)[1].lower() == format:
779                    # Make sure the ext included in the file name
780                    # especially on MAC
781                    fName = os.path.splitext(path)[0] + format
782                    loader.save(fName, data, format)
783                try:
784                    self._default_save_location = os.path.dirname(path)
785                except:
786                    pass   
787            dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.