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

Last change on this file since a67d674 was 3e5648b, checked in by krzywon, 8 years ago

Resolve merge conflicts and 2 small fixes to slicer panel. #467

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