source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py @ 39f0bf4

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.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 39f0bf4 was 39f0bf4, checked in by krzywon, 7 years ago

Modified slicer parameter panel to incorporate batch slicing. Added slicer combobox to slicer panel. Renamed files to be more explicit.

  • 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'
[39f0bf4]130        self.batch_slicer = None
[c039589]131        ## Graph
[1bf33c1]132        self.graph = Graph()
133        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
[32c0841]134        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
[1bf33c1]135        self.graph.render(self)
[c039589]136        ## store default value of zmin and zmax
[8dfdd20]137        self.default_zmin_ctl = self.zmin_2D
138        self.default_zmax_ctl = self.zmax_2D
[3e001f9]139
140    def on_plot_qrange(self, event=None):
141        """
142        On Qmin Qmax vertical line event
143        """
144        # Not implemented
145        if event == None:
146            return
[c039589]147        event.Skip()
148
149    def onLeftDown(self, event):
[a07e72f]150        """
151        left button down and ready to drag
[c039589]152
[a07e72f]153        """
154        # Check that the LEFT button was pressed
[c039589]155        PlotPanel.onLeftDown(self, event)
[e85e2bc]156        ax = event.inaxes
157        if ax != None:
158            # data coordinate position
[c039589]159            pos_x = "%8.3g" % event.xdata
160            pos_y = "%8.3g" % event.ydata
[e85e2bc]161            position = "x: %s    y: %s" % (pos_x, pos_y)
162            wx.PostEvent(self.parent, StatusEvent(status=position))
[a07e72f]163        self.plottable_selected(self.data2D.id)
164        self._manager.set_panel_on_focus(self)
165        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))
[c039589]166
[ac8671e]167    def add_toolbar(self):
168        """
[d955bf19]169        add toolbar
[ac8671e]170        """
171        self.enable_toolbar = True
[32c0841]172        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
[ac8671e]173        self.toolbar.Realize()
174        # On Windows platform, default window size is incorrect, so set
175        # toolbar width to figure width.
[c039589]176        _, th = self.toolbar.GetSizeTuple()
177        fw, _ = self.canvas.GetSizeTuple()
[ac8671e]178        self.toolbar.SetSize(wx.Size(fw, th))
[c039589]179        self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
[ac8671e]180        # update the axes menu on the toolbar
181        self.toolbar.update()
[c039589]182
[a07e72f]183    def plot_data(self, data):
[1bf33c1]184        """
[d955bf19]185        Data is ready to be displayed
[c039589]186
[d955bf19]187        :TODO: this name should be changed to something more appropriate
188             Don't forget that changing this name will mean changing code
189             in plotting.py
[c039589]190
[d955bf19]191        :param event: data event
[1bf33c1]192        """
[e4a703a]193        xlo = None
194        xhi = None
[c039589]195        ylo = None
[e4a703a]196        yhi = None
[b837e1f]197        if data.__class__.__name__ == 'Data1D':
198            return
[6c0568b]199        ## Update self.data2d with the current plot
[857d00f]200        self.data2D = data
[a07e72f]201        if data.id in self.plots.keys():
202            #replace
[e4a703a]203            xlo, xhi = self.subplot.get_xlim()
204            ylo, yhi = self.subplot.get_ylim()
[a07e72f]205            self.graph.replace(data)
206            self.plots[data.id] = data
[ab8f936]207        else:
[a07e72f]208            self.plots[data.id] = data
[c039589]209            self.graph.add(self.plots[data.id])
[ac9a5f6]210            # update qmax with the new xmax of data plotted
[c039589]211            self.qmax = data.xmax
[32c0841]212        self.slicer = None
[1bf33c1]213        # Check axis labels
214        #TODO: Should re-factor this
[c039589]215        ## render the graph with its new content
[7fff5cd]216        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
[c039589]217        if len(data.detector) < 1:
[a07e72f]218            if len(data._xunit) < 1 and len(data._yunit) < 1:
219                data._xaxis = '\\rm{x}'
220                data._yaxis = '\\rm{y}'
221                data._xunit = 'pixel'
222                data._yunit = 'pixel'
[857d00f]223        # graph properties
[a07e72f]224        self.graph.xaxis(data._xaxis, data._xunit)
225        self.graph.yaxis(data._yaxis, data._yunit)
[c039589]226        if self._is_changed_legend_label:
227            data.label = self.title_label
[fe48fcc]228        if data.label == None:
[c039589]229            data.label = data.name
[49a470d]230        if not self.title_font:
231            self.graph.title(data.label)
232            self.graph.render(self)
[857d00f]233            # Set the axis labels on subplot
234            self._set_axis_labels()
[49a470d]235            self.draw_plot()
236        else:
237            self.graph.render(self)
238            self.draw_plot()
239            self.subplot.set_title(label=data.label,
240                                   fontproperties=self.title_font,
241                                   color=self.title_color)
[c039589]242            self.subplot.figure.canvas.draw_idle()
243        ## store default value of zmin and zmax
[8dfdd20]244        self.default_zmin_ctl = self.zmin_2D
245        self.default_zmax_ctl = self.zmax_2D
[cafa75f]246        if not self.is_zoomed:
[7022fdc]247            return
[e4a703a]248        # Recover the x,y limits
[c039589]249        if xlo and xhi and ylo and yhi:
250            if xlo > data.xmin and xhi < data.xmax and \
251                        ylo > data.ymin and yhi < data.ymax:
252                self.subplot.set_xlim((xlo, xhi))
253                self.subplot.set_ylim((ylo, yhi))
254            else:
[fe48fcc]255                self.toolbar.update()
[cafa75f]256                self.is_zoomed = False
[a4964b8e]257
[857d00f]258    def _set_axis_labels(self):
259        """
260        Set axis labels
261        """
262        data = self.data2D
263        # control axis labels from the panel itself
264        yname, yunits = data.get_yaxis()
265        if self.yaxis_label != None:
266            yname = self.yaxis_label
267            yunits = self.yaxis_unit
268        else:
269            self.yaxis_label = yname
270            self.yaxis_unit = yunits
271        xname, xunits = data.get_xaxis()
272        if self.xaxis_label != None:
273            xname = self.xaxis_label
274            xunits = self.xaxis_unit
275        else:
276            self.xaxis_label = xname
277            self.xaxis_unit = xunits
[c039589]278        self.xaxis(xname, xunits, self.xaxis_font,
[2a09236]279                   self.xaxis_color, self.xaxis_tick)
[c039589]280        self.yaxis(yname, yunits, self.yaxis_font,
[2a09236]281                   self.yaxis_color, self.yaxis_tick)
[c039589]282
[1bf33c1]283    def onContextMenu(self, event):
284        """
[d955bf19]285        2D plot context menu
[c039589]286
[d955bf19]287        :param event: wx context event
[c039589]288
[d955bf19]289        """
[6f16e25]290        ids = iter(self._menu_ids)
[1bf33c1]291        slicerpop = PanelMenu()
292        slicerpop.set_plots(self.plots)
293        slicerpop.set_graph(self.graph)
[c039589]294
[6f16e25]295        wx_id = ids.next()
[1a696bf]296        slicerpop.Append(wx_id, '&Save Image', 'Save image as png')
[c039589]297        wx.EVT_MENU(self, wx_id, self.onSaveImage)
298
[6f16e25]299        wx_id = ids.next()
[c039589]300        slicerpop.Append(wx_id, '&Print Image', 'Print image')
301        wx.EVT_MENU(self, wx_id, self.onPrint)
302
[6f16e25]303        wx_id = ids.next()
[c039589]304        slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
305        wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
[c5a769e]306        slicerpop.AppendSeparator()
[ed8ad21]307        # saving data
308        plot = self.data2D
[6f16e25]309        wx_id = ids.next()
[c039589]310        slicerpop.Append(wx_id, "&Data Info")
311        wx.EVT_MENU(self, wx_id, self._onDataShow)
[0aca693]312
[6f16e25]313        wx_id = ids.next()
[c039589]314        slicerpop.Append(wx_id, "&Save as a File (DAT)")
315        self.action_ids[str(wx_id)] = plot
316        wx.EVT_MENU(self, wx_id, self._onSave)
[ed8ad21]317
[9a585d0]318        slicerpop.AppendSeparator()
[b2b36932]319        if len(self.data2D.detector) <= 1:
[940aca7]320            item_list = self.parent.get_current_context_menu(self)
[6d727ae]321            if (not item_list == None) and (not len(item_list) == 0) and\
[c039589]322                self.data2D.name.split(" ")[0] != 'Residuals':
[1a696bf]323                for item, wx_id in zip(item_list, [ids.next() for i in range(len(item_list))]):
[32c0841]324                    try:
[c039589]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
[6f16e25]333            wx_id = ids.next()
[c039589]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():
[6f16e25]338                wx_id = ids.next()
[c039589]339                slicerpop.Append(wx_id, '&Masked Circular Average')
340                wx.EVT_MENU(self, wx_id, self.onMaskedCircular)
[6f16e25]341            wx_id = ids.next()
[c039589]342            slicerpop.Append(wx_id, '&Sector [Q View]')
343            wx.EVT_MENU(self, wx_id, self.onSectorQ)
[6f16e25]344            wx_id = ids.next()
[c039589]345            slicerpop.Append(wx_id, '&Annulus [Phi View ]')
346            wx.EVT_MENU(self, wx_id, self.onSectorPhi)
[6f16e25]347            wx_id = ids.next()
[c039589]348            slicerpop.Append(wx_id, '&Box Sum')
349            wx.EVT_MENU(self, wx_id, self.onBoxSum)
[6f16e25]350            wx_id = ids.next()
[c039589]351            slicerpop.Append(wx_id, '&Box Averaging in Qx')
352            wx.EVT_MENU(self, wx_id, self.onBoxavgX)
[6f16e25]353            wx_id = ids.next()
[c039589]354            slicerpop.Append(wx_id, '&Box Averaging in Qy')
355            wx.EVT_MENU(self, wx_id, self.onBoxavgY)
[32c0841]356            if self.slicer != None:
[6f16e25]357                wx_id = ids.next()
[c039589]358                slicerpop.Append(wx_id, '&Clear Slicer')
359                wx.EVT_MENU(self, wx_id, self.onClearSlicer)
360                if self.slicer.__class__.__name__ != "BoxSum":
[6f16e25]361                    wx_id = ids.next()
[39f0bf4]362                    name = '&Edit Slicer Parameters and Batch Slicing'
363                    slicerpop.Append(wx_id, name)
[c039589]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)
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)
[b699768]572        from sas.sascalc.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)
[d85c194]585        from sas.sasgui.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:
[39f0bf4]631            from parameters_panel_slicer 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        """
[d85c194]657        from sas.sasgui.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
[39f0bf4]669        from parameters_panel_boxsum 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
[d85c194]684        from sas.sasgui.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.