source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py @ 0b1a677

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.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 0b1a677 was d85c194, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 9 years ago

Remaining modules refactored

  • Property mode set to 100644
File size: 29.5 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
[d7bb526]18from sas.sasgui.plottools.PlotPanel import PlotPanel
19from sas.sasgui.plottools.plottables import Graph
20from sas.sasgui.plottools.TextDialog import TextDialog
[d85c194]21from sas.sasgui.guiframe.events import StatusEvent
22from sas.sasgui.guiframe.events import NewPlotEvent
23from sas.sasgui.guiframe.events import PanelOnFocusEvent
24from sas.sasgui.guiframe.events import SlicerEvent
25from sas.sasgui.guiframe.utils import PanelMenu
26from  sas.sasgui.guiframe.local_perspectives.plotting.binder import BindArtist
[1bf33c1]27from Plotter1D import ModelPanel1D
[d7bb526]28from sas.sasgui.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        """
[6f16e25]289        ids = iter(self._menu_ids)
[1bf33c1]290        slicerpop = PanelMenu()
291        slicerpop.set_plots(self.plots)
292        slicerpop.set_graph(self.graph)
[c039589]293
[6f16e25]294        wx_id = ids.next()
[c039589]295        slicerpop.Append(wx_id, '&Save Image')
296        wx.EVT_MENU(self, wx_id, self.onSaveImage)
297
[6f16e25]298        wx_id = ids.next()
[c039589]299        slicerpop.Append(wx_id, '&Print Image', 'Print image')
300        wx.EVT_MENU(self, wx_id, self.onPrint)
301
[6f16e25]302        wx_id = ids.next()
[c039589]303        slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
304        wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
[c5a769e]305        slicerpop.AppendSeparator()
[ed8ad21]306        # saving data
307        plot = self.data2D
[6f16e25]308        wx_id = ids.next()
[c039589]309        slicerpop.Append(wx_id, "&Data Info")
310        wx.EVT_MENU(self, wx_id, self._onDataShow)
[0aca693]311
[6f16e25]312        wx_id = ids.next()
[c039589]313        slicerpop.Append(wx_id, "&Save as a File (DAT)")
314        self.action_ids[str(wx_id)] = plot
315        wx.EVT_MENU(self, wx_id, self._onSave)
[ed8ad21]316
[9a585d0]317        slicerpop.AppendSeparator()
[c039589]318        if len(self.data2D.detector) == 1:
[940aca7]319            item_list = self.parent.get_current_context_menu(self)
[6d727ae]320            if (not item_list == None) and (not len(item_list) == 0) and\
[c039589]321                self.data2D.name.split(" ")[0] != 'Residuals':
[6d727ae]322                # The line above; Not for trunk
[6f16e25]323                # Note: reusing menu ids for the sub-menus.  See Plotter1D.
324                for item, wx_id in zip(item_list, self._menu_ids):
[32c0841]325                    try:
[c039589]326                        slicerpop.Append(wx_id, item[0], item[1])
327                        wx.EVT_MENU(self, wx_id, item[2])
[32c0841]328                    except:
329                        msg = "ModelPanel1D.onContextMenu: "
[c039589]330                        msg += "bad menu item  %s" % sys.exc_value
[32c0841]331                        wx.PostEvent(self.parent, StatusEvent(status=msg))
332                slicerpop.AppendSeparator()
[c039589]333
[6f16e25]334            wx_id = ids.next()
[c039589]335            slicerpop.Append(wx_id, '&Perform Circular Average')
336            wx.EVT_MENU(self, wx_id, self.onCircular) \
[6d727ae]337            # For Masked Data
338            if not plot.mask.all():
[6f16e25]339                wx_id = ids.next()
[c039589]340                slicerpop.Append(wx_id, '&Masked Circular Average')
341                wx.EVT_MENU(self, wx_id, self.onMaskedCircular)
[6f16e25]342            wx_id = ids.next()
[c039589]343            slicerpop.Append(wx_id, '&Sector [Q View]')
344            wx.EVT_MENU(self, wx_id, self.onSectorQ)
[6f16e25]345            wx_id = ids.next()
[c039589]346            slicerpop.Append(wx_id, '&Annulus [Phi View ]')
347            wx.EVT_MENU(self, wx_id, self.onSectorPhi)
[6f16e25]348            wx_id = ids.next()
[c039589]349            slicerpop.Append(wx_id, '&Box Sum')
350            wx.EVT_MENU(self, wx_id, self.onBoxSum)
[6f16e25]351            wx_id = ids.next()
[c039589]352            slicerpop.Append(wx_id, '&Box Averaging in Qx')
353            wx.EVT_MENU(self, wx_id, self.onBoxavgX)
[6f16e25]354            wx_id = ids.next()
[c039589]355            slicerpop.Append(wx_id, '&Box Averaging in Qy')
356            wx.EVT_MENU(self, wx_id, self.onBoxavgY)
[32c0841]357            if self.slicer != None:
[6f16e25]358                wx_id = ids.next()
[c039589]359                slicerpop.Append(wx_id, '&Clear Slicer')
360                wx.EVT_MENU(self, wx_id, self.onClearSlicer)
361                if self.slicer.__class__.__name__ != "BoxSum":
[6f16e25]362                    wx_id = ids.next()
[c039589]363                    slicerpop.Append(wx_id, '&Edit Slicer Parameters')
364                    wx.EVT_MENU(self, wx_id, self._onEditSlicer)
365            slicerpop.AppendSeparator()
366
[6f16e25]367        wx_id = ids.next()
[c039589]368        slicerpop.Append(wx_id, '&Edit Graph Label', 'Edit Graph Label')
369        wx.EVT_MENU(self, wx_id, self.onEditLabels)
[fe48fcc]370        slicerpop.AppendSeparator()
[c039589]371
[8a687cfd]372        # ILL mod here
373
[6f16e25]374        wx_id = ids.next()
[c039589]375        slicerpop.Append(wx_id, '&Modify graph appearance', 'Modify graph appearance')
376        wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
[857d00f]377        slicerpop.AppendSeparator()
[8a687cfd]378
[6f16e25]379        wx_id = ids.next()
[c039589]380        slicerpop.Append(wx_id, '&2D Color Map')
381        wx.EVT_MENU(self, wx_id, self._onEditDetector)
[857d00f]382        slicerpop.AppendSeparator()
[c039589]383
[6f16e25]384        wx_id = ids.next()
[c039589]385        slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
386        wx.EVT_MENU(self, wx_id, self._onToggleScale)
387
[53cf669]388        slicerpop.AppendSeparator()
[6f16e25]389        wx_id = ids.next()
[c039589]390        slicerpop.Append(wx_id, '&Window Title')
391        wx.EVT_MENU(self, wx_id, self.onChangeCaption)
392
[dc51a7f]393        try:
394            pos_evt = event.GetPosition()
395            pos = self.ScreenToClient(pos_evt)
396        except:
397            pos_x, pos_y = self.toolbar.GetPositionTuple()
398            pos = (pos_x, pos_y + 5)
[1bf33c1]399        self.PopupMenu(slicerpop, pos)
[c039589]400
[fe48fcc]401    def onEditLabels(self, event):
402        """
403        Edit legend label
404        """
[657e52c]405        try:
406            selected_plot = self.plots[self.graph.selected_plottable]
407        except:
408            selected_plot = self.plots[self.data2D.id]
[fe48fcc]409        label = selected_plot.label
[49a470d]410        dial = TextDialog(None, -1, 'Change Label', label)
[fe48fcc]411        if dial.ShowModal() == wx.ID_OK:
[49a470d]412            try:
413                FONT = FontProperties()
414                newlabel = dial.getText()
415                font = FONT.copy()
416                font.set_size(dial.getSize())
417                font.set_family(dial.getFamily())
418                font.set_style(dial.getStyle())
419                font.set_weight(dial.getWeight())
420                colour = dial.getColor()
421                if len(newlabel) > 0:
[53cf669]422                    # update Label
[49a470d]423                    selected_plot.label = newlabel
[53cf669]424                    self.graph.title(newlabel)
[49a470d]425                    self.title_label = selected_plot.label
426                    self.title_font = font
427                    self.title_color = colour
428                    ## render the graph
429                    self.subplot.set_title(label=self.title_label,
430                                           fontproperties=self.title_font,
431                                           color=self.title_color)
[36288ca]432                    self._is_changed_legend_label = True
[c039589]433                    self.subplot.figure.canvas.draw_idle()
[49a470d]434            except:
[c039589]435                msg = "Add Text: Error. Check your property values..."
436                logging.error(msg)
[49a470d]437                if self.parent != None:
[c039589]438                    wx.PostEvent(self.parent, StatusEvent(status=msg))
[fe48fcc]439        dial.Destroy()
[c039589]440
[ea290ee]441    def _onEditDetector(self, event):
[6d920cd]442        """
[d955bf19]443        Allow to view and edits  detector parameters
[c039589]444
[d955bf19]445        :param event: wx.menu event
[c039589]446
[6d920cd]447        """
[ea290ee]448        import detector_dialog
[c039589]449        dialog = detector_dialog.DetectorDialog(self, -1, base=self.parent,
450                                                reset_zmin_ctl=self.default_zmin_ctl,
451                                                reset_zmax_ctl=self.default_zmax_ctl, cmap=self.cmap)
[6c0568b]452        ## info of current detector and data2D
[ea290ee]453        xnpts = len(self.data2D.x_bins)
454        ynpts = len(self.data2D.y_bins)
455        xmax = max(self.data2D.xmin, self.data2D.xmax)
456        ymax = max(self.data2D.ymin, self.data2D.ymax)
[32c0841]457        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
[6c0568b]458        ## set dialog window content
[c039589]459        dialog.setContent(xnpts=xnpts, ynpts=ynpts, qmax=qmax,
460                          beam=self.data2D.xmin,
461                          zmin=self.zmin_2D,
462                          zmax=self.zmax_2D)
[ea290ee]463        if dialog.ShowModal() == wx.ID_OK:
464            evt = dialog.getContent()
465            self.zmin_2D = evt.zmin
466            self.zmax_2D = evt.zmax
[32c0841]467            self.cmap = evt.cmap
[ea290ee]468        dialog.Destroy()
[6c0568b]469        ## Redraw the current image
[32c0841]470        self.image(data=self.data2D.data,
[20b6760]471                   qx_data=self.data2D.qx_data,
472                   qy_data=self.data2D.qy_data,
[c039589]473                   xmin=self.data2D.xmin,
474                   xmax=self.data2D.xmax,
475                   ymin=self.data2D.ymin,
476                   ymax=self.data2D.ymax,
477                   zmin=self.zmin_2D,
478                   zmax=self.zmax_2D,
479                   cmap=self.cmap,
[32c0841]480                   color=0, symbol=0, label=self.data2D.name)
[ea290ee]481        self.subplot.figure.canvas.draw_idle()
[c039589]482
[1bf33c1]483    def freeze_axes(self):
[d955bf19]484        """
485        """
[1bf33c1]486        self.axes_frozen = True
[c039589]487
[1bf33c1]488    def thaw_axes(self):
[d955bf19]489        """
490        """
[1bf33c1]491        self.axes_frozen = False
[c039589]492
493    def onMouseMotion(self, event):
[d955bf19]494        """
495        """
[1bf33c1]496        pass
[c039589]497
[1bf33c1]498    def onWheel(self, event):
[d955bf19]499        """
500        """
[c039589]501        pass
502
[1bf33c1]503    def update(self, draw=True):
504        """
[c039589]505        Respond to changes in the model by recalculating the
[d955bf19]506        profiles and resetting the widgets.
[1bf33c1]507        """
[6d727ae]508        self.draw_plot()
[c039589]509
[1bf33c1]510    def _getEmptySlicerEvent(self):
[6c0568b]511        """
[c039589]512        create an empty slicervent
[6c0568b]513        """
[32c0841]514        return SlicerEvent(type=None, params=None, obj_class=None)
[c039589]515
[1bf33c1]516    def _onEVT_INTERNAL(self, event):
517        """
[d955bf19]518        Draw the slicer
[c039589]519
[d955bf19]520        :param event: wx.lib.newevent (SlicerEvent) containing slicer
[6c0568b]521            parameter
[c039589]522
[1bf33c1]523        """
524        self._setSlicer(event.slicer)
[c039589]525
[1bf33c1]526    def _setSlicer(self, slicer):
[6c0568b]527        """
[d955bf19]528        Clear the previous slicer and create a new one.Post an internal
529        event.
[c039589]530
[d955bf19]531        :param slicer: slicer class to create
[c039589]532
[6c0568b]533        """
534        ## Clear current slicer
[c039589]535        if not self.slicer == None:
536            self.slicer.clear()
537        ## Create a new slicer
[1bf33c1]538        self.slicer_z += 1
539        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
[240c805]540        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
541        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
[6c0568b]542        ## Draw slicer
[1bf33c1]543        self.update()
544        self.slicer.update()
[c039589]545        msg = "Plotter2D._setSlicer  %s" % self.slicer.__class__.__name__
[32c0841]546        wx.PostEvent(self.parent, StatusEvent(status=msg))
[1bf33c1]547        # Post slicer event
548        event = self._getEmptySlicerEvent()
549        event.type = self.slicer.__class__.__name__
550        event.obj_class = self.slicer.__class__
551        event.params = self.slicer.get_params()
[d468daa]552        wx.PostEvent(self, event)
[c039589]553
[6d727ae]554    def onMaskedCircular(self, event):
555        """
556        perform circular averaging on Data2D with mask if it exists
[c039589]557
[6d727ae]558        :param event: wx.menu event
[c039589]559
[6d727ae]560        """
561        self.onCircular(event, True)
[c039589]562
[6d727ae]563    def onCircular(self, event, ismask=False):
[1bf33c1]564        """
[d955bf19]565        perform circular averaging on Data2D
[c039589]566
[d955bf19]567        :param event: wx.menu event
[c039589]568
[1bf33c1]569        """
[003fa4e]570        # Find the best number of bins
571        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
572        npt = math.floor(npt)
[b699768]573        from sas.sascalc.dataloader.manipulations import CircularAverage
[6c0568b]574        ## compute the maximum radius of data2D
[c039589]575        self.qmax = max(math.fabs(self.data2D.xmax),
[32c0841]576                        math.fabs(self.data2D.xmin))
577        self.ymax = max(math.fabs(self.data2D.ymax),
578                        math.fabs(self.data2D.ymin))
[c039589]579        self.radius = math.sqrt(math.pow(self.qmax, 2) + math.pow(self.ymax, 2))
[6c0568b]580        ##Compute beam width
[c039589]581        bin_width = (self.qmax + self.qmax) / npt
[6c0568b]582        ## Create data1D circular average of data2D
[c039589]583        Circle = CircularAverage(r_min=0, r_max=self.radius,
[32c0841]584                                 bin_width=bin_width)
[6d727ae]585        circ = Circle(self.data2D, ismask=ismask)
[d85c194]586        from sas.sasgui.guiframe.dataFitting import Data1D
[32c0841]587        if hasattr(circ, "dxl"):
588            dxl = circ.dxl
[1bf33c1]589        else:
[32c0841]590            dxl = None
591        if hasattr(circ, "dxw"):
592            dxw = circ.dxw
[1bf33c1]593        else:
[32c0841]594            dxw = None
[003fa4e]595
596        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
[32c0841]597        new_plot.dxl = dxl
598        new_plot.dxw = dxw
599        new_plot.name = "Circ avg " + self.data2D.name
600        new_plot.source = self.data2D.source
601        #new_plot.info = self.data2D.info
[1bf33c1]602        new_plot.interactive = True
[32c0841]603        new_plot.detector = self.data2D.detector
[c039589]604
[6c0568b]605        ## If the data file does not tell us what the axes are, just assume...
[32c0841]606        new_plot.xaxis("\\rm{Q}", "A^{-1}")
[2ca51f44]607        if hasattr(self.data2D, "scale") and \
608                    self.data2D.scale == 'linear':
609            new_plot.ytransform = 'y'
610            new_plot.yaxis("\\rm{Residuals} ", "normalized")
[6d727ae]611        else:
612            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")
613
[c039589]614        new_plot.group_id = "2daverage" + self.data2D.name
[32c0841]615        new_plot.id = "Circ avg " + self.data2D.name
616        new_plot.is_data = True
[657e52c]617        self.parent.update_theory(data_id=self.data2D.id, \
[13382fc7]618                                       theory=new_plot)
[c039589]619        wx.PostEvent(self.parent,
[32c0841]620                     NewPlotEvent(plot=new_plot, title=new_plot.name))
[c039589]621
[1bf33c1]622    def _onEditSlicer(self, event):
[6c0568b]623        """
[c039589]624        Is available only when a slicer is drawn.Create a dialog
[d955bf19]625        window where the user can enter value to reset slicer
626        parameters.
[c039589]627
[d955bf19]628        :param event: wx.menu event
[c039589]629
[6c0568b]630        """
[32c0841]631        if self.slicer != None:
[1bf33c1]632            from SlicerParameters import SlicerParameterPanel
[4f8a00c]633            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
[1bf33c1]634            dialog.set_slicer(self.slicer.__class__.__name__,
[c039589]635                              self.slicer.get_params())
[1bf33c1]636            if dialog.ShowModal() == wx.ID_OK:
[c039589]637                dialog.Destroy()
638
[1bf33c1]639    def onSectorQ(self, event):
640        """
[d955bf19]641        Perform sector averaging on Q and draw sector slicer
[1bf33c1]642        """
[ef0c170]643        from SectorSlicer import SectorInteractor
[1bf33c1]644        self.onClearSlicer(event)
[32c0841]645        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))
[c039589]646
[1bf33c1]647    def onSectorPhi(self, event):
648        """
[d955bf19]649        Perform sector averaging on Phi and draw annulus slicer
[1bf33c1]650        """
[ef0c170]651        from AnnulusSlicer import AnnulusInteractor
[1bf33c1]652        self.onClearSlicer(event)
[32c0841]653        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))
[c039589]654
[d955bf19]655    def onBoxSum(self, event):
656        """
657        """
[d85c194]658        from sas.sasgui.guiframe.gui_manager import MDIFrame
[7ab9241]659        from boxSum import BoxSum
660        self.onClearSlicer(event)
[54cc36a]661        self.slicer_z += 1
[c039589]662        self.slicer = BoxSum(self, self.subplot, zorder=self.slicer_z)
[54cc36a]663        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
664        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
665        self.update()
666        self.slicer.update()
[6c0568b]667        ## Value used to initially set the slicer panel
668        params = self.slicer.get_params()
669        ## Create a new panel to display results of summation of Data2D
[8a7a21b]670        from slicerpanel import SlicerPanel
[ae84427]671        win = MDIFrame(self.parent, None, 'None', (100, 200))
672        new_panel = SlicerPanel(parent=win, id=-1,
[c039589]673                                base=self, type=self.slicer.__class__.__name__,
674                                params=params, style=wx.RAISED_BORDER)
675
[32c0841]676        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
677                                    str(self.data2D.name)
[c039589]678        new_panel.window_name = self.slicer.__class__.__name__ + " " + \
[32c0841]679                                    str(self.data2D.name)
[6c0568b]680        ## Store a reference of the new created panel
[c039589]681
[6c0568b]682        ## save the window_caption of the new panel in the current slicer
[32c0841]683        self.slicer.set_panel_name(name=new_panel.window_caption)
[c039589]684        ## post slicer panel to guiframe to display it
[d85c194]685        from sas.sasgui.guiframe.events import SlicerPanelEvent
[c039589]686
[ae84427]687        win.set_panel(new_panel)
688        new_panel.frame = win
689        wx.PostEvent(self.parent, SlicerPanelEvent(panel=new_panel,
[c039589]690                                                   main_panel=self))
[ae84427]691        wx.CallAfter(new_panel.frame.Show)
692        self.panel_slicer = new_panel
[c039589]693
694    def onBoxavgX(self, event):
[6c0568b]695        """
[d955bf19]696        Perform 2D data averaging on Qx
697        Create a new slicer .
[c039589]698
[d955bf19]699        :param event: wx.menu event
[6c0568b]700        """
[8a7a21b]701        from boxSlicer import BoxInteractorX
[38224f10]702        self.onClearSlicer(event)
[32c0841]703        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))
[c039589]704
705    def onBoxavgY(self, event):
[6c0568b]706        """
[d955bf19]707        Perform 2D data averaging on Qy
708        Create a new slicer .
[c039589]709
[d955bf19]710        :param event: wx.menu event
[c039589]711
[6c0568b]712        """
[8a7a21b]713        from boxSlicer import BoxInteractorY
714        self.onClearSlicer(event)
[32c0841]715        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))
[c039589]716
[1bf33c1]717    def onClearSlicer(self, event):
718        """
[d955bf19]719        Clear the slicer on the plot
[1bf33c1]720        """
[32c0841]721        if not self.slicer == None:
[1bf33c1]722            self.slicer.clear()
723            self.subplot.figure.canvas.draw()
724            self.slicer = None
725            # Post slicer None event
726            event = self._getEmptySlicerEvent()
[d468daa]727            wx.PostEvent(self, event)
[c039589]728
[ed8ad21]729    def _onSave(self, evt):
730        """
731        Save a data set to a dat(text) file
[c039589]732
[ed8ad21]733        :param evt: Menu event
[c039589]734
[ed8ad21]735        """
[c039589]736        event_id = str(evt.GetId())
[c553b18]737        if self.parent != None:
738            self._default_save_location = self.parent._default_save_location
[3858e0f]739        default_name = self.plots[self.graph.selected_plottable].label
740        if default_name.count('.') > 0:
741            default_name = default_name.split('.')[0]
742        default_name += "_out"
[c039589]743        if event_id in self.action_ids:
[176fbf1]744            self.parent.save_data2d(self.data2D, default_name)
[c039589]745
[0aca693]746    def _onDataShow(self, evt):
747        """
748        Show the data set in text
[c039589]749
[0aca693]750        :param evt: Menu event
[c039589]751
[0aca693]752        """
753        menu = evt.GetEventObject()
[c039589]754        event_id = evt.GetId()
755        self.set_selected_from_menu(menu, event_id)
[0aca693]756        data = self.plots[self.graph.selected_plottable]
757        default_name = data.label
758        if default_name.count('.') > 0:
759            default_name = default_name.split('.')[0]
760        #default_name += "_out"
761        if self.parent != None:
762            self.parent.show_data2d(data, default_name)
[8a687cfd]763
[c039589]764    def modifyGraphAppearance(self, e):
765        self.graphApp = graphAppearance(self, 'Modify graph appearance', legend=False)
766        self.graphApp.setDefaults(self.grid_on, self.legend_on,
767                                  self.xaxis_label, self.yaxis_label,
768                                  self.xaxis_unit, self.yaxis_unit,
769                                  self.xaxis_font, self.yaxis_font,
770                                  find_key(self.get_loc_label(), self.legendLoc),
771                                  self.xcolor, self.ycolor,
772                                  self.is_xtick, self.is_ytick)
[8a687cfd]773        self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)
774
[c039589]775    def on_graphApp_close(self, e):
776        """
777            Gets values from graph appearance dialog and sends them off
778            to modify the plot
779        """
[8a687cfd]780        self.onGridOnOff(self.graphApp.get_togglegrid())
781        self.xaxis_label = self.graphApp.get_xlab()
782        self.yaxis_label = self.graphApp.get_ylab()
783        self.xaxis_unit = self.graphApp.get_xunit()
784        self.yaxis_unit = self.graphApp.get_yunit()
[657e52c]785        self.xaxis_font = self.graphApp.get_xfont()
786        self.yaxis_font = self.graphApp.get_yfont()
[c039589]787        self.is_xtick = self.graphApp.get_xtick_check()
788        self.is_ytick = self.graphApp.get_ytick_check()
[657e52c]789        if self.is_xtick:
790            self.xaxis_tick = self.xaxis_font
791        if self.is_ytick:
792            self.yaxis_tick = self.yaxis_font
[8a687cfd]793
[c039589]794        self.xaxis(self.xaxis_label, self.xaxis_unit,
795                   self.graphApp.get_xfont(), self.graphApp.get_xcolor(),
[657e52c]796                   self.xaxis_tick)
[c039589]797        self.yaxis(self.yaxis_label, self.yaxis_unit,
[657e52c]798                   self.graphApp.get_yfont(), self.graphApp.get_ycolor(),
799                   self.yaxis_tick)
[8a687cfd]800
801        self.graphApp.Destroy()
Note: See TracBrowser for help on using the repository browser.