source: sasview/src/sans/guiframe/local_perspectives/plotting/Plotter2D.py @ 8f52edd

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 8f52edd was f468791, checked in by Mathieu Doucet <doucetm@…>, 11 years ago

Move plottools under sans

  • Property mode set to 100644
File size: 31.0 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
15import math
[003fa4e]16import numpy
[f468791]17from sans.plottools.PlotPanel import PlotPanel
18from sans.plottools.plottables import Graph
19from sans.plottools.TextDialog import TextDialog
[55a0dc1]20from sans.guiframe.events import StatusEvent
21from sans.guiframe.events import NewPlotEvent
[a07e72f]22from sans.guiframe.events import PanelOnFocusEvent
[55a0dc1]23from sans.guiframe.events import SlicerEvent
[0d9dae8]24from sans.guiframe.utils import PanelMenu
[294a7bc]25from  sans.guiframe.local_perspectives.plotting.binder import BindArtist
[1bf33c1]26from Plotter1D import ModelPanel1D
[f468791]27from sans.plottools.toolbar import NavigationToolBar
[49a470d]28from matplotlib.font_manager import FontProperties
[8a687cfd]29from graphAppearance import graphAppearance
[32c0841]30(InternalEvent, EVT_INTERNAL) = wx.lib.newevent.NewEvent()
[0d9dae8]31
32DEFAULT_QMAX = 0.05
[1bf33c1]33DEFAULT_QSTEP = 0.001
34DEFAULT_BEAM = 0.005
[ef0c170]35BIN_WIDTH = 1.0
[32c0841]36
[d955bf19]37
[8a687cfd]38def find_key(dic, val):
39    """return the key of dictionary dic given the value"""
40    return [k for k, v in dic.iteritems() if v == val][0]
41
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        self.parent = parent
[ae84427]103        ## Reference to the parent window
104        if hasattr(parent, "parent"):
105            self.parent = self.parent.parent
[6c0568b]106        ## Dictionary containing Plottables
[1bf33c1]107        self.plots = {}
[6c0568b]108        ## Save reference of the current plotted
109        self.data2D = data2d
[1bf33c1]110        ## Unique ID (from gui_manager)
111        self.uid = None
112        ## Action IDs for internal call-backs
113        self.action_ids = {}
[6c0568b]114        ## Create Artist and bind it
[1bf33c1]115        self.connect = BindArtist(self.subplot.figure)
[6c0568b]116        ## Beam stop
[1bf33c1]117        self.beamstop_radius = DEFAULT_BEAM
[6c0568b]118        ## to set the order of lines drawn first.
[f15ed33]119        self.slicer_z = 5
[6c0568b]120        ## Reference to the current slicer
[1bf33c1]121        self.slicer = None
[6c0568b]122        ## event to send slicer info
[d468daa]123        self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)
[1bf33c1]124       
[6c0568b]125        self.axes_frozen = False
126        ## panel that contains result from slicer motion (ex: Boxsum info)
[32c0841]127        self.panel_slicer = None
[49a470d]128        self.title_label = None
129        self.title_font = None
130        self.title_color = 'black'
[1bf33c1]131        ## Graph       
132        self.graph = Graph()
133        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
[32c0841]134        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
[1bf33c1]135        self.graph.render(self)
[8dfdd20]136        ## store default value of zmin and zmax
137        self.default_zmin_ctl = self.zmin_2D
138        self.default_zmax_ctl = self.zmax_2D
[3e001f9]139
140    def on_plot_qrange(self, event=None):
141        """
142        On Qmin Qmax vertical line event
143        """
144        # Not implemented
145        if event == None:
146            return
147        event.Skip() 
148                       
[a07e72f]149    def onLeftDown(self, event): 
150        """
151        left button down and ready to drag
152       
153        """
154        # Check that the LEFT button was pressed
[53cf669]155        PlotPanel.onLeftDown(self, event)   
[e85e2bc]156        ax = event.inaxes
157        if ax != None:
158            # data coordinate position
159            pos_x = "%8.3g"% event.xdata
160            pos_y = "%8.3g"% event.ydata
161            position = "x: %s    y: %s" % (pos_x, pos_y)
162            wx.PostEvent(self.parent, StatusEvent(status=position))
[a07e72f]163        self.plottable_selected(self.data2D.id)
164        self._manager.set_panel_on_focus(self)
165        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
166       
[ac8671e]167    def add_toolbar(self):
168        """
[d955bf19]169        add toolbar
[ac8671e]170        """
171        self.enable_toolbar = True
[32c0841]172        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
[ac8671e]173        self.toolbar.Realize()
174        # On Windows platform, default window size is incorrect, so set
175        # toolbar width to figure width.
176        tw, th = self.toolbar.GetSizeTuple()
177        fw, fh = self.canvas.GetSizeTuple()
178        self.toolbar.SetSize(wx.Size(fw, th))
[32c0841]179        self.sizer.Add(self.toolbar, 0, wx.LEFT|wx.EXPAND)
[ac8671e]180        # update the axes menu on the toolbar
181        self.toolbar.update()
182         
[a07e72f]183    def plot_data(self, data):
[1bf33c1]184        """
[d955bf19]185        Data is ready to be displayed
186       
187        :TODO: this name should be changed to something more appropriate
188             Don't forget that changing this name will mean changing code
189             in plotting.py
190         
191        :param event: data event
[1bf33c1]192        """
[e4a703a]193        xlo = None
194        xhi = None
195        ylo = None 
196        yhi = None
[b837e1f]197        if data.__class__.__name__ == 'Data1D':
198            return
[6c0568b]199        ## Update self.data2d with the current plot
[857d00f]200        self.data2D = data
[a07e72f]201        if data.id in self.plots.keys():
202            #replace
[e4a703a]203            xlo, xhi = self.subplot.get_xlim()
204            ylo, yhi = self.subplot.get_ylim()
[a07e72f]205            self.graph.replace(data)
206            self.plots[data.id] = data
[ab8f936]207        else:
[a07e72f]208            self.plots[data.id] = data
209            self.graph.add(self.plots[data.id]) 
[ac9a5f6]210            # update qmax with the new xmax of data plotted
[2778c4f]211            self.qmax = data.xmax 
[32c0841]212        self.slicer = None
[1bf33c1]213        # Check axis labels
214        #TODO: Should re-factor this
[2778c4f]215        ## render the graph with its new content   
[7fff5cd]216        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
[49a470d]217        if len(data.detector) < 1: 
[a07e72f]218            if len(data._xunit) < 1 and len(data._yunit) < 1:
219                data._xaxis = '\\rm{x}'
220                data._yaxis = '\\rm{y}'
221                data._xunit = 'pixel'
222                data._yunit = 'pixel'
[857d00f]223        # graph properties
[a07e72f]224        self.graph.xaxis(data._xaxis, data._xunit)
225        self.graph.yaxis(data._yaxis, data._yunit)
[36288ca]226        if self._is_changed_legend_label:   
227                data.label = self.title_label
[fe48fcc]228        if data.label == None:
[2778c4f]229            data.label = data.name   
[49a470d]230        if not self.title_font:
231            self.graph.title(data.label)
232            self.graph.render(self)
[857d00f]233            # Set the axis labels on subplot
234            self._set_axis_labels()
[49a470d]235            self.draw_plot()
236        else:
237            self.graph.render(self)
238            self.draw_plot()
239            self.subplot.set_title(label=data.label,
240                                   fontproperties=self.title_font,
241                                   color=self.title_color)
[2778c4f]242            self.subplot.figure.canvas.draw_idle()   
243        # Update Graph menu and help string       
[ae84427]244        #pos = self.parent._window_menu.FindItem(self.window_caption)
[2778c4f]245        helpString = 'Show/Hide Graph: '
246        helpString += (' ' + str(data.label) +';')
[ae84427]247        #self.parent._window_menu.SetHelpString(pos, helpString)
[8dfdd20]248        ## store default value of zmin and zmax
249        self.default_zmin_ctl = self.zmin_2D
250        self.default_zmax_ctl = self.zmax_2D
[7022fdc]251        # Check if zoomed
252        toolbar_zoomed = self.toolbar.GetToolEnabled(self.toolbar._NTB2_BACK)
253        if not self.is_zoomed and not toolbar_zoomed:
254            return
[e4a703a]255        # Recover the x,y limits
256        if (xlo and xhi and ylo and yhi) != None:
257            if (xlo > data.xmin and xhi < data.xmax and\
258                        ylo > data.ymin and yhi < data.ymax):
259                self.subplot.set_xlim((xlo, xhi))     
[fe48fcc]260                self.subplot.set_ylim((ylo, yhi)) 
261            else: 
262                self.toolbar.update()
[7022fdc]263                self._is_zoomed = False
[a4964b8e]264
[857d00f]265    def _set_axis_labels(self):
266        """
267        Set axis labels
268        """
269        data = self.data2D
270        # control axis labels from the panel itself
271        yname, yunits = data.get_yaxis()
272        if self.yaxis_label != None:
273            yname = self.yaxis_label
274            yunits = self.yaxis_unit
275        else:
276            self.yaxis_label = yname
277            self.yaxis_unit = yunits
278        xname, xunits = data.get_xaxis()
279        if self.xaxis_label != None:
280            xname = self.xaxis_label
281            xunits = self.xaxis_unit
282        else:
283            self.xaxis_label = xname
284            self.xaxis_unit = xunits
[2a09236]285        self.xaxis(xname, xunits, self.xaxis_font, 
286                   self.xaxis_color, self.xaxis_tick)
287        self.yaxis(yname, yunits, self.yaxis_font, 
288                   self.yaxis_color, self.yaxis_tick)
[857d00f]289       
[1bf33c1]290    def onContextMenu(self, event):
291        """
[d955bf19]292        2D plot context menu
293       
294        :param event: wx context event
[15550f4]295       
[d955bf19]296        """
[1bf33c1]297        slicerpop = PanelMenu()
298        slicerpop.set_plots(self.plots)
299        slicerpop.set_graph(self.graph)
[9a585d0]300             
301        id = wx.NewId()
[6d727ae]302        slicerpop.Append(id, '&Save Image')
[9a585d0]303        wx.EVT_MENU(self, id, self.onSaveImage)
304       
305        id = wx.NewId()
[6d727ae]306        slicerpop.Append(id,'&Print Image', 'Print image')
[9a585d0]307        wx.EVT_MENU(self, id, self.onPrint)
308       
[1ce365f8]309        id = wx.NewId()
[6d727ae]310        slicerpop.Append(id,'&Print Preview', 'Print preview')
[1ce365f8]311        wx.EVT_MENU(self, id, self.onPrinterPreview)
[003fa4e]312
313        id = wx.NewId()
314        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
315        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)
[c5a769e]316        slicerpop.AppendSeparator()
[ed8ad21]317        # saving data
318        plot = self.data2D
319        id = wx.NewId()
320        name = plot.name
[0aca693]321        slicerpop.Append(id, "&Data Info" )
322        wx.EVT_MENU(self, id, self._onDataShow)
323
324        id = wx.NewId()
325        name = plot.name
[c17760d]326        slicerpop.Append(id, "&Save as a File (DAT)" )
[ed8ad21]327        self.action_ids[str(id)] = plot
328        wx.EVT_MENU(self, id, self._onSave)
329
[9a585d0]330        slicerpop.AppendSeparator()
[7fff5cd]331        if len(self.data2D.detector) == 1:       
[0e13148]332           
[940aca7]333            item_list = self.parent.get_current_context_menu(self)
[6d727ae]334            if (not item_list == None) and (not len(item_list) == 0) and\
335                self.data2D.name.split(" ")[0] != 'Residuals': 
336                # The line above; Not for trunk
[32c0841]337                for item in item_list:
338                    try:
339                        id = wx.NewId()
340                        slicerpop.Append(id, item[0], item[1])
341                        wx.EVT_MENU(self, id, item[2])
342                    except:
343                        msg = "ModelPanel1D.onContextMenu: "
344                        msg += "bad menu item  %s"%sys.exc_value
345                        wx.PostEvent(self.parent, StatusEvent(status=msg))
346                        pass
347                slicerpop.AppendSeparator()
[0e13148]348           
[15550f4]349            id = wx.NewId()
[c17760d]350            slicerpop.Append(id, '&Perform Circular Average')
[6d727ae]351            wx.EVT_MENU(self, id, self.onCircular) \
352            # For Masked Data
353            if not plot.mask.all():
354                id = wx.NewId()
[c17760d]355                slicerpop.Append(id, '&Masked Circular Average')
[6d727ae]356                wx.EVT_MENU(self, id, self.onMaskedCircular) 
[15550f4]357            id = wx.NewId()
[c17760d]358            slicerpop.Append(id, '&Sector [Q View]')
[15550f4]359            wx.EVT_MENU(self, id, self.onSectorQ) 
360            id = wx.NewId()
[c17760d]361            slicerpop.Append(id, '&Annulus [Phi View ]')
[15550f4]362            wx.EVT_MENU(self, id, self.onSectorPhi) 
[92c2345]363            id = wx.NewId()
[15550f4]364            slicerpop.Append(id, '&Box Sum')
365            wx.EVT_MENU(self, id, self.onBoxSum) 
366            id = wx.NewId()
[c17760d]367            slicerpop.Append(id, '&Box Averaging in Qx')
[15550f4]368            wx.EVT_MENU(self, id, self.onBoxavgX) 
369            id = wx.NewId()
[c17760d]370            slicerpop.Append(id, '&Box Averaging in Qy')
[15550f4]371            wx.EVT_MENU(self, id, self.onBoxavgY) 
[32c0841]372            if self.slicer != None:
[eba08f1a]373                id = wx.NewId()
[c17760d]374                slicerpop.Append(id, '&Clear Slicer')
[15550f4]375                wx.EVT_MENU(self, id,  self.onClearSlicer) 
[32c0841]376                if self.slicer.__class__.__name__  != "BoxSum":
[15550f4]377                    id = wx.NewId()
378                    slicerpop.Append(id, '&Edit Slicer Parameters')
379                    wx.EVT_MENU(self, id, self._onEditSlicer) 
380            slicerpop.AppendSeparator() 
[fe48fcc]381           
382        id = wx.NewId()
[dc51a7f]383        slicerpop.Append(id, '&Edit Graph Label', 'Edit Graph Label')
[fe48fcc]384        wx.EVT_MENU(self, id, self.onEditLabels)
385        slicerpop.AppendSeparator()
386       
[8a687cfd]387        # ILL mod here
388
[0e13148]389        id = wx.NewId()
[8a687cfd]390        slicerpop.Append(id, '&Modify graph appearance','Modify graph appearance')
391        wx.EVT_MENU(self, id, self.modifyGraphAppearance)
[857d00f]392        slicerpop.AppendSeparator()
[8a687cfd]393
394
[857d00f]395       
396        id = wx.NewId()
[52f3c98]397        slicerpop.Append(id, '&2D Color Map')
[32c0841]398        wx.EVT_MENU(self, id, self._onEditDetector)
[857d00f]399        slicerpop.AppendSeparator()
400       
[1bf33c1]401        id = wx.NewId()
[c17760d]402        slicerpop.Append(id, '&Toggle Linear/Log Scale')
[1bf33c1]403        wx.EVT_MENU(self, id, self._onToggleScale) 
[53cf669]404       
405       
406        slicerpop.AppendSeparator()
407        id = wx.NewId()
408        slicerpop.Append(id, '&Window Title')
409        wx.EVT_MENU(self, id, self.onChangeCaption)
410       
[dc51a7f]411        try:
412            pos_evt = event.GetPosition()
413            pos = self.ScreenToClient(pos_evt)
414        except:
415            pos_x, pos_y = self.toolbar.GetPositionTuple()
416            pos = (pos_x, pos_y + 5)
[1bf33c1]417        self.PopupMenu(slicerpop, pos)
[37c36d9]418       
[fe48fcc]419           
420    def onEditLabels(self, event):
421        """
422        Edit legend label
423        """
[657e52c]424        try:
425            selected_plot = self.plots[self.graph.selected_plottable]
426        except:
427            selected_plot = self.plots[self.data2D.id]
[fe48fcc]428        label = selected_plot.label
[49a470d]429        dial = TextDialog(None, -1, 'Change Label', label)
[fe48fcc]430        if dial.ShowModal() == wx.ID_OK:
[49a470d]431            try:
432                FONT = FontProperties()
433                newlabel = dial.getText()
434                font = FONT.copy()
435                font.set_size(dial.getSize())
436                font.set_family(dial.getFamily())
437                font.set_style(dial.getStyle())
438                font.set_weight(dial.getWeight())
439                colour = dial.getColor()
440                if len(newlabel) > 0:
[53cf669]441                    # update Label
[49a470d]442                    selected_plot.label = newlabel
[53cf669]443                    self.graph.title(newlabel)
[49a470d]444                    self.title_label = selected_plot.label
445                    self.title_font = font
446                    self.title_color = colour
447                    ## render the graph
448                    self.subplot.set_title(label=self.title_label,
449                                           fontproperties=self.title_font,
450                                           color=self.title_color)
[36288ca]451                    self._is_changed_legend_label = True
[49a470d]452                    self.subplot.figure.canvas.draw_idle() 
453            except:
454                if self.parent != None:
455                    from sans.guiframe.events import StatusEvent
456                    msg= "Add Text: Error. Check your property values..."
457                    wx.PostEvent(self.parent, StatusEvent(status = msg ))
458                else:
459                    raise
[fe48fcc]460        dial.Destroy()
[53cf669]461       
462        # Update Graph menu and help string
463        if self.title_label != None:     
[ae84427]464            #pos = self.parent._window_menu.FindItem(self.window_caption)
[53cf669]465            helpString = 'Show/Hide Graph: '
[e2160ab]466            helpString += (' ' + str(self.title_label) +';')
[ae84427]467            #self.parent._window_menu.SetHelpString(pos, helpString)
[49a470d]468
[fe48fcc]469       
[ea290ee]470    def _onEditDetector(self, event):
[6d920cd]471        """
[d955bf19]472        Allow to view and edits  detector parameters
473       
474        :param event: wx.menu event
475       
[6d920cd]476        """
[ea290ee]477        import detector_dialog
[8dfdd20]478        dialog = detector_dialog.DetectorDialog(self, -1,base=self.parent,
479                       reset_zmin_ctl =self.default_zmin_ctl,
480                       reset_zmax_ctl = self.default_zmax_ctl,cmap=self.cmap)
[6c0568b]481        ## info of current detector and data2D
[ea290ee]482        xnpts = len(self.data2D.x_bins)
483        ynpts = len(self.data2D.y_bins)
484        xmax = max(self.data2D.xmin, self.data2D.xmax)
485        ymax = max(self.data2D.ymin, self.data2D.ymax)
[32c0841]486        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
[ea290ee]487        beam = self.data2D.xmin
[6c0568b]488        ## set dialog window content
[ea290ee]489        dialog.setContent(xnpts=xnpts,ynpts=ynpts,qmax=qmax,
490                           beam=self.data2D.xmin,
491                           zmin = self.zmin_2D,
492                          zmax = self.zmax_2D)
493        if dialog.ShowModal() == wx.ID_OK:
494            evt = dialog.getContent()
495            self.zmin_2D = evt.zmin
496            self.zmax_2D = evt.zmax
[32c0841]497            self.cmap = evt.cmap
[ea290ee]498        dialog.Destroy()
[6c0568b]499        ## Redraw the current image
[32c0841]500        self.image(data=self.data2D.data,
[20b6760]501                   qx_data=self.data2D.qx_data,
502                   qy_data=self.data2D.qy_data,
[ea290ee]503                   xmin= self.data2D.xmin,
504                   xmax= self.data2D.xmax,
505                   ymin= self.data2D.ymin,
506                   ymax= self.data2D.ymax,
507                   zmin= self.zmin_2D,
508                   zmax= self.zmax_2D,
[8dfdd20]509                   cmap= self.cmap,
[32c0841]510                   color=0, symbol=0, label=self.data2D.name)
[ea290ee]511        self.subplot.figure.canvas.draw_idle()
[1bf33c1]512       
513    def freeze_axes(self):
[d955bf19]514        """
515        """
[1bf33c1]516        self.axes_frozen = True
517       
518    def thaw_axes(self):
[d955bf19]519        """
520        """
[1bf33c1]521        self.axes_frozen = False
522       
523    def onMouseMotion(self,event):
[d955bf19]524        """
525        """
[1bf33c1]526        pass
[d955bf19]527   
[1bf33c1]528    def onWheel(self, event):
[d955bf19]529        """
530        """
[6c0568b]531        pass 
532     
[1bf33c1]533    def update(self, draw=True):
534        """
[d955bf19]535        Respond to changes in the model by recalculating the
536        profiles and resetting the widgets.
[1bf33c1]537        """
[6d727ae]538        self.draw_plot()
[1bf33c1]539       
540    def _getEmptySlicerEvent(self):
[6c0568b]541        """
[d955bf19]542        create an empty slicervent
[6c0568b]543        """
[32c0841]544        return SlicerEvent(type=None, params=None, obj_class=None)
[d955bf19]545       
[1bf33c1]546    def _onEVT_INTERNAL(self, event):
547        """
[d955bf19]548        Draw the slicer
549       
550        :param event: wx.lib.newevent (SlicerEvent) containing slicer
[6c0568b]551            parameter
[d955bf19]552           
[1bf33c1]553        """
554        self._setSlicer(event.slicer)
555           
556    def _setSlicer(self, slicer):
[6c0568b]557        """
[d955bf19]558        Clear the previous slicer and create a new one.Post an internal
559        event.
560       
561        :param slicer: slicer class to create
562       
[6c0568b]563        """
564        ## Clear current slicer
[1bf33c1]565        if not self.slicer == None: 
566            self.slicer.clear()           
[6c0568b]567        ## Create a new slicer   
[1bf33c1]568        self.slicer_z += 1
569        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
[240c805]570        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
571        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
[6c0568b]572        ## Draw slicer
[1bf33c1]573        self.update()
574        self.slicer.update()
[32c0841]575        msg = "Plotter2D._setSlicer  %s"%self.slicer.__class__.__name__
576        wx.PostEvent(self.parent, StatusEvent(status=msg))
[1bf33c1]577        # Post slicer event
578        event = self._getEmptySlicerEvent()
579        event.type = self.slicer.__class__.__name__
580        event.obj_class = self.slicer.__class__
581        event.params = self.slicer.get_params()
[d468daa]582        wx.PostEvent(self, event)
[6d727ae]583       
584    def onMaskedCircular(self, event):
585        """
586        perform circular averaging on Data2D with mask if it exists
587       
588        :param event: wx.menu event
589       
590        """
591        self.onCircular(event, True)
592       
593    def onCircular(self, event, ismask=False):
[1bf33c1]594        """
[d955bf19]595        perform circular averaging on Data2D
596       
597        :param event: wx.menu event
598       
[1bf33c1]599        """
[003fa4e]600        # Find the best number of bins
601        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
602        npt = math.floor(npt)
[fe857e2]603        from sans.dataloader.manipulations import CircularAverage
[6c0568b]604        ## compute the maximum radius of data2D
[32c0841]605        self.qmax = max(math.fabs(self.data2D.xmax), 
606                        math.fabs(self.data2D.xmin))
607        self.ymax = max(math.fabs(self.data2D.ymax),
608                        math.fabs(self.data2D.ymin))
609        self.radius = math.sqrt(math.pow(self.qmax, 2)+ math.pow(self.ymax, 2)) 
[6c0568b]610        ##Compute beam width
[003fa4e]611        bin_width = (self.qmax + self.qmax)/npt
[6c0568b]612        ## Create data1D circular average of data2D
[32c0841]613        Circle = CircularAverage(r_min=0, r_max=self.radius, 
614                                 bin_width=bin_width)
[6d727ae]615        circ = Circle(self.data2D, ismask=ismask)
[1bf33c1]616        from sans.guiframe.dataFitting import Data1D
[32c0841]617        if hasattr(circ, "dxl"):
618            dxl = circ.dxl
[1bf33c1]619        else:
[32c0841]620            dxl = None
621        if hasattr(circ, "dxw"):
622            dxw = circ.dxw
[1bf33c1]623        else:
[32c0841]624            dxw = None
[003fa4e]625
626        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
[32c0841]627        new_plot.dxl = dxl
628        new_plot.dxw = dxw
629        new_plot.name = "Circ avg " + self.data2D.name
630        new_plot.source = self.data2D.source
631        #new_plot.info = self.data2D.info
[1bf33c1]632        new_plot.interactive = True
[32c0841]633        new_plot.detector = self.data2D.detector
[6d727ae]634       
[6c0568b]635        ## If the data file does not tell us what the axes are, just assume...
[32c0841]636        new_plot.xaxis("\\rm{Q}", "A^{-1}")
[2ca51f44]637        if hasattr(self.data2D, "scale") and \
638                    self.data2D.scale == 'linear':
639            new_plot.ytransform = 'y'
640            new_plot.yaxis("\\rm{Residuals} ", "normalized")
[6d727ae]641        else:
642            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
643
[940aca7]644        new_plot.group_id = "2daverage"  + self.data2D.name
[32c0841]645        new_plot.id = "Circ avg " + self.data2D.name
646        new_plot.is_data = True
[657e52c]647        self.parent.update_theory(data_id=self.data2D.id, \
[13382fc7]648                                       theory=new_plot)
[32c0841]649        wx.PostEvent(self.parent, 
650                     NewPlotEvent(plot=new_plot, title=new_plot.name))
[ef0c170]651       
[1bf33c1]652    def _onEditSlicer(self, event):
[6c0568b]653        """
[d955bf19]654        Is available only when a slicer is drawn.Create a dialog
655        window where the user can enter value to reset slicer
656        parameters.
657       
658        :param event: wx.menu event
659       
[6c0568b]660        """
[32c0841]661        if self.slicer != None:
[1bf33c1]662            from SlicerParameters import SlicerParameterPanel
[4f8a00c]663            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
[1bf33c1]664            dialog.set_slicer(self.slicer.__class__.__name__,
665                            self.slicer.get_params())
666            if dialog.ShowModal() == wx.ID_OK:
667                dialog.Destroy() 
668       
669    def onSectorQ(self, event):
670        """
[d955bf19]671        Perform sector averaging on Q and draw sector slicer
[1bf33c1]672        """
[ef0c170]673        from SectorSlicer import SectorInteractor
[1bf33c1]674        self.onClearSlicer(event)
[32c0841]675        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
[1bf33c1]676       
677    def onSectorPhi(self, event):
678        """
[d955bf19]679        Perform sector averaging on Phi and draw annulus slicer
[1bf33c1]680        """
[ef0c170]681        from AnnulusSlicer import AnnulusInteractor
[1bf33c1]682        self.onClearSlicer(event)
[32c0841]683        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
[1bf33c1]684       
[d955bf19]685    def onBoxSum(self, event):
686        """
687        """
[ae84427]688        from sans.guiframe.gui_manager import MDIFrame
[7ab9241]689        from boxSum import BoxSum
690        self.onClearSlicer(event)
[54cc36a]691        self.slicer_z += 1
692        self.slicer =  BoxSum(self, self.subplot, zorder=self.slicer_z)
693        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
694        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
695        self.update()
696        self.slicer.update()
[6c0568b]697        ## Value used to initially set the slicer panel
698        type = self.slicer.__class__.__name__
699        params = self.slicer.get_params()
700        ## Create a new panel to display results of summation of Data2D
[8a7a21b]701        from slicerpanel import SlicerPanel
[ae84427]702        win = MDIFrame(self.parent, None, 'None', (100, 200))
703        new_panel = SlicerPanel(parent=win, id=-1,
[32c0841]704                                    base=self, type=type,
705                                    params=params, style=wx.RAISED_BORDER)
706       
707        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
708                                    str(self.data2D.name)
709        new_panel.window_name = self.slicer.__class__.__name__+ " " + \
710                                    str(self.data2D.name)
[6c0568b]711        ## Store a reference of the new created panel
[ae84427]712       
[6c0568b]713        ## save the window_caption of the new panel in the current slicer
[32c0841]714        self.slicer.set_panel_name(name=new_panel.window_caption)
[6c0568b]715        ## post slicer panel to guiframe to display it
[55a0dc1]716        from sans.guiframe.events import SlicerPanelEvent
[ae84427]717       
718        win.set_panel(new_panel)
719        new_panel.frame = win
720        wx.PostEvent(self.parent, SlicerPanelEvent(panel=new_panel,
[32c0841]721                                                    main_panel=self))
[ae84427]722        wx.CallAfter(new_panel.frame.Show)
723        self.panel_slicer = new_panel
724       
[8a7a21b]725    def onBoxavgX(self,event):
[6c0568b]726        """
[d955bf19]727        Perform 2D data averaging on Qx
728        Create a new slicer .
729       
730        :param event: wx.menu event
[6c0568b]731        """
[8a7a21b]732        from boxSlicer import BoxInteractorX
[38224f10]733        self.onClearSlicer(event)
[32c0841]734        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
[d468daa]735       
[8a7a21b]736    def onBoxavgY(self,event):
[6c0568b]737        """
[d955bf19]738        Perform 2D data averaging on Qy
739        Create a new slicer .
740       
741        :param event: wx.menu event
742       
[6c0568b]743        """
[8a7a21b]744        from boxSlicer import BoxInteractorY
745        self.onClearSlicer(event)
[32c0841]746        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
[6c0568b]747       
[1bf33c1]748    def onClearSlicer(self, event):
749        """
[d955bf19]750        Clear the slicer on the plot
[1bf33c1]751        """
[32c0841]752        if not self.slicer == None:
[1bf33c1]753            self.slicer.clear()
754            self.subplot.figure.canvas.draw()
755            self.slicer = None
756            # Post slicer None event
757            event = self._getEmptySlicerEvent()
[d468daa]758            wx.PostEvent(self, event)
[ed8ad21]759           
760    def _onSave(self, evt):
761        """
762        Save a data set to a dat(text) file
763       
764        :param evt: Menu event
765       
766        """
767        id = str(evt.GetId())
[c553b18]768        if self.parent != None:
769            self._default_save_location = self.parent._default_save_location
[3858e0f]770        default_name = self.plots[self.graph.selected_plottable].label
771        if default_name.count('.') > 0:
772            default_name = default_name.split('.')[0]
773        default_name += "_out"
[ed8ad21]774        if id in self.action_ids:         
775            path = None
[176fbf1]776            self.parent.save_data2d(self.data2D, default_name)
[0aca693]777           
778    def _onDataShow(self, evt):
779        """
780        Show the data set in text
781       
782        :param evt: Menu event
783       
784        """
785        menu = evt.GetEventObject()
786        id = evt.GetId()
787        self.set_selected_from_menu(menu, id)
788        data = self.plots[self.graph.selected_plottable]
789        default_name = data.label
790        if default_name.count('.') > 0:
791            default_name = default_name.split('.')[0]
792        #default_name += "_out"
793        if self.parent != None:
794            self.parent.show_data2d(data, default_name)
[8a687cfd]795       
796
797    def modifyGraphAppearance(self,e):
798        self.graphApp = graphAppearance(self,'Modify graph appearance',
799                                        legend=False)
800
801       
802
803        self.graphApp.setDefaults(self.grid_on,self.legend_on,
804                                  self.xaxis_label,self.yaxis_label,
805                                  self.xaxis_unit,self.yaxis_unit,
806                                  self.xaxis_font,self.yaxis_font,
807                                  find_key(self.get_loc_label(),self.legendLoc),
[657e52c]808                                  self.xcolor,self.ycolor,
809                                   self.is_xtick, self.is_ytick)
[8a687cfd]810        self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
811   
812
813    def on_graphApp_close(self,e):
814        # gets values from graph appearance dialog and sends them off
815        # to modify the plot
816
817        self.onGridOnOff(self.graphApp.get_togglegrid())
818
819       
820        self.xaxis_label = self.graphApp.get_xlab()
821        self.yaxis_label = self.graphApp.get_ylab()
822        self.xaxis_unit = self.graphApp.get_xunit()
823        self.yaxis_unit = self.graphApp.get_yunit()
[657e52c]824        self.xaxis_font = self.graphApp.get_xfont()
825        self.yaxis_font = self.graphApp.get_yfont()
826        self.is_xtick =  self.graphApp.get_xtick_check()
827        self.is_ytick =  self.graphApp.get_ytick_check()
828        if self.is_xtick:
829            self.xaxis_tick = self.xaxis_font
830        if self.is_ytick:
831            self.yaxis_tick = self.yaxis_font
[8a687cfd]832
[657e52c]833        self.xaxis(self.xaxis_label, self.xaxis_unit, 
834                   self.graphApp.get_xfont(), self.graphApp.get_xcolor(), 
835                   self.xaxis_tick)
836        self.yaxis(self.yaxis_label, self.yaxis_unit, 
837                   self.graphApp.get_yfont(), self.graphApp.get_ycolor(),
838                   self.yaxis_tick)
[8a687cfd]839
840        self.graphApp.Destroy()
Note: See TracBrowser for help on using the repository browser.