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

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

mdi frames for main applications

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