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

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

pylint fixes

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