def sample_graph():
    # Construct a simple graph
    
    T1 = Text(text='text example 1', xpos=0.2, ypos=0.2)
    T2 = Text(text='text example 2', xpos=0.5, ypos=0.5)
    T3 = Text(text=r'$\chi^2=1.2$', xpos=0.8, ypos=0.8)
    
    graph = Graph()
    graph.title( 'Test Text Class' )
    graph.add( T1 )
    graph.add( T2 ) 
    graph.add( T3 )
    return graph
Exemple #2
0
def sample_graph():
    # Construct a simple graph

    T1 = Text(text='text example 1', xpos=0.2, ypos=0.2)
    T2 = Text(text='text example 2', xpos=0.5, ypos=0.5)
    T3 = Text(text=r'$\chi^2=1.2$', xpos=0.8, ypos=0.8)

    graph = Graph()
    graph.title('Test Text Class')
    graph.add(T1)
    graph.add(T2)
    graph.add(T3)
    return graph
def sample_graph():
    # Construct a simple graph
    x = numpy.linspace(0,2.0, 50)
    y = numpy.sin(2*numpy.pi*x*2.8)
    dy = numpy.sqrt(100*numpy.abs(y))/100
    
    data = Data1D(x,y,dy=dy)
    data.xaxis('distance', 'm')
    data.yaxis('time', 's')
    
    graph = Graph()
    
    graph.add(data)
    graph.add( Theory1D(x,y,dy=dy))

    graph.title( 'Test Copy and Print Image' )
    return graph
Exemple #4
0
def sample_graph():
    # Construct a simple graph
    x = numpy.linspace(0, 2.0, 50)
    y = numpy.sin(2 * numpy.pi * x * 2.8)
    dy = numpy.sqrt(100 * numpy.abs(y)) / 100

    data = Data1D(x, y, dy=dy)
    data.xaxis('distance', 'm')
    data.yaxis('time', 's')

    graph = Graph()

    graph.add(data)
    graph.add(Theory1D(x, y, dy=dy))

    graph.title('Test Copy and Print Image')
    return graph
Exemple #5
0
def sample_graph():
    # Construct a simple graph
    if False:
        x = numpy.array([1,2,3,4,5,6],'d')
        y = numpy.array([4,5,26,5,4,-1],'d')
        dy = numpy.array([0.2, 0.3, 0.1, 0.2, 0.9, 0.3])
    else:
        x = numpy.linspace(0,2.0, 50)
        y = numpy.sin(2*numpy.pi*x*2.8)
        dy = numpy.sqrt(100*numpy.abs(y))/100

    from sas.plottools.plottables import Data1D, Theory1D, Chisq , Graph
    data = Data1D(x,y,dy=dy)
    data.xaxis('distance', 'm')
    data.yaxis('time', 's')
    graph = Graph()
    graph.title('Walking Results')
    graph.add(data)
    graph.add( Theory1D(x,y,dy=dy))
    graph.add( Chisq( 1.0 ) )
    return graph
class OutputPlot(PlotPanel):
    """
    Plot panel used to show the selected results as a function
    of D_max
    """
    ## Title for plottools
    window_caption = "D Explorer"

    def __init__(self, d_min, d_max, parent, id= -1, color=None, \
                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
        """
        Initialization. The parameters added to PlotPanel are:

        :param d_min: Minimum value of D_max to explore
        :param d_max: Maximum value of D_max to explore

        """
        PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)

        self.parent = parent
        self.min = d_min
        self.max = d_max
        self.npts = DEFAULT_NPTS

        step = (self.max - self.min) / (self.npts - 1)
        self.x = numpy.arange(self.min, self.max + step * 0.01, step)
        dx = numpy.zeros(len(self.x))
        y = numpy.ones(len(self.x))
        dy = numpy.zeros(len(self.x))

        # Plot area
        self.plot = Model1D(self.x, y=y, dy=dy)
        self.plot.name = DEFAULT_OUTPUT
        self.plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM

        # Graph        
        self.graph = Graph()
        self.graph.xaxis("\\rm{D_{max}}", 'A')
        self.graph.yaxis("\\rm{%s}" % DEFAULT_OUTPUT, "")
        self.graph.add(self.plot)
        self.graph.render(self)

        self.toolbar.DeleteToolByPos(0)
        self.toolbar.DeleteToolByPos(8)
        self.toolbar.Realize()

    def onContextMenu(self, event):
        """
        Default context menu for the plot panel

        :TODO: Would be nice to add printing and log/linear scales.
            The current verison of plottools no longer plays well with
            plots outside of guiframe. Guiframe team needs to fix this.
        """
        # Slicer plot popup menu
        wx_id = wx.NewId()
        slicerpop = wx.Menu()
        slicerpop.Append(wx_id, '&Save image', 'Save image as PNG')
        wx.EVT_MENU(self, wx_id, self.onSaveImage)

        wx_id = wx.NewId()
        slicerpop.AppendSeparator()
        slicerpop.Append(wx_id, '&Reset Graph')
        wx.EVT_MENU(self, wx_id, self.onResetGraph)

        pos = event.GetPosition()
        pos = self.ScreenToClient(pos)
        self.PopupMenu(slicerpop, pos)
class OutputPlot(PlotPanel):
    """
    Plot panel used to show the selected results as a function
    of D_max
    """
    ## Title for plottools
    window_caption = "D Explorer"

    def __init__(self, d_min, d_max, parent, id= -1, color=None, \
                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
        """
        Initialization. The parameters added to PlotPanel are:

        :param d_min: Minimum value of D_max to explore
        :param d_max: Maximum value of D_max to explore

        """
        PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)

        self.parent = parent
        self.min = d_min
        self.max = d_max
        self.npts = DEFAULT_NPTS

        step = (self.max - self.min) / (self.npts - 1)
        self.x = numpy.arange(self.min, self.max + step * 0.01, step)
        dx = numpy.zeros(len(self.x))
        y = numpy.ones(len(self.x))
        dy = numpy.zeros(len(self.x))

        # Plot area
        self.plot = Model1D(self.x, y=y, dy=dy)
        self.plot.name = DEFAULT_OUTPUT
        self.plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM

        # Graph
        self.graph = Graph()
        self.graph.xaxis("\\rm{D_{max}}", 'A')
        self.graph.yaxis("\\rm{%s}" % DEFAULT_OUTPUT, "")
        self.graph.add(self.plot)
        self.graph.render(self)

        self.toolbar.DeleteToolByPos(0)
        self.toolbar.DeleteToolByPos(8)
        self.toolbar.Realize()

    def onContextMenu(self, event):
        """
        Default context menu for the plot panel

        :TODO: Would be nice to add printing and log/linear scales.
            The current verison of plottools no longer plays well with
            plots outside of guiframe. Guiframe team needs to fix this.
        """
        # Slicer plot popup menu
        wx_id = wx.NewId()
        slicerpop = wx.Menu()
        slicerpop.Append(wx_id, '&Save image', 'Save image as PNG')
        wx.EVT_MENU(self, wx_id, self.onSaveImage)

        wx_id = wx.NewId()
        slicerpop.AppendSeparator()
        slicerpop.Append(wx_id, '&Reset Graph')
        wx.EVT_MENU(self, wx_id, self.onResetGraph)

        pos = event.GetPosition()
        pos = self.ScreenToClient(pos)
        self.PopupMenu(slicerpop, pos)
Exemple #8
0
class SmallPanel(PlotPanel):
    """
    PlotPanel for Quick plot and masking plot
    """
    def __init__(self, parent, id=-1, is_number=False, content='?', **kwargs):
        """
        """
        PlotPanel.__init__(self, parent, id=id, **kwargs)
        self.is_number = is_number
        self.content = content
        self.point = None
        self.position = (0.4, 0.5)
        self.scale = 'linear'
        self.prevXtrans = "x"
        self.prevYtrans = "y"
        self.viewModel = "--"
        self.subplot.set_xticks([])
        self.subplot.set_yticks([])
        self.add_text()
        self.figure.subplots_adjust(left=0.1, bottom=0.1)

    def set_content(self, content=''):
        """
        Set text content
        """
        self.content = str(content)

    def add_toolbar(self):
        """
        Add toolbar
        """
        # Not implemented
        pass

    def on_set_focus(self, event):
        """
        send to the parenet the current panel on focus
        """
        pass

    def add_image(self, plot):
        """
        Add Image
        """
        self.content = ''
        self.textList = []
        self.plots = {}
        self.clear()
        self.point = plot
        try:
            self.figure.delaxes(self.figure.axes[0])
            self.subplot = self.figure.add_subplot(111)
            #self.figure.delaxes(self.figure.axes[1])
        except:
            pass
        try:
            name = plot.name
        except:
            name = plot.filename
        self.plots[name] = plot

        #init graph
        self.graph = Graph()

        #add plot
        self.graph.add(plot)
        #draw
        self.graph.render(self)

        try:
            self.figure.delaxes(self.figure.axes[1])
        except:
            pass
        self.subplot.figure.canvas.resizing = False
        self.subplot.tick_params(axis='both', labelsize=9)
        # Draw zero axis lines
        self.subplot.axhline(linewidth=1, color='r')
        self.subplot.axvline(linewidth=1, color='r')

        self.erase_legend()
        try:
            # mpl >= 1.1.0
            self.figure.tight_layout()
        except:
            self.figure.subplots_adjust(left=0.1, bottom=0.1)
        self.subplot.figure.canvas.draw()

    def add_text(self):
        """
        Text in the plot
        """
        if not self.is_number:
            return

        self.clear()
        try:
            self.figure.delaxes(self.figure.axes[0])
            self.subplot = self.figure.add_subplot(111)
            self.figure.delaxes(self.figure.axes[1])
        except:
            pass
        self.subplot.set_xticks([])
        self.subplot.set_yticks([])
        label = self.content
        FONT = FontProperties()
        xpos, ypos = (0.4, 0.5)
        font = FONT.copy()
        font.set_size(14)

        self.textList = []
        self.subplot.set_xlim((0, 1))
        self.subplot.set_ylim((0, 1))

        try:
            if self.content != '?':
                float(label)
        except:
            self.subplot.set_frame_on(False)
        try:
            # mpl >= 1.1.0
            self.figure.tight_layout()
        except:
            self.figure.subplots_adjust(left=0.1, bottom=0.1)
        if len(label) > 0 and xpos > 0 and ypos > 0:
            new_text = self.subplot.text(str(xpos),
                                         str(ypos),
                                         str(label),
                                         fontproperties=font)
            self.textList.append(new_text)

    def erase_legend(self):
        """
        Remove Legend
        """
        #for ax in self.axes:
        self.remove_legend(self.subplot)

    def onMouseMotion(self, event):
        """
        Disable dragging 2D image
        """

    def onWheel(self, event):
        """
        """

    def onLeftDown(self, event):
        """
        Disables LeftDown
        """

    def onPick(self, event):
        """
        Remove Legend
        """
        for ax in self.axes:
            self.remove_legend(ax)

    def draw(self):
        """
        Draw
        """
        if self.dimension == 3:
            pass
        else:
            self.subplot.figure.canvas.resizing = False
            self.subplot.tick_params(axis='both', labelsize=9)
            self.erase_legend()
            self.subplot.figure.canvas.draw_idle()
            try:
                self.figure.delaxes(self.figure.axes[1])
            except:
                pass

    def onContextMenu(self, event):
        """
        Default context menu for a plot panel
        """
        id = wx.NewId()
        slicerpop = wx.Menu()
        data = self.point
        if issubclass(data.__class__, Data1D):
            slicerpop.Append(id, '&Change Scale')
            wx.EVT_MENU(self, id, self._onProperties)
        else:
            slicerpop.Append(id, '&Toggle Linear/Log Scale')
            wx.EVT_MENU(self, id, self.ontogglescale)
        try:
            # mouse event
            pos_evt = event.GetPosition()
            pos = self.ScreenToClient(pos_evt)
        except:
            # toolbar event
            pos_x, pos_y = self.toolbar.GetPositionTuple()
            pos = (pos_x, pos_y + 5)
        self.PopupMenu(slicerpop, pos)

    def ontogglescale(self, event):
        """
        On toggle 2d scale
        """
        self._onToggleScale(event)
        try:
            # mpl >= 1.1.0
            self.figure.tight_layout()
        except:
            self.figure.subplots_adjust(left=0.1, bottom=0.1)
        try:
            self.figure.delaxes(self.figure.axes[1])
        except:
            pass

    def _onProperties(self, event):
        """
        when clicking on Properties on context menu ,
        The Property dialog is displayed
        The user selects a transformation for x or y value and
        a new plot is displayed
        """
        list = []
        list = self.graph.returnPlottable()
        if len(list.keys()) > 0:
            first_item = list.keys()[0]
            if first_item.x != []:
                from sas.plottools.PropertyDialog import Properties
                dial = Properties(self, -1, 'Change Scale')
                # type of view or model used
                dial.xvalue.Clear()
                dial.yvalue.Clear()
                dial.view.Clear()
                dial.xvalue.Insert("x", 0)
                dial.xvalue.Insert("log10(x)", 1)
                dial.yvalue.Insert("y", 0)
                dial.yvalue.Insert("log10(y)", 1)
                dial.view.Insert("--", 0)
                dial.view.Insert("Linear y vs x", 1)
                dial.setValues(self.prevXtrans, self.prevYtrans,
                               self.viewModel)
                dial.Update()
                if dial.ShowModal() == wx.ID_OK:
                    self.xLabel, self.yLabel, self.viewModel = dial.getValues()
                    if self.viewModel == "Linear y vs x":
                        self.xLabel = "x"
                        self.yLabel = "y"
                        self.viewModel = "--"
                        dial.setValues(self.xLabel, self.yLabel,
                                       self.viewModel)
                    self._onEVT_FUNC_PROPERTY()
                dial.Destroy()

    def _onEVT_FUNC_PROPERTY(self, remove_fit=True):
        """
        Receive the x and y transformation from myDialog,
        Transforms x and y in View
        and set the scale
        """
        list = []
        list = self.graph.returnPlottable()
        # Changing the scale might be incompatible with
        # currently displayed data (for instance, going
        # from ln to log when all plotted values have
        # negative natural logs).
        # Go linear and only change the scale at the end.
        self.set_xscale("linear")
        self.set_yscale("linear")
        _xscale = 'linear'
        _yscale = 'linear'
        for item in list:
            item.setLabel(self.xLabel, self.yLabel)
            # control axis labels from the panel itself
            yname, yunits = item.get_yaxis()
            xname, xunits = item.get_xaxis()
            # Goes through all possible scales
            # Goes through all possible scales
            if (self.xLabel == "x"):
                item.transformX(transform.toX, transform.errToX)
                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
            if (self.xLabel == "log10(x)"):
                item.transformX(transform.toX_pos, transform.errToX_pos)
                _xscale = 'log'
                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
            if (self.yLabel == "y"):
                item.transformY(transform.toX, transform.errToX)
                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
            if (self.yLabel == "log10(y)"):
                item.transformY(transform.toX_pos, transform.errToX_pos)
                _yscale = 'log'
                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
            item.transformView()
        self.prevXtrans = self.xLabel
        self.prevYtrans = self.yLabel
        self.set_xscale(_xscale)
        self.set_yscale(_yscale)
        self.draw()
Exemple #9
0
class Maskplotpanel(PlotPanel):
    """
    PlotPanel for Quick plot and masking plot
    """
    def __init__(self, parent, id=-1, dimension=2, color=None, dpi=None, **kwargs):
        """
        """
        PlotPanel.__init__(self, parent, id=id, color=color, dpi=dpi, **kwargs)

        # Keep track of the parent Frame
        self.parent = parent
        # Internal list of plottable names (because graph
        # doesn't have a dictionary of handles for the plottables)
        self.dimension = dimension
        self.plots = {}
        self.graph = Graph()
        # add axis labels
        self.graph.xaxis('\\rm{x} ', '')
        self.graph.yaxis('\\rm{y} ', '')

    def add_toolbar(self):
        """
        Add toolbar
        """
        # Not implemented
        pass

    def on_set_focus(self, event):
        """
        send to the parenet the current panel on focus
        """
        if self.dimension == 3:
            pass
        else:
            self.draw()

    def add_image(self, plot):
        """
        Add Image
        """
        self.plots[plot.name] = plot
        # init graph
        self.graph = Graph()
        # add plot
        self.graph.add(plot)
        # add axes
        if self.dimension == 1:
            self.xaxis_label = '\\rm{x} '
            self.xaxis_unit = ''
            self.yaxis_label = '\\rm{y} '
            self.yaxis_unit = ''
        # draw
        # message
        status_type = 'progress'
        msg = 'Plotting...'
        self._status_info(msg, status_type)
        status_type = 'stop'
        self.graph.render(self)
        self.subplot.figure.canvas.resizing = False
        if self.dimension < 3:
            self.graph.render(self)
            self.subplot.figure.canvas.draw()
        elif FONT_VARIANT:
            self.subplot.figure.canvas.draw()
        msg = 'Plotting Completed.'
        self._status_info(msg, status_type)

    def onMouseMotion(self, event):
        """
        Disable dragging 2D image
        """
        pass

    def onWheel(self, event):
        """
        """
        pass

    def onLeftDown(self, event):
        """
        Disables LeftDown
        """
        pass

    def onPick(self, event):
        """
        Disables OnPick
        """
        pass

    def draw(self):
        """
        Draw
        """
        # message
        status_type = 'progress'
        msg = 'Plotting...'
        self._status_info(msg, status_type)
        status_type = 'stop'

        if not self.dimension == 3:
            self.subplot.figure.canvas.draw_idle()

        msg = 'Plotting Completed.'
        self._status_info(msg, status_type)

    def onContextMenu(self, event):
        """
        Default context menu for a plot panel
        """
        # Selective Slicer plot popup menu
        slicerpop = wx.Menu()

        id = wx.NewId()
        slicerpop.Append(id, '&Print Image', 'Print image')
        wx.EVT_MENU(self, id, self.onPrint)

        id = wx.NewId()
        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)

        if self.dimension == 1:
            id = wx.NewId()
            slicerpop.Append(id, '&Change Scale')
            wx.EVT_MENU(self, id, self._onProperties)
        else:
            slicerpop.AppendSeparator()
            id_cm = wx.NewId()
            slicerpop.Append(id_cm, '&Toggle Linear/Log scale')
            wx.EVT_MENU(self, id_cm, self._onToggleScale)

        pos = event.GetPosition()
        pos = self.ScreenToClient(pos)
        self.PopupMenu(slicerpop, pos)

    def _status_info(self, msg='', type="update"):
        """
        Status msg
        """
        if self.parent.parent.parent != None:
            wx.PostEvent(self.parent.parent.parent,
                         StatusEvent(status=msg, type=type))
Exemple #10
0
class SimplePlotPanel(PlotPanel):
    """
    PlotPanel for 1d and 2d
    """
    _window_caption = 'Simple Plot'
    def __init__(self, parent, id=-1, color=None,
                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
        """
        Init
        """
        PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)

        self.SetColor(wx.WHITE)

        self.toolbar = NavigationToolBar(parent=self, canvas=self.canvas)
        self.toolbar.Show(False)
        self.scale = parent.scale
        self.window_caption = self._window_caption

    def draw(self):
        """
        """
        self.resizing = False
        self.canvas.set_resizing(self.resizing)
        self.canvas.draw()

    def add_toolbar(self):
        """
        """
        pass

    def onContextMenu(self, event):
        """
        2D plot context menu

        :param event: wx context event

        """
        slicerpop = PanelMenu()
        slicerpop.set_plots(self.plots)
        slicerpop.set_graph(self.graph)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Save Image')
        wx.EVT_MENU(self, wx_id, self.onSaveImage)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Print Image', 'Print image')
        wx.EVT_MENU(self, wx_id, self.onPrint)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
        wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)

        if self.dimension != 3:
            slicerpop.AppendSeparator()
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Toggle Grid On/Off', 'Toggle Grid On/Off')
            wx.EVT_MENU(self, wx_id, self.on_grid_onoff)

        if self.data.__class__.__name__ == 'Data1D':
            slicerpop.AppendSeparator()
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Change Scale')
            wx.EVT_MENU(self, wx_id, self._onProperties)
        elif self.data2D.__class__.__name__ == 'Data2D':
            slicerpop.AppendSeparator()
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
            wx.EVT_MENU(self, wx_id, self._onToggleScale)

        try:
            pos_evt = event.GetPosition()
            pos = self.ScreenToClient(pos_evt)
        except:
            pos_x, pos_y = self.toolbar.GetPositionTuple()
            pos = (pos_x, pos_y + 5)
        self.PopupMenu(slicerpop, pos)
        if self.scale != None:
            self.parent.scale2d = self.scale

    def on_grid_onoff(self, event):
        """
        On grid on/off
        """
        switch = (not self.grid_on)
        self.onGridOnOff(switch)

    def onLeftDown(self, event):
        """
        left button down and ready to drag

        """
        # Check that the LEFT button was pressed
        if event.button == 1:
            self.leftdown = True
            ax = event.inaxes
            if ax != None:
                self.xInit, self.yInit = event.xdata, event.ydata
                try:
                    pos_x = float(event.xdata)  # / size_x
                    pos_y = float(event.ydata)  # / size_y
                    pos_x = "%8.3g" % pos_x
                    pos_y = "%8.3g" % pos_y
                    self.position = str(pos_x), str(pos_y)
                    wx.PostEvent(self.parent, StatusEvent(status=self.position))
                except:
                    self.position = None

    def _OnReSize(self, event):
        """
        On response of the resize of a panel, set axes_visiable False
        """
        self.resizing = False
        if self.x_size != None:
            if self.x_size == self.GetSize():
                self.canvas.set_resizing(self.resizing)
                return
        self.x_size = self.GetSize()

        # Ready for another event
        # Do not remove this Skip.
        # Otherwise it will get runtime error on wx>=2.9.
        event.Skip()
        # set the resizing flag
        self.canvas.set_resizing(self.resizing)
        pos_x, pos_y = self.GetPositionTuple()
        if pos_x != 0 and pos_y != 0:
            self.size, _ = self.GetClientSizeTuple()
        self.SetSizer(self.sizer)

    def on_set_focus(self, event):
        """
        By pass default boundary blue color drawing
        """
        pass

    def on_kill_focus(self, event):
        """
        Reset the panel color
        """
        pass

    def show_plot(self, plot):
        """
        Show the plot
        """
        _yaxis, _yunit = plot.get_yaxis()
        _xaxis, _xunit = plot.get_xaxis()
        self.data = plot
        self.plots[plot.name] = plot
        # Axis scales
        if plot.xtransform != None:
            self.xLabel = plot.xtransform
        if plot.ytransform != None:
            self.yLabel = plot.ytransform
        # Init graph
        self.graph = Graph()
        # Add plot: Handles both 1D and 2D
        self.graph.add(self.data)
        self.canvas.set_resizing(False)
        if self.data.__class__.__name__ == 'Data2D':
            self.data2D = plot
        elif self.data.__class__.__name__ == 'Data1D':
            self._onEVT_FUNC_PROPERTY(show=False)
        # Axes
        self.graph.xaxis(_xaxis, _xunit)
        self.graph.yaxis(_yaxis, _yunit)
        self.xaxis(_xaxis, _xunit)
        self.yaxis(_yaxis, _yunit)
        self.set_xscale(self.xscale)
        self.set_yscale(self.yscale)
        self.graph.render(self)
Exemple #11
0
class ModelPanel2D(ModelPanel1D):
    """
    Plot panel for use with the GUI manager
    """

    ## Internal name for the AUI manager
    window_name = "plotpanel"
    ## Title to appear on top of the window
    window_caption = "Plot Panel"
    ## Flag to tell the GUI manager that this panel is not
    #  tied to any perspective
    ALWAYS_ON = True
    ## Group ID
    group_id = None

    def __init__(self,
                 parent,
                 id=-1,
                 data2d=None,
                 color=None,
                 dpi=None,
                 style=wx.NO_FULL_REPAINT_ON_RESIZE,
                 **kwargs):
        """
        Initialize the panel
        """
        ModelPanel1D.__init__(self, parent, id=id, style=style, **kwargs)
        self.parent = parent
        ## Reference to the parent window
        if hasattr(parent, "parent"):
            self.parent = self.parent.parent
        ## Dictionary containing Plottables
        self.plots = {}
        ## Save reference of the current plotted
        self.data2D = data2d
        ## Unique ID (from gui_manager)
        self.uid = None
        ## Action IDs for internal call-backs
        self.action_ids = {}
        ## Create Artist and bind it
        self.connect = BindArtist(self.subplot.figure)
        ## Beam stop
        self.beamstop_radius = DEFAULT_BEAM
        ## to set the order of lines drawn first.
        self.slicer_z = 5
        ## Reference to the current slicer
        self.slicer = None
        ## event to send slicer info
        self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)

        self.axes_frozen = False
        ## panel that contains result from slicer motion (ex: Boxsum info)
        self.panel_slicer = None
        self.title_label = None
        self.title_font = None
        self.title_color = 'black'
        ## Graph
        self.graph = Graph()
        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
        self.graph.render(self)
        ## store default value of zmin and zmax
        self.default_zmin_ctl = self.zmin_2D
        self.default_zmax_ctl = self.zmax_2D

    def on_plot_qrange(self, event=None):
        """
        On Qmin Qmax vertical line event
        """
        # Not implemented
        if event == None:
            return
        event.Skip()

    def onLeftDown(self, event):
        """
        left button down and ready to drag

        """
        # Check that the LEFT button was pressed
        PlotPanel.onLeftDown(self, event)
        ax = event.inaxes
        if ax != None:
            # data coordinate position
            pos_x = "%8.3g" % event.xdata
            pos_y = "%8.3g" % event.ydata
            position = "x: %s    y: %s" % (pos_x, pos_y)
            wx.PostEvent(self.parent, StatusEvent(status=position))
        self.plottable_selected(self.data2D.id)
        self._manager.set_panel_on_focus(self)
        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))

    def add_toolbar(self):
        """
        add toolbar
        """
        self.enable_toolbar = True
        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
        self.toolbar.Realize()
        # On Windows platform, default window size is incorrect, so set
        # toolbar width to figure width.
        _, th = self.toolbar.GetSizeTuple()
        fw, _ = self.canvas.GetSizeTuple()
        self.toolbar.SetSize(wx.Size(fw, th))
        self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
        # update the axes menu on the toolbar
        self.toolbar.update()

    def plot_data(self, data):
        """
        Data is ready to be displayed

        :TODO: this name should be changed to something more appropriate
             Don't forget that changing this name will mean changing code
             in plotting.py

        :param event: data event
        """
        xlo = None
        xhi = None
        ylo = None
        yhi = None
        if data.__class__.__name__ == 'Data1D':
            return
        ## Update self.data2d with the current plot
        self.data2D = data
        if data.id in self.plots.keys():
            #replace
            xlo, xhi = self.subplot.get_xlim()
            ylo, yhi = self.subplot.get_ylim()
            self.graph.replace(data)
            self.plots[data.id] = data
        else:
            self.plots[data.id] = data
            self.graph.add(self.plots[data.id])
            # update qmax with the new xmax of data plotted
            self.qmax = data.xmax
        self.slicer = None
        # Check axis labels
        #TODO: Should re-factor this
        ## render the graph with its new content
        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
        if len(data.detector) < 1:
            if len(data._xunit) < 1 and len(data._yunit) < 1:
                data._xaxis = '\\rm{x}'
                data._yaxis = '\\rm{y}'
                data._xunit = 'pixel'
                data._yunit = 'pixel'
        # graph properties
        self.graph.xaxis(data._xaxis, data._xunit)
        self.graph.yaxis(data._yaxis, data._yunit)
        if self._is_changed_legend_label:
            data.label = self.title_label
        if data.label == None:
            data.label = data.name
        if not self.title_font:
            self.graph.title(data.label)
            self.graph.render(self)
            # Set the axis labels on subplot
            self._set_axis_labels()
            self.draw_plot()
        else:
            self.graph.render(self)
            self.draw_plot()
            self.subplot.set_title(label=data.label,
                                   fontproperties=self.title_font,
                                   color=self.title_color)
            self.subplot.figure.canvas.draw_idle()
        ## store default value of zmin and zmax
        self.default_zmin_ctl = self.zmin_2D
        self.default_zmax_ctl = self.zmax_2D
        if not self.is_zoomed:
            return
        # Recover the x,y limits
        if xlo and xhi and ylo and yhi:
            if xlo > data.xmin and xhi < data.xmax and \
                        ylo > data.ymin and yhi < data.ymax:
                self.subplot.set_xlim((xlo, xhi))
                self.subplot.set_ylim((ylo, yhi))
            else:
                self.toolbar.update()
                self.is_zoomed = False

    def _set_axis_labels(self):
        """
        Set axis labels
        """
        data = self.data2D
        # control axis labels from the panel itself
        yname, yunits = data.get_yaxis()
        if self.yaxis_label != None:
            yname = self.yaxis_label
            yunits = self.yaxis_unit
        else:
            self.yaxis_label = yname
            self.yaxis_unit = yunits
        xname, xunits = data.get_xaxis()
        if self.xaxis_label != None:
            xname = self.xaxis_label
            xunits = self.xaxis_unit
        else:
            self.xaxis_label = xname
            self.xaxis_unit = xunits
        self.xaxis(xname, xunits, self.xaxis_font, self.xaxis_color,
                   self.xaxis_tick)
        self.yaxis(yname, yunits, self.yaxis_font, self.yaxis_color,
                   self.yaxis_tick)

    def onContextMenu(self, event):
        """
        2D plot context menu

        :param event: wx context event

        """
        slicerpop = PanelMenu()
        slicerpop.set_plots(self.plots)
        slicerpop.set_graph(self.graph)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Save Image')
        wx.EVT_MENU(self, wx_id, self.onSaveImage)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Print Image', 'Print image')
        wx.EVT_MENU(self, wx_id, self.onPrint)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Print Preview', 'Print preview')
        wx.EVT_MENU(self, wx_id, self.onPrinterPreview)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
        wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
        slicerpop.AppendSeparator()
        # saving data
        plot = self.data2D
        wx_id = wx.NewId()
        slicerpop.Append(wx_id, "&Data Info")
        wx.EVT_MENU(self, wx_id, self._onDataShow)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, "&Save as a File (DAT)")
        self.action_ids[str(wx_id)] = plot
        wx.EVT_MENU(self, wx_id, self._onSave)

        slicerpop.AppendSeparator()
        if len(self.data2D.detector) == 1:
            item_list = self.parent.get_current_context_menu(self)
            if (not item_list == None) and (not len(item_list) == 0) and\
                self.data2D.name.split(" ")[0] != 'Residuals':
                # The line above; Not for trunk
                for item in item_list:
                    try:
                        wx_id = wx.NewId()
                        slicerpop.Append(wx_id, item[0], item[1])
                        wx.EVT_MENU(self, wx_id, item[2])
                    except:
                        msg = "ModelPanel1D.onContextMenu: "
                        msg += "bad menu item  %s" % sys.exc_value
                        wx.PostEvent(self.parent, StatusEvent(status=msg))
                slicerpop.AppendSeparator()

            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Perform Circular Average')
            wx.EVT_MENU(self, wx_id, self.onCircular) \
            # For Masked Data

            if not plot.mask.all():
                wx_id = wx.NewId()
                slicerpop.Append(wx_id, '&Masked Circular Average')
                wx.EVT_MENU(self, wx_id, self.onMaskedCircular)
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Sector [Q View]')
            wx.EVT_MENU(self, wx_id, self.onSectorQ)
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Annulus [Phi View ]')
            wx.EVT_MENU(self, wx_id, self.onSectorPhi)
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Box Sum')
            wx.EVT_MENU(self, wx_id, self.onBoxSum)
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Box Averaging in Qx')
            wx.EVT_MENU(self, wx_id, self.onBoxavgX)
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Box Averaging in Qy')
            wx.EVT_MENU(self, wx_id, self.onBoxavgY)
            if self.slicer != None:
                wx_id = wx.NewId()
                slicerpop.Append(wx_id, '&Clear Slicer')
                wx.EVT_MENU(self, wx_id, self.onClearSlicer)
                if self.slicer.__class__.__name__ != "BoxSum":
                    wx_id = wx.NewId()
                    slicerpop.Append(wx_id, '&Edit Slicer Parameters')
                    wx.EVT_MENU(self, wx_id, self._onEditSlicer)
            slicerpop.AppendSeparator()

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Edit Graph Label', 'Edit Graph Label')
        wx.EVT_MENU(self, wx_id, self.onEditLabels)
        slicerpop.AppendSeparator()

        # ILL mod here

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Modify graph appearance',
                         'Modify graph appearance')
        wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
        slicerpop.AppendSeparator()

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&2D Color Map')
        wx.EVT_MENU(self, wx_id, self._onEditDetector)
        slicerpop.AppendSeparator()

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
        wx.EVT_MENU(self, wx_id, self._onToggleScale)

        slicerpop.AppendSeparator()
        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Window Title')
        wx.EVT_MENU(self, wx_id, self.onChangeCaption)

        try:
            pos_evt = event.GetPosition()
            pos = self.ScreenToClient(pos_evt)
        except:
            pos_x, pos_y = self.toolbar.GetPositionTuple()
            pos = (pos_x, pos_y + 5)
        self.PopupMenu(slicerpop, pos)

    def onEditLabels(self, event):
        """
        Edit legend label
        """
        try:
            selected_plot = self.plots[self.graph.selected_plottable]
        except:
            selected_plot = self.plots[self.data2D.id]
        label = selected_plot.label
        dial = TextDialog(None, -1, 'Change Label', label)
        if dial.ShowModal() == wx.ID_OK:
            try:
                FONT = FontProperties()
                newlabel = dial.getText()
                font = FONT.copy()
                font.set_size(dial.getSize())
                font.set_family(dial.getFamily())
                font.set_style(dial.getStyle())
                font.set_weight(dial.getWeight())
                colour = dial.getColor()
                if len(newlabel) > 0:
                    # update Label
                    selected_plot.label = newlabel
                    self.graph.title(newlabel)
                    self.title_label = selected_plot.label
                    self.title_font = font
                    self.title_color = colour
                    ## render the graph
                    self.subplot.set_title(label=self.title_label,
                                           fontproperties=self.title_font,
                                           color=self.title_color)
                    self._is_changed_legend_label = True
                    self.subplot.figure.canvas.draw_idle()
            except:
                msg = "Add Text: Error. Check your property values..."
                logging.error(msg)
                if self.parent != None:
                    wx.PostEvent(self.parent, StatusEvent(status=msg))
        dial.Destroy()

    def _onEditDetector(self, event):
        """
        Allow to view and edits  detector parameters

        :param event: wx.menu event

        """
        import detector_dialog
        dialog = detector_dialog.DetectorDialog(
            self,
            -1,
            base=self.parent,
            reset_zmin_ctl=self.default_zmin_ctl,
            reset_zmax_ctl=self.default_zmax_ctl,
            cmap=self.cmap)
        ## info of current detector and data2D
        xnpts = len(self.data2D.x_bins)
        ynpts = len(self.data2D.y_bins)
        xmax = max(self.data2D.xmin, self.data2D.xmax)
        ymax = max(self.data2D.ymin, self.data2D.ymax)
        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
        ## set dialog window content
        dialog.setContent(xnpts=xnpts,
                          ynpts=ynpts,
                          qmax=qmax,
                          beam=self.data2D.xmin,
                          zmin=self.zmin_2D,
                          zmax=self.zmax_2D)
        if dialog.ShowModal() == wx.ID_OK:
            evt = dialog.getContent()
            self.zmin_2D = evt.zmin
            self.zmax_2D = evt.zmax
            self.cmap = evt.cmap
        dialog.Destroy()
        ## Redraw the current image
        self.image(data=self.data2D.data,
                   qx_data=self.data2D.qx_data,
                   qy_data=self.data2D.qy_data,
                   xmin=self.data2D.xmin,
                   xmax=self.data2D.xmax,
                   ymin=self.data2D.ymin,
                   ymax=self.data2D.ymax,
                   zmin=self.zmin_2D,
                   zmax=self.zmax_2D,
                   cmap=self.cmap,
                   color=0,
                   symbol=0,
                   label=self.data2D.name)
        self.subplot.figure.canvas.draw_idle()

    def freeze_axes(self):
        """
        """
        self.axes_frozen = True

    def thaw_axes(self):
        """
        """
        self.axes_frozen = False

    def onMouseMotion(self, event):
        """
        """
        pass

    def onWheel(self, event):
        """
        """
        pass

    def update(self, draw=True):
        """
        Respond to changes in the model by recalculating the
        profiles and resetting the widgets.
        """
        self.draw_plot()

    def _getEmptySlicerEvent(self):
        """
        create an empty slicervent
        """
        return SlicerEvent(type=None, params=None, obj_class=None)

    def _onEVT_INTERNAL(self, event):
        """
        Draw the slicer

        :param event: wx.lib.newevent (SlicerEvent) containing slicer
            parameter

        """
        self._setSlicer(event.slicer)

    def _setSlicer(self, slicer):
        """
        Clear the previous slicer and create a new one.Post an internal
        event.

        :param slicer: slicer class to create

        """
        ## Clear current slicer
        if not self.slicer == None:
            self.slicer.clear()
        ## Create a new slicer
        self.slicer_z += 1
        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
        ## Draw slicer
        self.update()
        self.slicer.update()
        msg = "Plotter2D._setSlicer  %s" % self.slicer.__class__.__name__
        wx.PostEvent(self.parent, StatusEvent(status=msg))
        # Post slicer event
        event = self._getEmptySlicerEvent()
        event.type = self.slicer.__class__.__name__
        event.obj_class = self.slicer.__class__
        event.params = self.slicer.get_params()
        wx.PostEvent(self, event)

    def onMaskedCircular(self, event):
        """
        perform circular averaging on Data2D with mask if it exists

        :param event: wx.menu event

        """
        self.onCircular(event, True)

    def onCircular(self, event, ismask=False):
        """
        perform circular averaging on Data2D

        :param event: wx.menu event

        """
        # Find the best number of bins
        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(
            self.data2D.data)]))
        npt = math.floor(npt)
        from sas.dataloader.manipulations import CircularAverage
        ## compute the maximum radius of data2D
        self.qmax = max(math.fabs(self.data2D.xmax),
                        math.fabs(self.data2D.xmin))
        self.ymax = max(math.fabs(self.data2D.ymax),
                        math.fabs(self.data2D.ymin))
        self.radius = math.sqrt(
            math.pow(self.qmax, 2) + math.pow(self.ymax, 2))
        ##Compute beam width
        bin_width = (self.qmax + self.qmax) / npt
        ## Create data1D circular average of data2D
        Circle = CircularAverage(r_min=0,
                                 r_max=self.radius,
                                 bin_width=bin_width)
        circ = Circle(self.data2D, ismask=ismask)
        from sas.guiframe.dataFitting import Data1D
        if hasattr(circ, "dxl"):
            dxl = circ.dxl
        else:
            dxl = None
        if hasattr(circ, "dxw"):
            dxw = circ.dxw
        else:
            dxw = None

        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
        new_plot.dxl = dxl
        new_plot.dxw = dxw
        new_plot.name = "Circ avg " + self.data2D.name
        new_plot.source = self.data2D.source
        #new_plot.info = self.data2D.info
        new_plot.interactive = True
        new_plot.detector = self.data2D.detector

        ## If the data file does not tell us what the axes are, just assume...
        new_plot.xaxis("\\rm{Q}", "A^{-1}")
        if hasattr(self.data2D, "scale") and \
                    self.data2D.scale == 'linear':
            new_plot.ytransform = 'y'
            new_plot.yaxis("\\rm{Residuals} ", "normalized")
        else:
            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")

        new_plot.group_id = "2daverage" + self.data2D.name
        new_plot.id = "Circ avg " + self.data2D.name
        new_plot.is_data = True
        self.parent.update_theory(data_id=self.data2D.id, \
                                       theory=new_plot)
        wx.PostEvent(self.parent,
                     NewPlotEvent(plot=new_plot, title=new_plot.name))

    def _onEditSlicer(self, event):
        """
        Is available only when a slicer is drawn.Create a dialog
        window where the user can enter value to reset slicer
        parameters.

        :param event: wx.menu event

        """
        if self.slicer != None:
            from SlicerParameters import SlicerParameterPanel
            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
            dialog.set_slicer(self.slicer.__class__.__name__,
                              self.slicer.get_params())
            if dialog.ShowModal() == wx.ID_OK:
                dialog.Destroy()

    def onSectorQ(self, event):
        """
        Perform sector averaging on Q and draw sector slicer
        """
        from SectorSlicer import SectorInteractor
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))

    def onSectorPhi(self, event):
        """
        Perform sector averaging on Phi and draw annulus slicer
        """
        from AnnulusSlicer import AnnulusInteractor
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))

    def onBoxSum(self, event):
        """
        """
        from sas.guiframe.gui_manager import MDIFrame
        from boxSum import BoxSum
        self.onClearSlicer(event)
        self.slicer_z += 1
        self.slicer = BoxSum(self, self.subplot, zorder=self.slicer_z)
        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
        self.update()
        self.slicer.update()
        ## Value used to initially set the slicer panel
        params = self.slicer.get_params()
        ## Create a new panel to display results of summation of Data2D
        from slicerpanel import SlicerPanel
        win = MDIFrame(self.parent, None, 'None', (100, 200))
        new_panel = SlicerPanel(parent=win,
                                id=-1,
                                base=self,
                                type=self.slicer.__class__.__name__,
                                params=params,
                                style=wx.RAISED_BORDER)

        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
                                    str(self.data2D.name)
        new_panel.window_name = self.slicer.__class__.__name__ + " " + \
                                    str(self.data2D.name)
        ## Store a reference of the new created panel

        ## save the window_caption of the new panel in the current slicer
        self.slicer.set_panel_name(name=new_panel.window_caption)
        ## post slicer panel to guiframe to display it
        from sas.guiframe.events import SlicerPanelEvent

        win.set_panel(new_panel)
        new_panel.frame = win
        wx.PostEvent(self.parent,
                     SlicerPanelEvent(panel=new_panel, main_panel=self))
        wx.CallAfter(new_panel.frame.Show)
        self.panel_slicer = new_panel

    def onBoxavgX(self, event):
        """
        Perform 2D data averaging on Qx
        Create a new slicer .

        :param event: wx.menu event
        """
        from boxSlicer import BoxInteractorX
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))

    def onBoxavgY(self, event):
        """
        Perform 2D data averaging on Qy
        Create a new slicer .

        :param event: wx.menu event

        """
        from boxSlicer import BoxInteractorY
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))

    def onClearSlicer(self, event):
        """
        Clear the slicer on the plot
        """
        if not self.slicer == None:
            self.slicer.clear()
            self.subplot.figure.canvas.draw()
            self.slicer = None
            # Post slicer None event
            event = self._getEmptySlicerEvent()
            wx.PostEvent(self, event)

    def _onSave(self, evt):
        """
        Save a data set to a dat(text) file

        :param evt: Menu event

        """
        event_id = str(evt.GetId())
        if self.parent != None:
            self._default_save_location = self.parent._default_save_location
        default_name = self.plots[self.graph.selected_plottable].label
        if default_name.count('.') > 0:
            default_name = default_name.split('.')[0]
        default_name += "_out"
        if event_id in self.action_ids:
            self.parent.save_data2d(self.data2D, default_name)

    def _onDataShow(self, evt):
        """
        Show the data set in text

        :param evt: Menu event

        """
        menu = evt.GetEventObject()
        event_id = evt.GetId()
        self.set_selected_from_menu(menu, event_id)
        data = self.plots[self.graph.selected_plottable]
        default_name = data.label
        if default_name.count('.') > 0:
            default_name = default_name.split('.')[0]
        #default_name += "_out"
        if self.parent != None:
            self.parent.show_data2d(data, default_name)

    def modifyGraphAppearance(self, e):
        self.graphApp = graphAppearance(self,
                                        'Modify graph appearance',
                                        legend=False)
        self.graphApp.setDefaults(
            self.grid_on, self.legend_on, self.xaxis_label, self.yaxis_label,
            self.xaxis_unit, self.yaxis_unit, self.xaxis_font, self.yaxis_font,
            find_key(self.get_loc_label(), self.legendLoc), self.xcolor,
            self.ycolor, self.is_xtick, self.is_ytick)
        self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)

    def on_graphApp_close(self, e):
        """
            Gets values from graph appearance dialog and sends them off
            to modify the plot
        """
        self.onGridOnOff(self.graphApp.get_togglegrid())
        self.xaxis_label = self.graphApp.get_xlab()
        self.yaxis_label = self.graphApp.get_ylab()
        self.xaxis_unit = self.graphApp.get_xunit()
        self.yaxis_unit = self.graphApp.get_yunit()
        self.xaxis_font = self.graphApp.get_xfont()
        self.yaxis_font = self.graphApp.get_yfont()
        self.is_xtick = self.graphApp.get_xtick_check()
        self.is_ytick = self.graphApp.get_ytick_check()
        if self.is_xtick:
            self.xaxis_tick = self.xaxis_font
        if self.is_ytick:
            self.yaxis_tick = self.yaxis_font

        self.xaxis(self.xaxis_label,
                   self.xaxis_unit, self.graphApp.get_xfont(),
                   self.graphApp.get_xcolor(), self.xaxis_tick)
        self.yaxis(self.yaxis_label,
                   self.yaxis_unit, self.graphApp.get_yfont(),
                   self.graphApp.get_ycolor(), self.yaxis_tick)

        self.graphApp.Destroy()
Exemple #12
0
class SmallPanel(PlotPanel):
    """
    PlotPanel for Quick plot and masking plot
    """
    def __init__(self, parent, id= -1, is_number=False, content='?', **kwargs):
        """
        """
        PlotPanel.__init__(self, parent, id=id, **kwargs)
        self.is_number = is_number
        self.content = content
        self.point = None
        self.position = (0.4, 0.5)
        self.scale = 'linear'
        self.prevXtrans = "x"
        self.prevYtrans = "y"
        self.viewModel = "--"
        self.subplot.set_xticks([])
        self.subplot.set_yticks([])
        self.add_text()
        self.figure.subplots_adjust(left=0.1, bottom=0.1)

    def set_content(self, content=''):
        """
        Set text content
        """
        self.content = str(content)

    def add_toolbar(self):
        """
        Add toolbar
        """
        # Not implemented
        pass

    def on_set_focus(self, event):
        """
        send to the parenet the current panel on focus
        """
        pass

    def add_image(self, plot):
        """
        Add Image
        """
        self.content = ''
        self.textList = []
        self.plots = {}
        self.clear()
        self.point = plot
        try:
            self.figure.delaxes(self.figure.axes[0])
            self.subplot = self.figure.add_subplot(111)
            #self.figure.delaxes(self.figure.axes[1])
        except:
            pass
        try:
            name = plot.name
        except:
            name = plot.filename
        self.plots[name] = plot

        #init graph
        self.graph = Graph()

        #add plot
        self.graph.add(plot)
        #draw        
        self.graph.render(self)

        try:
            self.figure.delaxes(self.figure.axes[1])
        except:
            pass
        self.subplot.figure.canvas.resizing = False
        self.subplot.tick_params(axis='both', labelsize=9)
        # Draw zero axis lines
        self.subplot.axhline(linewidth=1, color='r')
        self.subplot.axvline(linewidth=1, color='r')

        self.erase_legend()
        try:
            # mpl >= 1.1.0
            self.figure.tight_layout()
        except:
            self.figure.subplots_adjust(left=0.1, bottom=0.1)
        self.subplot.figure.canvas.draw()

    def add_text(self):
        """
        Text in the plot
        """
        if not self.is_number:
            return

        self.clear()
        try:
            self.figure.delaxes(self.figure.axes[0])
            self.subplot = self.figure.add_subplot(111)
            self.figure.delaxes(self.figure.axes[1])
        except:
            pass
        self.subplot.set_xticks([])
        self.subplot.set_yticks([])
        label = self.content
        FONT = FontProperties()
        xpos, ypos = (0.4, 0.5)
        font = FONT.copy()
        font.set_size(14)

        self.textList = []
        self.subplot.set_xlim((0, 1))
        self.subplot.set_ylim((0, 1))

        try:
            if self.content != '?':
                float(label)
        except:
            self.subplot.set_frame_on(False)
        try:
            # mpl >= 1.1.0
            self.figure.tight_layout()
        except:
            self.figure.subplots_adjust(left=0.1, bottom=0.1)
        if len(label) > 0 and xpos > 0 and ypos > 0:
            new_text = self.subplot.text(str(xpos), str(ypos), str(label),
                                           fontproperties=font)
            self.textList.append(new_text)

    def erase_legend(self):
        """
        Remove Legend
        """
        #for ax in self.axes:
        self.remove_legend(self.subplot)

    def onMouseMotion(self, event):
        """
        Disable dragging 2D image
        """

    def onWheel(self, event):
        """
        """

    def onLeftDown(self, event):
        """
        Disables LeftDown
        """

    def onPick(self, event):
        """
        Remove Legend
        """
        for ax in self.axes:
            self.remove_legend(ax)


    def draw(self):
        """
        Draw
        """
        if self.dimension == 3:
            pass
        else:
            self.subplot.figure.canvas.resizing = False
            self.subplot.tick_params(axis='both', labelsize=9)
            self.erase_legend()
            self.subplot.figure.canvas.draw_idle()
            try:
                self.figure.delaxes(self.figure.axes[1])
            except:
                pass


    def onContextMenu(self, event):
        """
        Default context menu for a plot panel
        """
        id = wx.NewId()
        slicerpop = wx.Menu()
        data = self.point
        if issubclass(data.__class__, Data1D):
            slicerpop.Append(id, '&Change Scale')
            wx.EVT_MENU(self, id, self._onProperties)
        else:
            slicerpop.Append(id, '&Toggle Linear/Log Scale')
            wx.EVT_MENU(self, id, self.ontogglescale)
        try:
            # mouse event
            pos_evt = event.GetPosition()
            pos = self.ScreenToClient(pos_evt)
        except:
            # toolbar event
            pos_x, pos_y = self.toolbar.GetPositionTuple()
            pos = (pos_x, pos_y + 5)
        self.PopupMenu(slicerpop, pos)

    def ontogglescale(self, event):
        """
        On toggle 2d scale
        """
        self._onToggleScale(event)
        try:
            # mpl >= 1.1.0
            self.figure.tight_layout()
        except:
            self.figure.subplots_adjust(left=0.1, bottom=0.1)
        try:
            self.figure.delaxes(self.figure.axes[1])
        except:
            pass

    def _onProperties(self, event):
        """
        when clicking on Properties on context menu ,
        The Property dialog is displayed
        The user selects a transformation for x or y value and
        a new plot is displayed
        """
        list = []
        list = self.graph.returnPlottable()
        if len(list.keys()) > 0:
            first_item = list.keys()[0]
            if first_item.x != []:
                from sas.plottools.PropertyDialog import Properties
                dial = Properties(self, -1, 'Change Scale')
                # type of view or model used
                dial.xvalue.Clear()
                dial.yvalue.Clear()
                dial.view.Clear()
                dial.xvalue.Insert("x", 0)
                dial.xvalue.Insert("log10(x)", 1)
                dial.yvalue.Insert("y", 0)
                dial.yvalue.Insert("log10(y)", 1)
                dial.view.Insert("--", 0)
                dial.view.Insert("Linear y vs x", 1)
                dial.setValues(self.prevXtrans, self.prevYtrans, self.viewModel)
                dial.Update()
                if dial.ShowModal() == wx.ID_OK:
                    self.xLabel, self.yLabel, self.viewModel = dial.getValues()
                    if self.viewModel == "Linear y vs x":
                        self.xLabel = "x"
                        self.yLabel = "y"
                        self.viewModel = "--"
                        dial.setValues(self.xLabel, self.yLabel, self.viewModel)
                    self._onEVT_FUNC_PROPERTY()
                dial.Destroy()

    def _onEVT_FUNC_PROPERTY(self, remove_fit=True):
        """
        Receive the x and y transformation from myDialog,
        Transforms x and y in View
        and set the scale
        """
        list = []
        list = self.graph.returnPlottable()
        # Changing the scale might be incompatible with
        # currently displayed data (for instance, going
        # from ln to log when all plotted values have
        # negative natural logs).
        # Go linear and only change the scale at the end.
        self.set_xscale("linear")
        self.set_yscale("linear")
        _xscale = 'linear'
        _yscale = 'linear'
        for item in list:
            item.setLabel(self.xLabel, self.yLabel)
            # control axis labels from the panel itself
            yname, yunits = item.get_yaxis()
            xname, xunits = item.get_xaxis()
            # Goes through all possible scales
            # Goes through all possible scales
            if(self.xLabel == "x"):
                item.transformX(transform.toX, transform.errToX)
                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
            if(self.xLabel == "log10(x)"):
                item.transformX(transform.toX_pos, transform.errToX_pos)
                _xscale = 'log'
                self.graph._xaxis_transformed("%s" % xname, "%s" % xunits)
            if(self.yLabel == "y"):
                item.transformY(transform.toX, transform.errToX)
                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
            if(self.yLabel == "log10(y)"):
                item.transformY(transform.toX_pos, transform.errToX_pos)
                _yscale = 'log'
                self.graph._yaxis_transformed("%s" % yname, "%s" % yunits)
            item.transformView()
        self.prevXtrans = self.xLabel
        self.prevYtrans = self.yLabel
        self.set_xscale(_xscale)
        self.set_yscale(_yscale)
        self.draw()
class SLDplotpanel(PlotPanel):
    """
    Panel
    """
    def __init__(self, parent, axes=[], id=-1, color=None, dpi=None, **kwargs):
        """
        """
        PlotPanel.__init__(self, parent, id=id, xtransform='x', ytransform='y',
                           color=color, dpi=dpi,
                           size=(_STATICBOX_WIDTH, PANEL_SIZE - 100), **kwargs)

        # Keep track of the parent Frame
        self.parent = parent
        self.window_name = "Scattering Length Density Profile"
        self.window_caption = self.window_name
        self.prevXtrans = "x"
        self.prevYtrans = "y"
        self.viewModel = "--"
        # Internal list of plottable names (because graph
        # doesn't have a dictionary of handles for the plottables)
        self.plots = {}
        self.graph = Graph()
        self.axes_label = []
        for idx in range(0, len(axes)):
            self.axes_label.append(axes[idx])
        self.xaxis_label = ''
        self.xaxis_unit = ''
        self.yaxis_label = ''
        self.yaxis_unit = ''
        self.resizing = True
        self.xcolor = 'black'
        self.ycolor = 'black'

    def add_image(self, plot):
        """
        Add image(Theory1D)
        """
        self.plots[plot.id] = plot
        self.plots[plot.id].is_data = True
        #add plot
        self.graph.add(plot)
        #add axes
        x1_label = self.axes_label[0]
        self.xaxis_label = '\\rm{%s} ' % x1_label
        self.xaxis_unit = 'A'
        self.graph.xaxis(self.xaxis_label, self.xaxis_unit)
        self.yaxis_label = '\\rm{SLD} '
        self.yaxis_unit = '10^{-6}A^{-2}'
        self.graph.yaxis(self.yaxis_label, self.yaxis_unit)
        # For latter scale changes
        self.plots[plot.id].xaxis('\\rm{%s} ' % x1_label, 'A')
        self.plots[plot.id].yaxis('\\rm{SLD} ', '10^{-6}A^{-2}')

    def on_set_focus(self, event):
        """
        send to the parenet the current panel on focus

        """
        #Not implemented
        pass

    def on_kill_focus(self, event):
        """
        reset the panel color

        """
        #Not implemented
        pass

    def onChangeCaption(self, event):
        """
        Not implemented
        """
        pass

    def _onSave(self, evt):
        """
        Save a data set to a text file

        :param evt: Menu event

        """
        menu = evt.GetEventObject()
        event_id = evt.GetId()
        self.set_selected_from_menu(menu, event_id)
        data = self.plots[self.graph.selected_plottable]
        default_name = data.label
        if default_name.count('.') > 0:
            default_name = default_name.split('.')[0]
        default_name += "_out"
        if self.parent != None:
            # What an ancestor!
            fit_panel = self.parent.parent.parent
            fit_panel._manager.parent.save_data1d(data, default_name)
Exemple #14
0
class SLDplotpanel(PlotPanel):
    """
    Panel
    """
    def __init__(self, parent, axes=[], id=-1, color=None, dpi=None, **kwargs):
        """
        """
        PlotPanel.__init__(self,
                           parent,
                           id=id,
                           xtransform='x',
                           ytransform='y',
                           color=color,
                           dpi=dpi,
                           size=(_STATICBOX_WIDTH, PANEL_SIZE - 100),
                           **kwargs)

        # Keep track of the parent Frame
        self.parent = parent
        self.window_name = "Scattering Length Density Profile"
        self.window_caption = self.window_name
        self.prevXtrans = "x"
        self.prevYtrans = "y"
        self.viewModel = "--"
        # Internal list of plottable names (because graph
        # doesn't have a dictionary of handles for the plottables)
        self.plots = {}
        self.graph = Graph()
        self.axes_label = []
        for idx in range(0, len(axes)):
            self.axes_label.append(axes[idx])
        self.xaxis_label = ''
        self.xaxis_unit = ''
        self.yaxis_label = ''
        self.yaxis_unit = ''
        self.resizing = True
        self.xcolor = 'black'
        self.ycolor = 'black'

    def add_image(self, plot):
        """
        Add image(Theory1D)
        """
        self.plots[plot.id] = plot
        self.plots[plot.id].is_data = True
        #add plot
        self.graph.add(plot)
        #add axes
        x1_label = self.axes_label[0]
        self.xaxis_label = '\\rm{%s} ' % x1_label
        self.xaxis_unit = 'A'
        self.graph.xaxis(self.xaxis_label, self.xaxis_unit)
        self.yaxis_label = '\\rm{SLD} '
        self.yaxis_unit = '10^{-6}A^{-2}'
        self.graph.yaxis(self.yaxis_label, self.yaxis_unit)
        # For latter scale changes
        self.plots[plot.id].xaxis('\\rm{%s} ' % x1_label, 'A')
        self.plots[plot.id].yaxis('\\rm{SLD} ', '10^{-6}A^{-2}')

    def on_set_focus(self, event):
        """
        send to the parenet the current panel on focus

        """
        #Not implemented
        pass

    def on_kill_focus(self, event):
        """
        reset the panel color

        """
        #Not implemented
        pass

    def onChangeCaption(self, event):
        """
        Not implemented
        """
        pass

    def _onSave(self, evt):
        """
        Save a data set to a text file

        :param evt: Menu event

        """
        menu = evt.GetEventObject()
        event_id = evt.GetId()
        self.set_selected_from_menu(menu, event_id)
        data = self.plots[self.graph.selected_plottable]
        default_name = data.label
        if default_name.count('.') > 0:
            default_name = default_name.split('.')[0]
        default_name += "_out"
        if self.parent != None:
            # What an ancestor!
            fit_panel = self.parent.parent.parent
            fit_panel._manager.parent.save_data1d(data, default_name)
Exemple #15
0
class SimplePlotPanel(PlotPanel):
    """
    PlotPanel for 1d and 2d
    """
    _window_caption = 'Simple Plot'

    def __init__(self,
                 parent,
                 id=-1,
                 color=None,
                 dpi=None,
                 style=wx.NO_FULL_REPAINT_ON_RESIZE,
                 **kwargs):
        """
        Init
        """
        PlotPanel.__init__(self, parent, id=id, style=style, **kwargs)

        self.SetColor(wx.WHITE)

        self.toolbar = NavigationToolBar(parent=self, canvas=self.canvas)
        self.toolbar.Show(False)
        self.scale = parent.scale
        self.window_caption = self._window_caption

    def draw(self):
        """
        """
        self.resizing = False
        self.canvas.set_resizing(self.resizing)
        self.canvas.draw()

    def add_toolbar(self):
        """
        """
        pass

    def onContextMenu(self, event):
        """
        2D plot context menu

        :param event: wx context event

        """
        slicerpop = PanelMenu()
        slicerpop.set_plots(self.plots)
        slicerpop.set_graph(self.graph)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Save Image')
        wx.EVT_MENU(self, wx_id, self.onSaveImage)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Print Image', 'Print image')
        wx.EVT_MENU(self, wx_id, self.onPrint)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Print Preview', 'Print preview')
        wx.EVT_MENU(self, wx_id, self.onPrinterPreview)

        wx_id = wx.NewId()
        slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
        wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)

        if self.dimension != 3:
            slicerpop.AppendSeparator()
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Toggle Grid On/Off',
                             'Toggle Grid On/Off')
            wx.EVT_MENU(self, wx_id, self.on_grid_onoff)

        if self.data.__class__.__name__ == 'Data1D':
            slicerpop.AppendSeparator()
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Change Scale')
            wx.EVT_MENU(self, wx_id, self._onProperties)
        elif self.data2D.__class__.__name__ == 'Data2D':
            slicerpop.AppendSeparator()
            wx_id = wx.NewId()
            slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
            wx.EVT_MENU(self, wx_id, self._onToggleScale)

        try:
            pos_evt = event.GetPosition()
            pos = self.ScreenToClient(pos_evt)
        except:
            pos_x, pos_y = self.toolbar.GetPositionTuple()
            pos = (pos_x, pos_y + 5)
        self.PopupMenu(slicerpop, pos)
        if self.scale != None:
            self.parent.scale2d = self.scale

    def on_grid_onoff(self, event):
        """
        On grid on/off
        """
        switch = (not self.grid_on)
        self.onGridOnOff(switch)

    def onLeftDown(self, event):
        """
        left button down and ready to drag

        """
        # Check that the LEFT button was pressed
        if event.button == 1:
            self.leftdown = True
            ax = event.inaxes
            if ax != None:
                self.xInit, self.yInit = event.xdata, event.ydata
                try:
                    pos_x = float(event.xdata)  # / size_x
                    pos_y = float(event.ydata)  # / size_y
                    pos_x = "%8.3g" % pos_x
                    pos_y = "%8.3g" % pos_y
                    self.position = str(pos_x), str(pos_y)
                    wx.PostEvent(self.parent,
                                 StatusEvent(status=self.position))
                except:
                    self.position = None

    def _OnReSize(self, event):
        """
        On response of the resize of a panel, set axes_visiable False
        """
        self.resizing = False
        if self.x_size != None:
            if self.x_size == self.GetSize():
                self.canvas.set_resizing(self.resizing)
                return
        self.x_size = self.GetSize()

        # Ready for another event
        # Do not remove this Skip.
        # Otherwise it will get runtime error on wx>=2.9.
        event.Skip()
        # set the resizing flag
        self.canvas.set_resizing(self.resizing)
        pos_x, pos_y = self.GetPositionTuple()
        if pos_x != 0 and pos_y != 0:
            self.size, _ = self.GetClientSizeTuple()
        self.SetSizer(self.sizer)

    def on_set_focus(self, event):
        """
        By pass default boundary blue color drawing
        """
        pass

    def on_kill_focus(self, event):
        """
        Reset the panel color
        """
        pass

    def show_plot(self, plot):
        """
        Show the plot
        """
        _yaxis, _yunit = plot.get_yaxis()
        _xaxis, _xunit = plot.get_xaxis()
        self.data = plot
        self.plots[plot.name] = plot
        # Axis scales
        if plot.xtransform != None:
            self.xLabel = plot.xtransform
        if plot.ytransform != None:
            self.yLabel = plot.ytransform
        # Init graph
        self.graph = Graph()
        # Add plot: Handles both 1D and 2D
        self.graph.add(self.data)
        self.canvas.set_resizing(False)
        if self.data.__class__.__name__ == 'Data2D':
            self.data2D = plot
        elif self.data.__class__.__name__ == 'Data1D':
            self._onEVT_FUNC_PROPERTY(show=False)
        # Axes
        self.graph.xaxis(_xaxis, _xunit)
        self.graph.yaxis(_yaxis, _yunit)
        self.xaxis(_xaxis, _xunit)
        self.yaxis(_yaxis, _yunit)
        self.set_xscale(self.xscale)
        self.set_yscale(self.yscale)
        self.graph.render(self)
Exemple #16
0
class Maskplotpanel(PlotPanel):
    """
    PlotPanel for Quick plot and masking plot
    """
    def __init__(self,
                 parent,
                 id=-1,
                 dimension=2,
                 color=None,
                 dpi=None,
                 **kwargs):
        """
        """
        PlotPanel.__init__(self, parent, id=id, color=color, dpi=dpi, **kwargs)

        # Keep track of the parent Frame
        self.parent = parent
        # Internal list of plottable names (because graph
        # doesn't have a dictionary of handles for the plottables)
        self.dimension = dimension
        self.plots = {}
        self.graph = Graph()
        # add axis labels
        self.graph.xaxis('\\rm{x} ', '')
        self.graph.yaxis('\\rm{y} ', '')

    def add_toolbar(self):
        """
        Add toolbar
        """
        # Not implemented
        pass

    def on_set_focus(self, event):
        """
        send to the parenet the current panel on focus
        """
        if self.dimension == 3:
            pass
        else:
            self.draw()

    def add_image(self, plot):
        """
        Add Image
        """
        self.plots[plot.name] = plot
        # init graph
        self.graph = Graph()
        # add plot
        self.graph.add(plot)
        # add axes
        if self.dimension == 1:
            self.xaxis_label = '\\rm{x} '
            self.xaxis_unit = ''
            self.yaxis_label = '\\rm{y} '
            self.yaxis_unit = ''
        # draw
        # message
        status_type = 'progress'
        msg = 'Plotting...'
        self._status_info(msg, status_type)
        status_type = 'stop'
        self.graph.render(self)
        self.subplot.figure.canvas.resizing = False
        if self.dimension < 3:
            self.graph.render(self)
            self.subplot.figure.canvas.draw()
        elif FONT_VARIANT:
            self.subplot.figure.canvas.draw()
        msg = 'Plotting Completed.'
        self._status_info(msg, status_type)

    def onMouseMotion(self, event):
        """
        Disable dragging 2D image
        """
        pass

    def onWheel(self, event):
        """
        """
        pass

    def onLeftDown(self, event):
        """
        Disables LeftDown
        """
        pass

    def onPick(self, event):
        """
        Disables OnPick
        """
        pass

    def draw(self):
        """
        Draw
        """
        # message
        status_type = 'progress'
        msg = 'Plotting...'
        self._status_info(msg, status_type)
        status_type = 'stop'

        if not self.dimension == 3:
            self.subplot.figure.canvas.draw_idle()

        msg = 'Plotting Completed.'
        self._status_info(msg, status_type)

    def onContextMenu(self, event):
        """
        Default context menu for a plot panel
        """
        # Selective Slicer plot popup menu
        slicerpop = wx.Menu()

        id = wx.NewId()
        slicerpop.Append(id, '&Print Image', 'Print image')
        wx.EVT_MENU(self, id, self.onPrint)

        id = wx.NewId()
        slicerpop.Append(id, '&Copy to Clipboard', 'Copy to the clipboard')
        wx.EVT_MENU(self, id, self.OnCopyFigureMenu)

        if self.dimension == 1:
            id = wx.NewId()
            slicerpop.Append(id, '&Change Scale')
            wx.EVT_MENU(self, id, self._onProperties)
        else:
            slicerpop.AppendSeparator()
            id_cm = wx.NewId()
            slicerpop.Append(id_cm, '&Toggle Linear/Log scale')
            wx.EVT_MENU(self, id_cm, self._onToggleScale)

        pos = event.GetPosition()
        pos = self.ScreenToClient(pos)
        self.PopupMenu(slicerpop, pos)

    def _status_info(self, msg='', type="update"):
        """
        Status msg
        """
        if self.parent.parent.parent != None:
            wx.PostEvent(self.parent.parent.parent,
                         StatusEvent(status=msg, type=type))
Exemple #17
0
class ModelPanel2D(ModelPanel1D):
    """
    Plot panel for use with the GUI manager
    """

    ## Internal name for the AUI manager
    window_name = "plotpanel"
    ## Title to appear on top of the window
    window_caption = "Plot Panel"
    ## Flag to tell the GUI manager that this panel is not
    #  tied to any perspective
    ALWAYS_ON = True
    ## Group ID
    group_id = None


    def __init__(self, parent, id=-1, data2d=None, color=None,
                 dpi=None, style=wx.NO_FULL_REPAINT_ON_RESIZE, **kwargs):
        """
        Initialize the panel
        """
        ModelPanel1D.__init__(self, parent, id=id, style=style, **kwargs)
        self.parent = parent
        ## Reference to the parent window
        if hasattr(parent, "parent"):
            self.parent = self.parent.parent
        ## Dictionary containing Plottables
        self.plots = {}
        ## Save reference of the current plotted
        self.data2D = data2d
        ## Unique ID (from gui_manager)
        self.uid = None
        ## Action IDs for internal call-backs
        self.action_ids = {}
        ## Create Artist and bind it
        self.connect = BindArtist(self.subplot.figure)
        ## Beam stop
        self.beamstop_radius = DEFAULT_BEAM
        ## to set the order of lines drawn first.
        self.slicer_z = 5
        ## Reference to the current slicer
        self.slicer = None
        ## event to send slicer info
        self.Bind(EVT_INTERNAL, self._onEVT_INTERNAL)

        self.axes_frozen = False
        ## panel that contains result from slicer motion (ex: Boxsum info)
        self.panel_slicer = None
        self.title_label = None
        self.title_font = None
        self.title_color = 'black'
        ## Graph
        self.graph = Graph()
        self.graph.xaxis("\\rm{Q}", 'A^{-1}')
        self.graph.yaxis("\\rm{Intensity} ", "cm^{-1}")
        self.graph.render(self)
        ## store default value of zmin and zmax
        self.default_zmin_ctl = self.zmin_2D
        self.default_zmax_ctl = self.zmax_2D

    def on_plot_qrange(self, event=None):
        """
        On Qmin Qmax vertical line event
        """
        # Not implemented
        if event == None:
            return
        event.Skip()

    def onLeftDown(self, event):
        """
        left button down and ready to drag

        """
        # Check that the LEFT button was pressed
        PlotPanel.onLeftDown(self, event)
        ax = event.inaxes
        if ax != None:
            # data coordinate position
            pos_x = "%8.3g" % event.xdata
            pos_y = "%8.3g" % event.ydata
            position = "x: %s    y: %s" % (pos_x, pos_y)
            wx.PostEvent(self.parent, StatusEvent(status=position))
        self.plottable_selected(self.data2D.id)
        self._manager.set_panel_on_focus(self)
        wx.PostEvent(self.parent, PanelOnFocusEvent(panel=self))

    def add_toolbar(self):
        """
        add toolbar
        """
        self.enable_toolbar = True
        self.toolbar = NavigationToolBar2D(parent=self, canvas=self.canvas)
        self.toolbar.Realize()
        # On Windows platform, default window size is incorrect, so set
        # toolbar width to figure width.
        _, th = self.toolbar.GetSizeTuple()
        fw, _ = self.canvas.GetSizeTuple()
        self.toolbar.SetSize(wx.Size(fw, th))
        self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND)
        # update the axes menu on the toolbar
        self.toolbar.update()

    def plot_data(self, data):
        """
        Data is ready to be displayed

        :TODO: this name should be changed to something more appropriate
             Don't forget that changing this name will mean changing code
             in plotting.py

        :param event: data event
        """
        xlo = None
        xhi = None
        ylo = None
        yhi = None
        if data.__class__.__name__ == 'Data1D':
            return
        ## Update self.data2d with the current plot
        self.data2D = data
        if data.id in self.plots.keys():
            #replace
            xlo, xhi = self.subplot.get_xlim()
            ylo, yhi = self.subplot.get_ylim()
            self.graph.replace(data)
            self.plots[data.id] = data
        else:
            self.plots[data.id] = data
            self.graph.add(self.plots[data.id])
            # update qmax with the new xmax of data plotted
            self.qmax = data.xmax
        self.slicer = None
        # Check axis labels
        #TODO: Should re-factor this
        ## render the graph with its new content
        #data2D: put 'Pixel (Number)' for axis title and unit in case of having no detector info and none in _units
        if len(data.detector) < 1:
            if len(data._xunit) < 1 and len(data._yunit) < 1:
                data._xaxis = '\\rm{x}'
                data._yaxis = '\\rm{y}'
                data._xunit = 'pixel'
                data._yunit = 'pixel'
        # graph properties
        self.graph.xaxis(data._xaxis, data._xunit)
        self.graph.yaxis(data._yaxis, data._yunit)
        if self._is_changed_legend_label:
            data.label = self.title_label
        if data.label == None:
            data.label = data.name
        if not self.title_font:
            self.graph.title(data.label)
            self.graph.render(self)
            # Set the axis labels on subplot
            self._set_axis_labels()
            self.draw_plot()
        else:
            self.graph.render(self)
            self.draw_plot()
            self.subplot.set_title(label=data.label,
                                   fontproperties=self.title_font,
                                   color=self.title_color)
            self.subplot.figure.canvas.draw_idle()
        ## store default value of zmin and zmax
        self.default_zmin_ctl = self.zmin_2D
        self.default_zmax_ctl = self.zmax_2D
        if not self.is_zoomed:
            return
        # Recover the x,y limits
        if xlo and xhi and ylo and yhi:
            if xlo > data.xmin and xhi < data.xmax and \
                        ylo > data.ymin and yhi < data.ymax:
                self.subplot.set_xlim((xlo, xhi))
                self.subplot.set_ylim((ylo, yhi))
            else:
                self.toolbar.update()
                self.is_zoomed = False

    def _set_axis_labels(self):
        """
        Set axis labels
        """
        data = self.data2D
        # control axis labels from the panel itself
        yname, yunits = data.get_yaxis()
        if self.yaxis_label != None:
            yname = self.yaxis_label
            yunits = self.yaxis_unit
        else:
            self.yaxis_label = yname
            self.yaxis_unit = yunits
        xname, xunits = data.get_xaxis()
        if self.xaxis_label != None:
            xname = self.xaxis_label
            xunits = self.xaxis_unit
        else:
            self.xaxis_label = xname
            self.xaxis_unit = xunits
        self.xaxis(xname, xunits, self.xaxis_font,
                   self.xaxis_color, self.xaxis_tick)
        self.yaxis(yname, yunits, self.yaxis_font,
                   self.yaxis_color, self.yaxis_tick)

    def onContextMenu(self, event):
        """
        2D plot context menu

        :param event: wx context event

        """
        ids = iter(self._menu_ids)
        slicerpop = PanelMenu()
        slicerpop.set_plots(self.plots)
        slicerpop.set_graph(self.graph)

        wx_id = ids.next()
        slicerpop.Append(wx_id, '&Save Image')
        wx.EVT_MENU(self, wx_id, self.onSaveImage)

        wx_id = ids.next()
        slicerpop.Append(wx_id, '&Print Image', 'Print image')
        wx.EVT_MENU(self, wx_id, self.onPrint)

        wx_id = ids.next()
        slicerpop.Append(wx_id, '&Copy to Clipboard', 'Copy to the clipboard')
        wx.EVT_MENU(self, wx_id, self.OnCopyFigureMenu)
        slicerpop.AppendSeparator()
        # saving data
        plot = self.data2D
        wx_id = ids.next()
        slicerpop.Append(wx_id, "&Data Info")
        wx.EVT_MENU(self, wx_id, self._onDataShow)

        wx_id = ids.next()
        slicerpop.Append(wx_id, "&Save as a File (DAT)")
        self.action_ids[str(wx_id)] = plot
        wx.EVT_MENU(self, wx_id, self._onSave)

        slicerpop.AppendSeparator()
        if len(self.data2D.detector) == 1:
            item_list = self.parent.get_current_context_menu(self)
            if (not item_list == None) and (not len(item_list) == 0) and\
                self.data2D.name.split(" ")[0] != 'Residuals':
                # The line above; Not for trunk
                # Note: reusing menu ids for the sub-menus.  See Plotter1D.
                for item, wx_id in zip(item_list, self._menu_ids):
                    try:
                        slicerpop.Append(wx_id, item[0], item[1])
                        wx.EVT_MENU(self, wx_id, item[2])
                    except:
                        msg = "ModelPanel1D.onContextMenu: "
                        msg += "bad menu item  %s" % sys.exc_value
                        wx.PostEvent(self.parent, StatusEvent(status=msg))
                slicerpop.AppendSeparator()

            wx_id = ids.next()
            slicerpop.Append(wx_id, '&Perform Circular Average')
            wx.EVT_MENU(self, wx_id, self.onCircular) \
            # For Masked Data
            if not plot.mask.all():
                wx_id = ids.next()
                slicerpop.Append(wx_id, '&Masked Circular Average')
                wx.EVT_MENU(self, wx_id, self.onMaskedCircular)
            wx_id = ids.next()
            slicerpop.Append(wx_id, '&Sector [Q View]')
            wx.EVT_MENU(self, wx_id, self.onSectorQ)
            wx_id = ids.next()
            slicerpop.Append(wx_id, '&Annulus [Phi View ]')
            wx.EVT_MENU(self, wx_id, self.onSectorPhi)
            wx_id = ids.next()
            slicerpop.Append(wx_id, '&Box Sum')
            wx.EVT_MENU(self, wx_id, self.onBoxSum)
            wx_id = ids.next()
            slicerpop.Append(wx_id, '&Box Averaging in Qx')
            wx.EVT_MENU(self, wx_id, self.onBoxavgX)
            wx_id = ids.next()
            slicerpop.Append(wx_id, '&Box Averaging in Qy')
            wx.EVT_MENU(self, wx_id, self.onBoxavgY)
            if self.slicer != None:
                wx_id = ids.next()
                slicerpop.Append(wx_id, '&Clear Slicer')
                wx.EVT_MENU(self, wx_id, self.onClearSlicer)
                if self.slicer.__class__.__name__ != "BoxSum":
                    wx_id = ids.next()
                    slicerpop.Append(wx_id, '&Edit Slicer Parameters')
                    wx.EVT_MENU(self, wx_id, self._onEditSlicer)
            slicerpop.AppendSeparator()

        wx_id = ids.next()
        slicerpop.Append(wx_id, '&Edit Graph Label', 'Edit Graph Label')
        wx.EVT_MENU(self, wx_id, self.onEditLabels)
        slicerpop.AppendSeparator()

        # ILL mod here

        wx_id = ids.next()
        slicerpop.Append(wx_id, '&Modify graph appearance', 'Modify graph appearance')
        wx.EVT_MENU(self, wx_id, self.modifyGraphAppearance)
        slicerpop.AppendSeparator()

        wx_id = ids.next()
        slicerpop.Append(wx_id, '&2D Color Map')
        wx.EVT_MENU(self, wx_id, self._onEditDetector)
        slicerpop.AppendSeparator()

        wx_id = ids.next()
        slicerpop.Append(wx_id, '&Toggle Linear/Log Scale')
        wx.EVT_MENU(self, wx_id, self._onToggleScale)

        slicerpop.AppendSeparator()
        wx_id = ids.next()
        slicerpop.Append(wx_id, '&Window Title')
        wx.EVT_MENU(self, wx_id, self.onChangeCaption)

        try:
            pos_evt = event.GetPosition()
            pos = self.ScreenToClient(pos_evt)
        except:
            pos_x, pos_y = self.toolbar.GetPositionTuple()
            pos = (pos_x, pos_y + 5)
        self.PopupMenu(slicerpop, pos)

    def onEditLabels(self, event):
        """
        Edit legend label
        """
        try:
            selected_plot = self.plots[self.graph.selected_plottable]
        except:
            selected_plot = self.plots[self.data2D.id]
        label = selected_plot.label
        dial = TextDialog(None, -1, 'Change Label', label)
        if dial.ShowModal() == wx.ID_OK:
            try:
                FONT = FontProperties()
                newlabel = dial.getText()
                font = FONT.copy()
                font.set_size(dial.getSize())
                font.set_family(dial.getFamily())
                font.set_style(dial.getStyle())
                font.set_weight(dial.getWeight())
                colour = dial.getColor()
                if len(newlabel) > 0:
                    # update Label
                    selected_plot.label = newlabel
                    self.graph.title(newlabel)
                    self.title_label = selected_plot.label
                    self.title_font = font
                    self.title_color = colour
                    ## render the graph
                    self.subplot.set_title(label=self.title_label,
                                           fontproperties=self.title_font,
                                           color=self.title_color)
                    self._is_changed_legend_label = True
                    self.subplot.figure.canvas.draw_idle()
            except:
                msg = "Add Text: Error. Check your property values..."
                logging.error(msg)
                if self.parent != None:
                    wx.PostEvent(self.parent, StatusEvent(status=msg))
        dial.Destroy()

    def _onEditDetector(self, event):
        """
        Allow to view and edits  detector parameters

        :param event: wx.menu event

        """
        import detector_dialog
        dialog = detector_dialog.DetectorDialog(self, -1, base=self.parent,
                                                reset_zmin_ctl=self.default_zmin_ctl,
                                                reset_zmax_ctl=self.default_zmax_ctl, cmap=self.cmap)
        ## info of current detector and data2D
        xnpts = len(self.data2D.x_bins)
        ynpts = len(self.data2D.y_bins)
        xmax = max(self.data2D.xmin, self.data2D.xmax)
        ymax = max(self.data2D.ymin, self.data2D.ymax)
        qmax = math.sqrt(math.pow(xmax, 2) + math.pow(ymax, 2))
        ## set dialog window content
        dialog.setContent(xnpts=xnpts, ynpts=ynpts, qmax=qmax,
                          beam=self.data2D.xmin,
                          zmin=self.zmin_2D,
                          zmax=self.zmax_2D)
        if dialog.ShowModal() == wx.ID_OK:
            evt = dialog.getContent()
            self.zmin_2D = evt.zmin
            self.zmax_2D = evt.zmax
            self.cmap = evt.cmap
        dialog.Destroy()
        ## Redraw the current image
        self.image(data=self.data2D.data,
                   qx_data=self.data2D.qx_data,
                   qy_data=self.data2D.qy_data,
                   xmin=self.data2D.xmin,
                   xmax=self.data2D.xmax,
                   ymin=self.data2D.ymin,
                   ymax=self.data2D.ymax,
                   zmin=self.zmin_2D,
                   zmax=self.zmax_2D,
                   cmap=self.cmap,
                   color=0, symbol=0, label=self.data2D.name)
        self.subplot.figure.canvas.draw_idle()

    def freeze_axes(self):
        """
        """
        self.axes_frozen = True

    def thaw_axes(self):
        """
        """
        self.axes_frozen = False

    def onMouseMotion(self, event):
        """
        """
        pass

    def onWheel(self, event):
        """
        """
        pass

    def update(self, draw=True):
        """
        Respond to changes in the model by recalculating the
        profiles and resetting the widgets.
        """
        self.draw_plot()

    def _getEmptySlicerEvent(self):
        """
        create an empty slicervent
        """
        return SlicerEvent(type=None, params=None, obj_class=None)

    def _onEVT_INTERNAL(self, event):
        """
        Draw the slicer

        :param event: wx.lib.newevent (SlicerEvent) containing slicer
            parameter

        """
        self._setSlicer(event.slicer)

    def _setSlicer(self, slicer):
        """
        Clear the previous slicer and create a new one.Post an internal
        event.

        :param slicer: slicer class to create

        """
        ## Clear current slicer
        if not self.slicer == None:
            self.slicer.clear()
        ## Create a new slicer
        self.slicer_z += 1
        self.slicer = slicer(self, self.subplot, zorder=self.slicer_z)
        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
        ## Draw slicer
        self.update()
        self.slicer.update()
        msg = "Plotter2D._setSlicer  %s" % self.slicer.__class__.__name__
        wx.PostEvent(self.parent, StatusEvent(status=msg))
        # Post slicer event
        event = self._getEmptySlicerEvent()
        event.type = self.slicer.__class__.__name__
        event.obj_class = self.slicer.__class__
        event.params = self.slicer.get_params()
        wx.PostEvent(self, event)

    def onMaskedCircular(self, event):
        """
        perform circular averaging on Data2D with mask if it exists

        :param event: wx.menu event

        """
        self.onCircular(event, True)

    def onCircular(self, event, ismask=False):
        """
        perform circular averaging on Data2D

        :param event: wx.menu event

        """
        # Find the best number of bins
        npt = math.sqrt(len(self.data2D.data[numpy.isfinite(self.data2D.data)]))
        npt = math.floor(npt)
        from sas.dataloader.manipulations import CircularAverage
        ## compute the maximum radius of data2D
        self.qmax = max(math.fabs(self.data2D.xmax),
                        math.fabs(self.data2D.xmin))
        self.ymax = max(math.fabs(self.data2D.ymax),
                        math.fabs(self.data2D.ymin))
        self.radius = math.sqrt(math.pow(self.qmax, 2) + math.pow(self.ymax, 2))
        ##Compute beam width
        bin_width = (self.qmax + self.qmax) / npt
        ## Create data1D circular average of data2D
        Circle = CircularAverage(r_min=0, r_max=self.radius,
                                 bin_width=bin_width)
        circ = Circle(self.data2D, ismask=ismask)
        from sas.guiframe.dataFitting import Data1D
        if hasattr(circ, "dxl"):
            dxl = circ.dxl
        else:
            dxl = None
        if hasattr(circ, "dxw"):
            dxw = circ.dxw
        else:
            dxw = None

        new_plot = Data1D(x=circ.x, y=circ.y, dy=circ.dy, dx=circ.dx)
        new_plot.dxl = dxl
        new_plot.dxw = dxw
        new_plot.name = "Circ avg " + self.data2D.name
        new_plot.source = self.data2D.source
        #new_plot.info = self.data2D.info
        new_plot.interactive = True
        new_plot.detector = self.data2D.detector

        ## If the data file does not tell us what the axes are, just assume...
        new_plot.xaxis("\\rm{Q}", "A^{-1}")
        if hasattr(self.data2D, "scale") and \
                    self.data2D.scale == 'linear':
            new_plot.ytransform = 'y'
            new_plot.yaxis("\\rm{Residuals} ", "normalized")
        else:
            new_plot.yaxis("\\rm{Intensity} ", "cm^{-1}")

        new_plot.group_id = "2daverage" + self.data2D.name
        new_plot.id = "Circ avg " + self.data2D.name
        new_plot.is_data = True
        self.parent.update_theory(data_id=self.data2D.id, \
                                       theory=new_plot)
        wx.PostEvent(self.parent,
                     NewPlotEvent(plot=new_plot, title=new_plot.name))

    def _onEditSlicer(self, event):
        """
        Is available only when a slicer is drawn.Create a dialog
        window where the user can enter value to reset slicer
        parameters.

        :param event: wx.menu event

        """
        if self.slicer != None:
            from SlicerParameters import SlicerParameterPanel
            dialog = SlicerParameterPanel(self, -1, "Slicer Parameters")
            dialog.set_slicer(self.slicer.__class__.__name__,
                              self.slicer.get_params())
            if dialog.ShowModal() == wx.ID_OK:
                dialog.Destroy()

    def onSectorQ(self, event):
        """
        Perform sector averaging on Q and draw sector slicer
        """
        from SectorSlicer import SectorInteractor
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=SectorInteractor))

    def onSectorPhi(self, event):
        """
        Perform sector averaging on Phi and draw annulus slicer
        """
        from AnnulusSlicer import AnnulusInteractor
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=AnnulusInteractor))

    def onBoxSum(self, event):
        """
        """
        from sas.guiframe.gui_manager import MDIFrame
        from boxSum import BoxSum
        self.onClearSlicer(event)
        self.slicer_z += 1
        self.slicer = BoxSum(self, self.subplot, zorder=self.slicer_z)
        self.subplot.set_ylim(self.data2D.ymin, self.data2D.ymax)
        self.subplot.set_xlim(self.data2D.xmin, self.data2D.xmax)
        self.update()
        self.slicer.update()
        ## Value used to initially set the slicer panel
        params = self.slicer.get_params()
        ## Create a new panel to display results of summation of Data2D
        from slicerpanel import SlicerPanel
        win = MDIFrame(self.parent, None, 'None', (100, 200))
        new_panel = SlicerPanel(parent=win, id=-1,
                                base=self, type=self.slicer.__class__.__name__,
                                params=params, style=wx.RAISED_BORDER)

        new_panel.window_caption = self.slicer.__class__.__name__ + " " + \
                                    str(self.data2D.name)
        new_panel.window_name = self.slicer.__class__.__name__ + " " + \
                                    str(self.data2D.name)
        ## Store a reference of the new created panel

        ## save the window_caption of the new panel in the current slicer
        self.slicer.set_panel_name(name=new_panel.window_caption)
        ## post slicer panel to guiframe to display it
        from sas.guiframe.events import SlicerPanelEvent

        win.set_panel(new_panel)
        new_panel.frame = win
        wx.PostEvent(self.parent, SlicerPanelEvent(panel=new_panel,
                                                   main_panel=self))
        wx.CallAfter(new_panel.frame.Show)
        self.panel_slicer = new_panel

    def onBoxavgX(self, event):
        """
        Perform 2D data averaging on Qx
        Create a new slicer .

        :param event: wx.menu event
        """
        from boxSlicer import BoxInteractorX
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorX))

    def onBoxavgY(self, event):
        """
        Perform 2D data averaging on Qy
        Create a new slicer .

        :param event: wx.menu event

        """
        from boxSlicer import BoxInteractorY
        self.onClearSlicer(event)
        wx.PostEvent(self, InternalEvent(slicer=BoxInteractorY))

    def onClearSlicer(self, event):
        """
        Clear the slicer on the plot
        """
        if not self.slicer == None:
            self.slicer.clear()
            self.subplot.figure.canvas.draw()
            self.slicer = None
            # Post slicer None event
            event = self._getEmptySlicerEvent()
            wx.PostEvent(self, event)

    def _onSave(self, evt):
        """
        Save a data set to a dat(text) file

        :param evt: Menu event

        """
        event_id = str(evt.GetId())
        if self.parent != None:
            self._default_save_location = self.parent._default_save_location
        default_name = self.plots[self.graph.selected_plottable].label
        if default_name.count('.') > 0:
            default_name = default_name.split('.')[0]
        default_name += "_out"
        if event_id in self.action_ids:
            self.parent.save_data2d(self.data2D, default_name)

    def _onDataShow(self, evt):
        """
        Show the data set in text

        :param evt: Menu event

        """
        menu = evt.GetEventObject()
        event_id = evt.GetId()
        self.set_selected_from_menu(menu, event_id)
        data = self.plots[self.graph.selected_plottable]
        default_name = data.label
        if default_name.count('.') > 0:
            default_name = default_name.split('.')[0]
        #default_name += "_out"
        if self.parent != None:
            self.parent.show_data2d(data, default_name)

    def modifyGraphAppearance(self, e):
        self.graphApp = graphAppearance(self, 'Modify graph appearance', legend=False)
        self.graphApp.setDefaults(self.grid_on, self.legend_on,
                                  self.xaxis_label, self.yaxis_label,
                                  self.xaxis_unit, self.yaxis_unit,
                                  self.xaxis_font, self.yaxis_font,
                                  find_key(self.get_loc_label(), self.legendLoc),
                                  self.xcolor, self.ycolor,
                                  self.is_xtick, self.is_ytick)
        self.graphApp.Bind(wx.EVT_CLOSE, self.on_graphApp_close)

    def on_graphApp_close(self, e):
        """
            Gets values from graph appearance dialog and sends them off
            to modify the plot
        """
        self.onGridOnOff(self.graphApp.get_togglegrid())
        self.xaxis_label = self.graphApp.get_xlab()
        self.yaxis_label = self.graphApp.get_ylab()
        self.xaxis_unit = self.graphApp.get_xunit()
        self.yaxis_unit = self.graphApp.get_yunit()
        self.xaxis_font = self.graphApp.get_xfont()
        self.yaxis_font = self.graphApp.get_yfont()
        self.is_xtick = self.graphApp.get_xtick_check()
        self.is_ytick = self.graphApp.get_ytick_check()
        if self.is_xtick:
            self.xaxis_tick = self.xaxis_font
        if self.is_ytick:
            self.yaxis_tick = self.yaxis_font

        self.xaxis(self.xaxis_label, self.xaxis_unit,
                   self.graphApp.get_xfont(), self.graphApp.get_xcolor(),
                   self.xaxis_tick)
        self.yaxis(self.yaxis_label, self.yaxis_unit,
                   self.graphApp.get_yfont(), self.graphApp.get_ycolor(),
                   self.yaxis_tick)

        self.graphApp.Destroy()