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

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

minor fix in saving as data

  • Property mode set to 100644
File size: 29.7 KB
RevLine 
[1bf33c1]1
[d955bf19]2################################################################################
3#This software was developed by the University of Tennessee as part of the
4#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
5#project funded by the US National Science Foundation.
6#
7#See the license text in license.txt
8#
9#copyright 2008, University of Tennessee
10################################################################################
[1bf33c1]11
12
13import wx
[32c0841]14import sys
[ed8ad21]15import os
[32c0841]16import math
[003fa4e]17import numpy
[0d9dae8]18import pylab
[1bf33c1]19import danse.common.plottools
20from danse.common.plottools.PlotPanel import PlotPanel
[4ac8556]21from danse.common.plottools.plottables import Graph
[49a470d]22from danse.common.plottools.TextDialog import TextDialog
[55a0dc1]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
[a07e72f]27from sans.guiframe.events import PanelOnFocusEvent
[55a0dc1]28from sans.guiframe.events import SlicerEvent
[0d9dae8]29from sans.guiframe.utils import PanelMenu
[1bf33c1]30from binder import BindArtist
31from Plotter1D import ModelPanel1D
[32c0841]32from danse.common.plottools.toolbar import NavigationToolBar
[4ac8556]33from sans.guiframe.dataFitting import Data1D
[49a470d]34from matplotlib.font_manager import FontProperties
[32c0841]35(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
[0d9dae8]36
37DEFAULT_QMAX = 0.05
[1bf33c1]38DEFAULT_QSTEP = 0.001
39DEFAULT_BEAM = 0.005
[ef0c170]40BIN_WIDTH = 1.0
[32c0841]41
[d955bf19]42
[ac8671e]43class NavigationToolBar2D(NavigationToolBar):
[d955bf19]44    """
45    """
[ac8671e]46    def __init__(self, canvas, parent=None):
47        NavigationToolBar.__init__(self, canvas=canvas, parent=parent)
48       
49    def delete_option(self):
50        """
[d955bf19]51        remove default toolbar item
[ac8671e]52        """
53        #delete reset button
54        self.DeleteToolByPos(0) 
55        #delete dragging
[88ca6db]56        self.DeleteToolByPos(2) 
[ac8671e]57        #delete unwanted button that configures subplot parameters
58        self.DeleteToolByPos(4)
59       
60    def add_option(self):
61        """
[d955bf19]62        add item to the toolbar
[ac8671e]63        """
[dc51a7f]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)
[ac8671e]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):
[1bf33c1]81    """
[d955bf19]82    Plot panel for use with the GUI manager
[1bf33c1]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   
[32c0841]96    def __init__(self, parent, id=-1, data2d=None, color = None,
97                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
[1bf33c1]98        """
[d955bf19]99        Initialize the panel
[1bf33c1]100        """
[32c0841]101        ModelPanel1D.__init__(self, parent, id=id, style=style, **kwargs)
[1bf33c1]102       
103        ## Reference to the parent window
104        self.parent = parent
[6c0568b]105        ## Dictionary containing Plottables
[1bf33c1]106        self.plots = {}
[6c0568b]107        ## Save reference of the current plotted
108        self.data2D = data2d
[1bf33c1]109        ## Unique ID (from gui_manager)
110        self.uid = None
111        ## Action IDs for internal call-backs
112        self.action_ids = {}
[6c0568b]113        ## Create Artist and bind it
[1bf33c1]114        self.connect = BindArtist(self.subplot.figure)
[6c0568b]115        ## Beam stop
[1bf33c1]116        self.beamstop_radius = DEFAULT_BEAM
[6c0568b]117        ## to set the order of lines drawn first.
[f15ed33]118        self.slicer_z = 5
[6c0568b]119        ## Reference to the current slicer
[1bf33c1]120        self.slicer = None
[6c0568b]121        ## event to send slicer info
[d468daa]122        self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
[1bf33c1]123       
[6c0568b]124        self.axes_frozen = False
125        ## panel that contains result from slicer motion (ex: Boxsum info)
[32c0841]126        self.panel_slicer = None
[49a470d]127        self.title_label = None
128        self.title_font = None
129        self.title_color = 'black'
[1bf33c1]130        ## Graph       
131        self.graph = Graph()
132        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
[32c0841]133        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
[1bf33c1]134        self.graph.render(self)
[8dfdd20]135        ## store default value of zmin and zmax
136        self.default_zmin_ctl = self.zmin_2D
137        self.default_zmax_ctl = self.zmax_2D
[ac8671e]138       
[a07e72f]139    def onLeftDown(self, event): 
140        """
141        left button down and ready to drag
142       
143        """
144        # Check that the LEFT button was pressed
[53cf669]145        PlotPanel.onLeftDown(self, event)   
[e85e2bc]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))
[a07e72f]153        self.plottable_selected(self.data2D.id)
154        self._manager.set_panel_on_focus(self)
155        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
156       
[ac8671e]157    def add_toolbar(self):
158        """
[d955bf19]159        add toolbar
[ac8671e]160        """
161        self.enable_toolbar = True
[32c0841]162        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
[ac8671e]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))
[32c0841]169        self.sizer.Add(self.toolbar, 0, wx.LEFT|wx.EXPAND)
[ac8671e]170        # update the axes menu on the toolbar
171        self.toolbar.update()
172         
[a07e72f]173    def plot_data(self, data):
[1bf33c1]174        """
[d955bf19]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
[1bf33c1]182        """
[e4a703a]183        xlo = None
184        xhi = None
185        ylo = None 
186        yhi = None
[6c0568b]187        ## Update self.data2d with the current plot
[857d00f]188        self.data2D = data
[a07e72f]189        if data.id in self.plots.keys():
190            #replace
[e4a703a]191            xlo, xhi = self.subplot.get_xlim()
192            ylo, yhi = self.subplot.get_ylim()
[a07e72f]193            self.graph.replace(data)
194            self.plots[data.id] = data
[ab8f936]195        else:
[a07e72f]196            self.plots[data.id] = data
197            self.graph.add(self.plots[data.id]) 
[ac9a5f6]198            # update qmax with the new xmax of data plotted
[a07e72f]199            self.qmax = data.xmax
[4b91fd1]200           
[32c0841]201        self.slicer = None
[1bf33c1]202        # Check axis labels
203        #TODO: Should re-factor this
[6c0568b]204        ## render the graph with its new content
[7fff5cd]205               
206        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
[49a470d]207        if len(data.detector) < 1: 
[a07e72f]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'
[857d00f]213       
214        # graph properties
[a07e72f]215        self.graph.xaxis(data._xaxis, data._xunit)
216        self.graph.yaxis(data._yaxis, data._yunit)
[36288ca]217        if self._is_changed_legend_label:   
218                data.label = self.title_label
[49a470d]219       
[fe48fcc]220        if data.label == None:
221            data.label = data.name
[49a470d]222           
223        if not self.title_font:
224            self.graph.title(data.label)
225            self.graph.render(self)
[857d00f]226            # Set the axis labels on subplot
227            self._set_axis_labels()
[49a470d]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       
[857d00f]237       
[8dfdd20]238        ## store default value of zmin and zmax
239        self.default_zmin_ctl = self.zmin_2D
240        self.default_zmax_ctl = self.zmax_2D
[7022fdc]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       
[e4a703a]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))     
[fe48fcc]251                self.subplot.set_ylim((ylo, yhi)) 
252            else: 
253                self.toolbar.update()
[7022fdc]254                self._is_zoomed = False
[53cf669]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       
[857d00f]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       
[1bf33c1]285    def onContextMenu(self, event):
286        """
[d955bf19]287        2D plot context menu
288       
289        :param event: wx context event
[15550f4]290       
[d955bf19]291        """
[1bf33c1]292        slicerpop = PanelMenu()
293        slicerpop.set_plots(self.plots)
294        slicerpop.set_graph(self.graph)
[9a585d0]295             
296        id = wx.NewId()
[6d727ae]297        slicerpop.Append(id, '&Save Image')
[9a585d0]298        wx.EVT_MENU(self, id, self.onSaveImage)
299       
300        id = wx.NewId()
[6d727ae]301        slicerpop.Append(id,'&Print Image', 'Print image')
[9a585d0]302        wx.EVT_MENU(self, id, self.onPrint)
303       
[1ce365f8]304        id = wx.NewId()
[6d727ae]305        slicerpop.Append(id,'&Print Preview', 'Print preview')
[1ce365f8]306        wx.EVT_MENU(self, id, self.onPrinterPreview)
[003fa4e]307
308        id = wx.NewId()
309        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
310        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
[c5a769e]311        slicerpop.AppendSeparator()
[ed8ad21]312        # saving data
313        plot = self.data2D
314        id = wx.NewId()
315        name = plot.name
[c17760d]316        slicerpop.Append(id, "&Save as a File (DAT)" )
[ed8ad21]317        self.action_ids[str(id)] = plot
318        wx.EVT_MENU(self, id, self._onSave)
319
[9a585d0]320        slicerpop.AppendSeparator()
[7fff5cd]321        if len(self.data2D.detector) == 1:       
[0e13148]322           
[a07e72f]323            item_list = self.parent.get_context_menu(self)
[6d727ae]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
[32c0841]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()
[0e13148]338           
[15550f4]339            id = wx.NewId()
[c17760d]340            slicerpop.Append(id, '&Perform Circular Average')
[6d727ae]341            wx.EVT_MENU(self, id, self.onCircular) \
342            # For Masked Data
343            if not plot.mask.all():
344                id = wx.NewId()
[c17760d]345                slicerpop.Append(id, '&Masked Circular Average')
[6d727ae]346                wx.EVT_MENU(self, id, self.onMaskedCircular) 
[15550f4]347            id = wx.NewId()
[c17760d]348            slicerpop.Append(id, '&Sector [Q View]')
[15550f4]349            wx.EVT_MENU(self, id, self.onSectorQ) 
350            id = wx.NewId()
[c17760d]351            slicerpop.Append(id, '&Annulus [Phi View ]')
[15550f4]352            wx.EVT_MENU(self, id, self.onSectorPhi) 
[92c2345]353            id = wx.NewId()
[15550f4]354            slicerpop.Append(id, '&Box Sum')
355            wx.EVT_MENU(self, id, self.onBoxSum) 
356            id = wx.NewId()
[c17760d]357            slicerpop.Append(id, '&Box Averaging in Qx')
[15550f4]358            wx.EVT_MENU(self, id, self.onBoxavgX) 
359            id = wx.NewId()
[c17760d]360            slicerpop.Append(id, '&Box Averaging in Qy')
[15550f4]361            wx.EVT_MENU(self, id, self.onBoxavgY) 
[32c0841]362            if self.slicer != None:
[eba08f1a]363                id = wx.NewId()
[c17760d]364                slicerpop.Append(id, '&Clear Slicer')
[15550f4]365                wx.EVT_MENU(self, id,  self.onClearSlicer) 
[32c0841]366                if self.slicer.__class__.__name__  != "BoxSum":
[15550f4]367                    id = wx.NewId()
368                    slicerpop.Append(id, '&Edit Slicer Parameters')
369                    wx.EVT_MENU(self, id, self._onEditSlicer) 
370            slicerpop.AppendSeparator() 
[fe48fcc]371           
372        id = wx.NewId()
[dc51a7f]373        slicerpop.Append(id, '&Edit Graph Label', 'Edit Graph Label')
[fe48fcc]374        wx.EVT_MENU(self, id, self.onEditLabels)
375        slicerpop.AppendSeparator()
376       
[0e13148]377        id = wx.NewId()
[5637362]378        slicerpop.Append(id, '&Edit Y Axis Label')
[857d00f]379        wx.EVT_MENU(self, id, self._on_yaxis_label)     
380        id = wx.NewId()
[5637362]381        slicerpop.Append(id, '&Edit X Axis Label')
[857d00f]382        wx.EVT_MENU(self, id, self._on_xaxis_label)
[5637362]383        id = wx.NewId()
384        slicerpop.Append(id, '&Toggle Grid On/Off', 'Toggle Grid On/Off')
385        wx.EVT_MENU(self, id, self.onGridOnOff)
[857d00f]386        slicerpop.AppendSeparator()
387       
388        id = wx.NewId()
[52f3c98]389        slicerpop.Append(id, '&2D Color Map')
[32c0841]390        wx.EVT_MENU(self, id, self._onEditDetector)
[857d00f]391        slicerpop.AppendSeparator()
392       
[1bf33c1]393        id = wx.NewId()
[c17760d]394        slicerpop.Append(id, '&Toggle Linear/Log Scale')
[1bf33c1]395        wx.EVT_MENU(self, id, self._onToggleScale) 
[53cf669]396       
397       
398        slicerpop.AppendSeparator()
399        id = wx.NewId()
400        slicerpop.Append(id, '&Window Title')
401        wx.EVT_MENU(self, id, self.onChangeCaption)
402       
[dc51a7f]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)
[1bf33c1]409        self.PopupMenu(slicerpop, pos)
[37c36d9]410       
[fe48fcc]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
[49a470d]418        dial = TextDialog(None, -1, 'Change Label', label)
[fe48fcc]419        if dial.ShowModal() == wx.ID_OK:
[49a470d]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:
[53cf669]430                    # update Label
[49a470d]431                    selected_plot.label = newlabel
[53cf669]432                    self.graph.title(newlabel)
[49a470d]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)
[36288ca]440                    self._is_changed_legend_label = True
[49a470d]441                    self.subplot.figure.canvas.draw_idle() 
442            except:
443                if self.parent != None:
444                    from sans.guiframe.events import StatusEvent
445                    msg= "Add Text: Error. Check your property values..."
446                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
447                else:
448                    raise
[fe48fcc]449        dial.Destroy()
[53cf669]450       
451        # Update Graph menu and help string
452        if self.title_label != None:     
453            pos = self.parent._window_menu.FindItem(self.window_caption)
454            helpString = 'Show/Hide Graph: '
455            helpString += (' ' + self.title_label +';')
456            self.parent._window_menu.SetHelpString(pos, helpString)
[49a470d]457
[fe48fcc]458       
[ea290ee]459    def _onEditDetector(self, event):
[6d920cd]460        """
[d955bf19]461        Allow to view and edits  detector parameters
462       
463        :param event: wx.menu event
464       
[6d920cd]465        """
[ea290ee]466        import detector_dialog
[8dfdd20]467        dialog = detector_dialog.DetectorDialog(self, -1,base=self.parent,
468                       reset_zmin_ctl =self.default_zmin_ctl,
469                       reset_zmax_ctl = self.default_zmax_ctl,cmap=self.cmap)
[6c0568b]470        ## info of current detector and data2D
[ea290ee]471        xnpts = len(self.data2D.x_bins)
472        ynpts = len(self.data2D.y_bins)
473        xmax = max(self.data2D.xmin, self.data2D.xmax)
474        ymax = max(self.data2D.ymin, self.data2D.ymax)
[32c0841]475        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
[ea290ee]476        beam = self.data2D.xmin
[6c0568b]477        ## set dialog window content
[ea290ee]478        dialog.setContent(xnpts=xnpts,ynpts=ynpts,qmax=qmax,
479                           beam=self.data2D.xmin,
480                           zmin = self.zmin_2D,
481                          zmax = self.zmax_2D)
482        if dialog.ShowModal() == wx.ID_OK:
483            evt = dialog.getContent()
484            self.zmin_2D = evt.zmin
485            self.zmax_2D = evt.zmax
[32c0841]486            self.cmap = evt.cmap
[ea290ee]487        dialog.Destroy()
[6c0568b]488        ## Redraw the current image
[32c0841]489        self.image(data=self.data2D.data,
[20b6760]490                   qx_data=self.data2D.qx_data,
491                   qy_data=self.data2D.qy_data,
[ea290ee]492                   xmin= self.data2D.xmin,
493                   xmax= self.data2D.xmax,
494                   ymin= self.data2D.ymin,
495                   ymax= self.data2D.ymax,
496                   zmin= self.zmin_2D,
497                   zmax= self.zmax_2D,
[8dfdd20]498                   cmap= self.cmap,
[32c0841]499                   color=0, symbol=0, label=self.data2D.name)
[ea290ee]500        self.subplot.figure.canvas.draw_idle()
[1bf33c1]501       
502    def freeze_axes(self):
[d955bf19]503        """
504        """
[1bf33c1]505        self.axes_frozen = True
506       
507    def thaw_axes(self):
[d955bf19]508        """
509        """
[1bf33c1]510        self.axes_frozen = False
511       
512    def onMouseMotion(self,event):
[d955bf19]513        """
514        """
[1bf33c1]515        pass
[d955bf19]516   
[1bf33c1]517    def onWheel(self, event):
[d955bf19]518        """
519        """
[6c0568b]520        pass 
521     
[1bf33c1]522    def update(self, draw=True):
523        """
[d955bf19]524        Respond to changes in the model by recalculating the
525        profiles and resetting the widgets.
[1bf33c1]526        """
[6d727ae]527        self.draw_plot()
[1bf33c1]528       
529    def _getEmptySlicerEvent(self):
[6c0568b]530        """
[d955bf19]531        create an empty slicervent
[6c0568b]532        """
[32c0841]533        return SlicerEvent(type=None, params=None, obj_class=None)
[d955bf19]534       
[1bf33c1]535    def _onEVT_INTERNAL(self, event):
536        """
[d955bf19]537        Draw the slicer
538       
539        :param event: wx.lib.newevent (SlicerEvent) containing slicer
[6c0568b]540            parameter
[d955bf19]541           
[1bf33c1]542        """
543        self._setSlicer(event.slicer)
544           
545    def _setSlicer(self, slicer):
[6c0568b]546        """
[d955bf19]547        Clear the previous slicer and create a new one.Post an internal
548        event.
549       
550        :param slicer: slicer class to create
551       
[6c0568b]552        """
553        ## Clear current slicer
[1bf33c1]554        if not self.slicer == None: 
555            self.slicer.clear()           
[6c0568b]556        ## Create a new slicer   
[1bf33c1]557        self.slicer_z += 1
558        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
[240c805]559        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
560        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
[6c0568b]561        ## Draw slicer
[1bf33c1]562        self.update()
563        self.slicer.update()
[32c0841]564        msg = "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__
565        wx.PostEvent(self.parent, StatusEvent(status=msg))
[1bf33c1]566        # Post slicer event
567        event = self._getEmptySlicerEvent()
568        event.type = self.slicer.__class__.__name__
569        event.obj_class = self.slicer.__class__
570        event.params = self.slicer.get_params()
[d468daa]571        wx.PostEvent(self, event)
[6d727ae]572       
573    def onMaskedCircular(self, event):
574        """
575        perform circular averaging on Data2D with mask if it exists
576       
577        :param event: wx.menu event
578       
579        """
580        self.onCircular(event, True)
581       
582    def onCircular(self, event, ismask=False):
[1bf33c1]583        """
[d955bf19]584        perform circular averaging on Data2D
585       
586        :param event: wx.menu event
587       
[1bf33c1]588        """
[003fa4e]589        # Find the best number of bins
590        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
591        npt = math.floor(npt)
[fe857e2]592        from sans.dataloader.manipulations import CircularAverage
[6c0568b]593        ## compute the maximum radius of data2D
[32c0841]594        self.qmax = max(math.fabs(self.data2D.xmax), 
595                        math.fabs(self.data2D.xmin))
596        self.ymax = max(math.fabs(self.data2D.ymax),
597                        math.fabs(self.data2D.ymin))
598        self.radius = math.sqrt(math.pow(self.qmax, 2)+ math.pow(self.ymax, 2)) 
[6c0568b]599        ##Compute beam width
[003fa4e]600        bin_width = (self.qmax + self.qmax)/npt
[6c0568b]601        ## Create data1D circular average of data2D
[32c0841]602        Circle = CircularAverage(r_min=0, r_max=self.radius, 
603                                 bin_width=bin_width)
[6d727ae]604        circ = Circle(self.data2D, ismask=ismask)
[1bf33c1]605        from sans.guiframe.dataFitting import Data1D
[32c0841]606        if hasattr(circ, "dxl"):
607            dxl = circ.dxl
[1bf33c1]608        else:
[32c0841]609            dxl = None
610        if hasattr(circ, "dxw"):
611            dxw = circ.dxw
[1bf33c1]612        else:
[32c0841]613            dxw = None
[003fa4e]614
615        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
[32c0841]616        new_plot.dxl = dxl
617        new_plot.dxw = dxw
618        new_plot.name = "Circ avg " + self.data2D.name
619        new_plot.source = self.data2D.source
620        #new_plot.info = self.data2D.info
[1bf33c1]621        new_plot.interactive = True
[32c0841]622        new_plot.detector = self.data2D.detector
[6d727ae]623       
[6c0568b]624        ## If the data file does not tell us what the axes are, just assume...
[32c0841]625        new_plot.xaxis("\\rm{Q}", "A^{-1}")
[2ca51f44]626        if hasattr(self.data2D, "scale") and \
627                    self.data2D.scale == 'linear':
628            new_plot.ytransform = 'y'
629            new_plot.yaxis("\\rm{Residuals} ", "normalized")
[6d727ae]630        else:
631            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
632
[32c0841]633        new_plot.group_id = "Circ avg " + self.data2D.name
634        new_plot.id = "Circ avg " + self.data2D.name
635        new_plot.is_data = True
[13382fc7]636        self.parent.update_theory(data_id=self.data2D, \
637                                       theory=new_plot)
[32c0841]638        wx.PostEvent(self.parent, 
639                     NewPlotEvent(plot=new_plot, title=new_plot.name))
[ef0c170]640       
[1bf33c1]641    def _onEditSlicer(self, event):
[6c0568b]642        """
[d955bf19]643        Is available only when a slicer is drawn.Create a dialog
644        window where the user can enter value to reset slicer
645        parameters.
646       
647        :param event: wx.menu event
648       
[6c0568b]649        """
[32c0841]650        if self.slicer != None:
[1bf33c1]651            from SlicerParameters import SlicerParameterPanel
[4f8a00c]652            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
[1bf33c1]653            dialog.set_slicer(self.slicer.__class__.__name__,
654                            self.slicer.get_params())
655            if dialog.ShowModal() == wx.ID_OK:
656                dialog.Destroy() 
657       
658    def onSectorQ(self, event):
659        """
[d955bf19]660        Perform sector averaging on Q and draw sector slicer
[1bf33c1]661        """
[ef0c170]662        from SectorSlicer import SectorInteractor
[1bf33c1]663        self.onClearSlicer(event)
[32c0841]664        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
[1bf33c1]665       
666    def onSectorPhi(self, event):
667        """
[d955bf19]668        Perform sector averaging on Phi and draw annulus slicer
[1bf33c1]669        """
[ef0c170]670        from AnnulusSlicer import AnnulusInteractor
[1bf33c1]671        self.onClearSlicer(event)
[32c0841]672        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
[1bf33c1]673       
[d955bf19]674    def onBoxSum(self, event):
675        """
676        """
[7ab9241]677        from boxSum import BoxSum
678        self.onClearSlicer(event)
[54cc36a]679        self.slicer_z += 1
680        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
681        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
682        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
683        self.update()
684        self.slicer.update()
[6c0568b]685        ## Value used to initially set the slicer panel
686        type = self.slicer.__class__.__name__
687        params = self.slicer.get_params()
688        ## Create a new panel to display results of summation of Data2D
[8a7a21b]689        from slicerpanel import SlicerPanel
[32c0841]690        new_panel = SlicerPanel(parent=self.parent, id=-1,
691                                    base=self, type=type,
692                                    params=params, style=wx.RAISED_BORDER)
693       
694        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
695                                    str(self.data2D.name)
696        new_panel.window_name = self.slicer.__class__.__name__+ " " + \
697                                    str(self.data2D.name)
[6c0568b]698        ## Store a reference of the new created panel
[32c0841]699        self.panel_slicer = new_panel
[6c0568b]700        ## save the window_caption of the new panel in the current slicer
[32c0841]701        self.slicer.set_panel_name(name=new_panel.window_caption)
[6c0568b]702        ## post slicer panel to guiframe to display it
[55a0dc1]703        from sans.guiframe.events import SlicerPanelEvent
[32c0841]704        wx.PostEvent(self.parent, SlicerPanelEvent(panel=self.panel_slicer,
705                                                    main_panel=self))
[6c0568b]706
[8a7a21b]707    def onBoxavgX(self,event):
[6c0568b]708        """
[d955bf19]709        Perform 2D data averaging on Qx
710        Create a new slicer .
711       
712        :param event: wx.menu event
[6c0568b]713        """
[8a7a21b]714        from boxSlicer import BoxInteractorX
[38224f10]715        self.onClearSlicer(event)
[32c0841]716        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
[d468daa]717       
[8a7a21b]718    def onBoxavgY(self,event):
[6c0568b]719        """
[d955bf19]720        Perform 2D data averaging on Qy
721        Create a new slicer .
722       
723        :param event: wx.menu event
724       
[6c0568b]725        """
[8a7a21b]726        from boxSlicer import BoxInteractorY
727        self.onClearSlicer(event)
[32c0841]728        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
[6c0568b]729       
[1bf33c1]730    def onClearSlicer(self, event):
731        """
[d955bf19]732        Clear the slicer on the plot
[1bf33c1]733        """
[32c0841]734        if not self.slicer == None:
[1bf33c1]735            self.slicer.clear()
736            self.subplot.figure.canvas.draw()
737            self.slicer = None
738            # Post slicer None event
739            event = self._getEmptySlicerEvent()
[d468daa]740            wx.PostEvent(self, event)
[ed8ad21]741           
742    def _onSave(self, evt):
743        """
744        Save a data set to a dat(text) file
745       
746        :param evt: Menu event
747       
748        """
749        id = str(evt.GetId())
[c553b18]750        if self.parent != None:
751            self._default_save_location = self.parent._default_save_location
[3858e0f]752        default_name = self.plots[self.graph.selected_plottable].label
753        if default_name.count('.') > 0:
754            default_name = default_name.split('.')[0]
755        default_name += "_out"
[ed8ad21]756        if id in self.action_ids:         
757           
758            path = None
759            wildcard = "IGOR/DAT 2D file in Q_map (*.dat)|*.DAT"
760            dlg = wx.FileDialog(self, "Choose a file",
761                                self._default_save_location,
[3858e0f]762                                default_name, wildcard , wx.SAVE)
[ed8ad21]763           
764            if dlg.ShowModal() == wx.ID_OK:
765                path = dlg.GetPath()
[ad1e49c]766                # ext_num = 0 for .txt, ext_num = 1 for .xml
767                # This is MAC Fix
768                ext_num = dlg.GetFilterIndex()
769                if ext_num == 0:
770                    format = '.dat'
771                else:
772                    format = ''
773                path = os.path.splitext(path)[0] + format
[ed8ad21]774                mypath = os.path.basename(path)
775               
776                #TODO: This is bad design. The DataLoader is designed
777                #to recognize extensions.
778                # It should be a simple matter of calling the .
779                #save(file, data, '.xml') method
780                # of the DataLoader.loader.Loader class.
[fe857e2]781                from sans.dataloader.loader import  Loader
[ed8ad21]782                #Instantiate a loader
783                loader = Loader() 
784                data = self.data2D
785
786                format = ".dat"
787                if os.path.splitext(mypath)[1].lower() == format:
[959981b]788                    # Make sure the ext included in the file name
789                    # especially on MAC
790                    fName = os.path.splitext(path)[0] + format
791                    loader.save(fName, data, format)
[ed8ad21]792                try:
793                    self._default_save_location = os.path.dirname(path)
[c553b18]794                    self.parent._default_save_location = \
795                                            self._default_save_location
[ed8ad21]796                except:
797                    pass   
798            dlg.Destroy()
Note: See TracBrowser for help on using the repository browser.