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

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

put back the x-y pos on left-click

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