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

Last change on this file since f5f8553 was 5251ec6, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

improved support for py37 in sasgui

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