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

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

merging from the release 2.2.0

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