source: sasview/src/sas/sasgui/guiframe/local_perspectives/plotting/Plotter2D.py @ 2510b9b

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since 2510b9b was b2b36932, checked in by krzywon, 8 years ago

#824: 2D data without detector information can now use the slicers, and annular and sector averaging. The real question is why are we limiting this to single detector sets?

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