source: sasview/src/sas/guiframe/local_perspectives/plotting/Plotter2D.py @ 098f3d2

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 098f3d2 was 098f3d2, checked in by Doucet, Mathieu <doucetm@…>, 9 years ago

Remove print preview menu items. Fix 2D plotting from fit perspective.

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