Пример #1
0
    def matplotCanvas(self):
        f = Figure(figsize=(5, 5), dpi=100)
        a = f.add_subplot(111)
        a.plot([1, 2, 3, 4, 5, 6, 7, 8], [5, 6, 1, 3, 8, 9, 3, 5])

        canvas = FigureCanvasAgg(f, self)
        canvas.show()

        canvas.get_tk_widget().pack(side=BOTTOM, fill=BOTH, expand=True)
Пример #2
0
class PlotWrap(object):
    __debug = False
    __keyArgDict =  {
        'title' : None,
        'winTitle' : None,
        'xlabel' : None,
        'xticks' : None,
        'ylabel' : None,
        'yticks' : None,
        'ylog' : False, 
        'xlog' : False, 
        'ybound' : (None,None),
        'xbound' : (None,None),
        'legend' : None,
        'style' : None,
        'aging' : None,
        'alphaMin' : 0.02,
        'agingCull' : True,
        'bball' : None,
        'accum' : False,
        'showByDefault' : True,
        'makeWinByDefault': True,
        'axes' :  None,
        'axesRect' :  None,
        'axprops' :  {},
        'figsize' : (5,4),
        'dpi' : 100,
        'window' :  None,
        'as3D' : False,
        }
    def __init__(self,
                 **keyArgs
                 ):
        
        # defaults
        for parm, val in self.__keyArgDict.iteritems():
            self.__setattr__(parm, val)
        #
        # parse keyword args
        for keyArg in self.getKeyArgList():
            if keyArgs.has_key(keyArg):
                self.__setattr__(keyArg, keyArgs.pop(keyArg))
        if len(keyArgs) > 0:
            raise RuntimeError, 'unparsed keyword args : '+str(keyArgs)
        #
        window = self.window
        del self.window
        #
        self.x_accum = self.accum
        del self.accum
        #
        axes = self.axes
        del self.axes
        
        self.x_prev = None
        self.x_store = [[],[]]

        self.win = None
        self.a   = None
        self.canvas = None
        
        self.ownCanvas = True
        if window is None:
            self.ownCanvas = True
            'checking self.showByDefault here causes trouble because it is hard to attach a figure to a window later for a general backend ***'
            if self.showByDefault or self.makeWinByDefault:
                # 'go ahead and make a window, using PlotWinP to increase backend flexibility'
                # self.win    = ...PlotWinP(as3D=self.as3D, figsize=self.figsize, dpi=self.dpi)
                # self.a      = self.win.getAxes(0)
                # self.f      = self.win.getFigure()
                # self.canvas = self.win.getCanvas()
                # self.a.set_autoscale_on(True)
                self.__checkWin()
                self.f = self.win.f
            else:
                from matplotlib.figure import Figure
                self.f = Figure(figsize=self.figsize, dpi=self.dpi)
            if self.as3D:
                import mpl_toolkits.mplot3d.axes3d as p3
                self.a = p3.Axes3D(self.f)
            else:
                if self.axesRect is None:
                    self.a = self.f.add_subplot(1, 1, 1, **self.axprops)
                else:
                    self.a = self.f.add_axes(self.axesRect, **self.axprops)
                
            if axes is not None:
                raise RuntimeError, 'do not specify axes when have not passed a window'
        else:
            self.ownCanvas = False
            self.win = window
            self.canvas = self.win.getCanvas()
            self.f = self.win.getFigure()
            if axes is None:
                if self.__debug: print 'using axprops: '+str(self.axprops)
                self.a = self.win.getNextAxes(rect=self.axesRect, attachPW=self, **self.axprops)
            elif isinstance(axes, int):
                self.a = self.win.getAxes(axes, **self.axprops)
            else:
                self.a = axes
        #
        self.clear() # sets labels and so forth

        # self.style = style # can be None
        # self.bball = bball # can be None
        #
        #self.aging = aging
        #self.agingCull = agingCull
        #self.alphaMin = alphaMin
        self.agingNumAge = -1
        if self.aging is not None:
            from math import log
            self.agingNumAge = max(int(log(self.alphaMin)/log(self.aging)),1)
        self.plotProps = {}
        # self.lineListList = [] # not needed, can, and should, use a.lines
        
        self.asImIJ = False
        # self.transform = None
        self.axIm = None
        self.__colorbar = None

        return
    def add_axes(self, arect, kwAddAxes={}, **kwarg):
        aNew = self.f.add_axes(arect, **kwAddAxes)
        # self.a.set_position((0.05, 0.05, 0.45, 0.9))
        new = self.__class__(window=self.win, axes=aNew, **kwarg)
        return new
    @classmethod
    def popKeyArgs(cls, kwargs):
        retval = {}
        for key in cls.getKeyArgList():
            if kwargs.has_key(key):
                retval[key] = kwargs.pop(key)
        return retval
    @classmethod
    def getKeyArgList(cls):
        return cls.__keyArgDict.keys()
    def __checkCanvas(self):
        'leave dead True, not checking for window, just for canvas'
        #from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
        if self.win is not None: return
        if self.canvas is not None: return

        from matplotlib.backends.backend_tkagg import FigureCanvasAgg
        
        self.canvas = FigureCanvasAgg(self.f)
        if hasattr(self.a,'mouse_init'):
            self.a.mouse_init()
        return

    def __checkWin(self):
        if self.win is not None: return
        winTitle = self.winTitle
        if winTitle is None : winTitle = self.title
        if winTitle is None : winTitle = 'plotWin'
        if hasattr(self,'f'):
            self.win = PlotWin(1,1,title=winTitle, relfigsize=self.figsize, figure=self.f, axesList=[self.a])
        else:
            self.win = PlotWin(1,1,title=winTitle, relfigsize=self.figsize, axesList=[self.a])
        #self.win = PlotWinP(title=winTitle, figure=self.f, axes=self.a)
        self.canvas = self.win.getCanvas()
        return
    def removeLines(self):
        lines = self.a.get_lines()
        for line in lines:
            line.remove()
        if self.showByDefault:
            self.show() # self.canvas.show()
        return
    def show(self):
        self.__checkWin()
        if self.legend is not None:
            pass # do not yet have this right
            # if isinstance(self.legend, str) or isinstance(self.legend, int): #  or hasattr(self.legend,'__len__')
            #     self.a.legend(loc=self.legend)
            # elif isinstance(self.legend, bool):
            #     self.a.legend()
            # elif isinstance(self.legend, list):
            #     self.a.legend(*self.legend)
            # elif isinstance(self.legend, dict):
            #     self.a.legend(**self.legend)
            # else:
            #     raise RuntimeError, 'do not know what to do with legend specification: '+str(self.legend)
        if hasattr(self.a,'mouse_init'):
            self.a.mouse_init()
        if hasattr(self.f, 'show'):
            self.f.show()
        elif hasattr(self.canvas, 'show'):
            self.canvas.show()
        else:
            raise RuntimeError, 'do not know how to do show'
        return
    def clear(self):
        self.asImIJ = False
        self.axIm = None
        # self.transform = None
        self.x_prev = None
        self.__colorbar = None
        self.x_store = [[],[]]
        if self.showByDefault:
            self.__checkWin()
        if self.a is not None:
            if hasattr(self.a,'mouse_init'):
                'doing a.clear() seems like it causes trouble with plotting collections?' 
                self.a.clear() # self.a.cla()
                self.a.set_autoscale_on(True)
            else:
                self.a.clear() # self.a.cla()
                self.a.set_autoscale_on(True)
        if self.xticks is not None:
            self.a.set_xticks(self.xticks)
        if self.title is not None:
            self.a.set_title(self.title)
        if self.xlabel is not None:
            self.a.set_xlabel(self.xlabel)  # r'X axis label $\mu\mbox{lentz}$'
            if self.win is not None:
                'make some room for the label'
                self.win.haveXLabels()
        if self.yticks is not None:
            self.a.set_yticks(self.yticks)
        if self.xlog: self.a.set_xscale('log')
        if self.ylog: self.a.set_yscale('log')
        #self.a.set_ybound(self.ybound)
        self.a.set_ylim(ymin=self.ybound[0], ymax=self.ybound[1])
        self.a.set_xlim(xmin=self.xbound[0], xmax=self.xbound[1])
        if self.ylabel is not None:
            self.a.set_ylabel(self.ylabel)
            if self.win is not None:
                'make some room for the label'
                self.win.haveYLabels()
        if self.legend is not None:
            pass # do not yet have this right
            # if isinstance(self.legend, str) or isinstance(self.legend, int): #  or hasattr(self.legend,'__len__')
            #     self.a.legend(loc=self.legend)
            # elif isinstance(self.legend, bool):
            #     self.a.legend()
            # elif isinstance(self.legend, list):
            #     self.a.legend(*self.legend)
            # elif isinstance(self.legend, dict):
            #     self.a.legend(**self.legend)
            # else:
            #     raise RuntimeError, 'do not know what to do with legend specification: '+str(self.legend)
        if self.a is not None:
            self.a.set_autoscale_on(True)
        if self.showByDefault:
            self.show() # self.canvas.show()
        return
    def setLegend(self, val=True):
        # if self.legend is None:
        #     self.legend = True
        # if val is not None:
        #     self.legend = val
        self.legend = val
        return
    def save(self, **keyArgs):
        '''make hardcopy of the current figure;
        specify filename or prefix keyword argument
        '''
        import numpy as num
        
        filename = None
        prefix = None
        if keyArgs.has_key('filename'):
            filename = keyArgs.pop('filename')
        if keyArgs.has_key('prefix'):
            prefix = keyArgs.pop('prefix')
            filename = prefix+'.pdf' # .eps
        
        if prefix is not None:
            'export data'
            if len(self.x_store[0]) > 0:
                dataFilename = prefix+'.data'
                from hexrd import arrayUtil
                try:
                    arrayUtil.writeArray(dataFilename, num.array(self.x_store))
                except:
                    import sys
                    print 'problem writing to '+dataFilename+' : '+str(self.x_store)
                    sys.exit(1)
        
        if not self.ownCanvas:
            if self.__debug:
                print 'skipping print_figure because this plot does not own its canvas'
        else:
            self.__checkCanvas()
            if filename is None:
                raise RuntimeError, 'need filename or prefix entry in keyArgs'
            #self.canvas.print_figure(filename, **keyArgs)
            self.f.savefig(filename, **keyArgs)
        
        return
    def destroy(self):
        'does not clean up self.a, just kills the window if this plot owns the window'
        if self.ownCanvas and self.win is not None:
            self.win.destroy()
        return
    def drawBBox(self, bbox, **kwargs):
        import numpy as num
        bbox_x = bbox[0]
        bbox_y = bbox[1]
        xBBox = num.array([ bbox_x[0], bbox_x[1], bbox_x[1], bbox_x[0], bbox_x[0] ])
        yBBox = num.array([ bbox_y[0], bbox_y[0], bbox_y[1], bbox_y[1], bbox_y[0] ])
        'go through call, instead of callXY, in case of asImIJ'
        self.__call__(xBBox, yBBox, **kwargs)
        return
    def __call__(self, *args, **keyArgs):
        import numpy as num
        noShow = False
        retVal = None
        # if keyArgs.has_key('transform'):
        #     'pop transform so that can keep it for other (overlaid) plots'
        #     self.transform = keyArgs.pop('transform')
        if keyArgs.has_key('noShow'):
            noShow = keyArgs.pop('noShow')
        if len(args) == 2:
            alphas = None
            if self.asImIJ:
                x = args[1]
                y = args[0]
            else:
                x = args[0]
                y = args[1]
            if keyArgs.has_key('alphas'):
                alphas = keyArgs.pop('alphas')
                assert len(args) == 2, 'len(args) != 2'
                assert len(alphas) == len(y), 'len(alphas) != len(y)'
                self.x_prev = None
                for iX in range(len(x)):
                    self.callXY([x[iX]],[y[iX]],alpha=alphas[iX],**keyArgs)
            else:
                self.callXY(x, y, **keyArgs)
        elif len(args) == 3:
            X = args[0]; Y = args[1]; data = args[2];
            cont = self.callContour(X, Y, data, **keyArgs)
            retVal = cont
        elif len(args) == 1 and isinstance(args[0],str):
            'interpret string as name of a file to plot in axes'
            filename = args[0]
            im = self.callImage(filename, **keyArgs)
            retVal = im
        elif len(args) == 1 and isinstance(args[0],num.ndarray):
            im = self.callIm(args[0], **keyArgs)
            retVal = im
        else:
            raise RuntimeError, 'do not know what to do with args'
        self.a.set_ylim(ymin=self.ybound[0], ymax=self.ybound[1])
        self.a.set_xlim(xmin=self.xbound[0], xmax=self.xbound[1])
        if not noShow:
            if self.showByDefault:
                self.show()
        return retVal
    def callImage(self, filename, 
                  **keyArgs):
        import Image
        im = Image.open(filename)
        s = im.tostring() # convert PIL image -> string
        import numpy as num
        rgb = num.fromstring(s, dtype=num.uint8).astype(num.float)/255.0 # convert string -> array of floats
        rgb = num.resize(rgb, (im.size[1], im.size[0], 3)) # resize to RGB array
        retval = self.callIm(rgb, **keyArgs)
        return retval
    def callIm(self, im, 
               interpolation='nearest', aspect='equal', 
               ijAsXY=False,
               clear=True, **keyArgs):
        if clear: 
            self.clear()
        self.a.axis('off')
        self.a.set_autoscale_on(True)
        if ijAsXY:
            self.asImIJ = False
            'imshow does not yet really support transform'
            if len(im.shape) == 3:
                imT = im.transpose(1,0,2)
            else:
                imT = im.T
            axIm = self.a.imshow(imT, 
                                 interpolation=interpolation, aspect=aspect, origin='lower', 
                                 # transform=self.transform,
                                 **keyArgs)
            self.a.format_coord = lambda x,y: 'i=%d; j=%d; val=%s' % \
                (round(x), round(y), str(im[round(x),round(y)]))
        else:
            self.asImIJ = True
            'imshow does not yet really support transform'
            axIm = self.a.imshow(im, 
                                 interpolation=interpolation, aspect=aspect, 
                                 # transform=self.transform,
                                 **keyArgs)
            self.a.format_coord = lambda x,y: 'i=%d; j=%d; val=%s' % \
                (round(y), round(x), str(im[round(y),round(x)]))
        'turn off autoscale so that axis limits do not get reset on replots'
        self.axIm = axIm
        self.mappable = axIm
        self.a.set_autoscale_on(False)
        return axIm
    def callContour(self, X, Y, data, 
                    interpolation=None, aspect=None,
                    **keyArgs):
        pp = {}
        pp.update(self.plotProps)
        pp.update(keyArgs) # plotProps
        #cont = self.a.contourf(X, Y, data, 200, **keyArgs)
        'imshow does not yet really support transform'
        self.a.set_autoscale_on(True)
        cont = self.a.imshow(data, origin='lower',
                             extent=(X[0,0],X[0,-1],Y[0,0],Y[-1,0]), 
                             interpolation=interpolation,
                             aspect=aspect,
                             # transform=self.transform,
                             **keyArgs)
        self.a.set_autoscale_on(False)
        self.mappable = cont
        return cont
    def discontXY(self):
        self.x_prev = None
        return
    def callXY(self, x, y, style=None, **keyArgs):
        assert len(x) == len(y), \
               'x and y must be same length'

        xUse = x
        yUse = y
        if len(x) == 1:
            if self.x_prev is not None:
                xUse = []; xUse.append(self.x_prev[0]); xUse.append(x)
                yUse = []; yUse.append(self.x_prev[1]); yUse.append(y)

        pp = {}
        pp.update(self.plotProps)
        pp.update(keyArgs) # plotProps
        if self.bball is not None:
            'first, get rid of last bball'
            lenCur = len(self.a.lines)
            if lenCur>0:
                self.a.lines = self.a.lines[0:lenCur-1]
        if self.aging is not None:
            #for lineList in self.lineListList[:-1]:
            #    for line in lineList:
            lenCur = len(self.a.lines)
            for line in self.a.lines[max(0,lenCur-self.agingNumAge):lenCur]:
                alphaCur = line.get_alpha()
                line.set_alpha(alphaCur*self.aging)
            if self.agingCull:
                if lenCur > self.agingNumAge:
                    self.a.lines = self.a.lines[lenCur-self.agingNumAge:lenCur]
        if style is not None:
            'passing transform of None can cause trouble'
            lines = self.a.plot(xUse, yUse, style,
                                # transform=self.transform,
                                **pp)
        elif self.style is not None:
            #self.lineListList.append(self.a.plot(x,y,self.style,**pp))
            lines = self.a.plot(xUse, yUse, self.style,
                                # transform=self.transform,
                                **pp)
        else:
            #self.lineListList.append(self.a.plot(x,y,**pp))
            lines = self.a.plot(xUse, yUse, 
                                # transform=self.transform,
                                **pp)
        if self.bball is not None:
            'add bball at end'
            self.a.plot([x[-1]],[y[-1]], self.bball)
            # transform=self.transform
        if len(x) == 1:
            if self.x_accum:
                self.x_prev = [x, y]
            self.x_store[0] = self.x_store[0] + list(x)
            self.x_store[1] = self.x_store[1] + list(y) 
        else:
            self.x_prev = None
            if len(x) == len(self.x_store[0]):
                'assume called with the same x values'
                self.x_store.append(list(y))
            else:
                self.x_store[0] = list(x)
                self.x_store[1] = list(y) 
        return
    def setVMM(self, vMM):
        if type(vMM) == int:
            iCol = vMM
            vMM = self.a.collections[iCol].get_clim()
        for col in self.a.collections:
            col.set_clim(vmin=vMM[0],vmax=vMM[1])
        return
    def colorbar(self, rect=(0.80,0.1,0.05,0.8), adjustPos=True, thing=None, **kwargs):
        '''
        if set rect to None, then colorbar steals self.a
        '''
        self.__checkWin()
        w = self.win
        f = self.f
        if len(self.a.collections) > 0:
            self.setVMM(0)
        if thing is None:
            if len(self.a.collections) > 0:
                thing = self.a.collections[0]
            elif hasattr(self, 'mappable'):
                thing = self.mappable
            else:
                raise RuntimeError, 'do not know what to colobar, pass in a thing'
        if rect is None:
            self.__colorbar = f.colorbar(thing, ax=self.a)
        else:
            cax = w.getNextAxes(rect=rect)
            self.__colorbar = f.colorbar(thing, cax=cax)
            if adjustPos:
                'adjust existing position to make room for colorbar'
                bbox = self.a.get_position().get_points()
                arect = (bbox[0,0], # left
                         bbox[0,1], # bottom
                         rect[0]-bbox[0,0]-0.02, # width
                         bbox[1,1]-bbox[0,1], # height
                         ) 
                self.a.set_position(arect) 
        self.show()
        return
Пример #3
0
class PlotWrap(object):
    __debug = False
    __keyArgDict =  {
        'title' : None,
        'winTitle' : None,
        'xlabel' : None,
        'xticks' : None,
        'ylabel' : None,
        'yticks' : None,
        'ylog' : False,
        'xlog' : False,
        'ybound' : (None,None),
        'xbound' : (None,None),
        'legend' : None,
        'style' : None,
        'aging' : None,
        'alphaMin' : 0.02,
        'agingCull' : True,
        'bball' : None,
        'accum' : False,
        'showByDefault' : True,
        'makeWinByDefault': True,
        'axes' :  None,
        'axesRect' :  None,
        'axprops' :  {},
        'figsize' : (5,4),
        'dpi' : 100,
        'window' :  None,
        'as3D' : False,
        }
    def __init__(self,
                 **keyArgs
                 ):

        # defaults
        for parm, val in self.__keyArgDict.iteritems():
            self.__setattr__(parm, val)
        #
        # parse keyword args
        for keyArg in self.getKeyArgList():
            if keyArgs.has_key(keyArg):
                self.__setattr__(keyArg, keyArgs.pop(keyArg))
        if len(keyArgs) > 0:
            raise RuntimeError, 'unparsed keyword args : '+str(keyArgs)
        #
        window = self.window
        del self.window
        #
        self.x_accum = self.accum
        del self.accum
        #
        axes = self.axes
        del self.axes

        self.x_prev = None
        self.x_store = [[],[]]

        self.win = None
        self.a   = None
        self.canvas = None

        self.ownCanvas = True
        if window is None:
            self.ownCanvas = True
            'checking self.showByDefault here causes trouble because it is hard to attach a figure to a window later for a general backend ***'
            if self.showByDefault or self.makeWinByDefault:
                # 'go ahead and make a window, using PlotWinP to increase backend flexibility'
                # self.win    = ...PlotWinP(as3D=self.as3D, figsize=self.figsize, dpi=self.dpi)
                # self.a      = self.win.getAxes(0)
                # self.f      = self.win.getFigure()
                # self.canvas = self.win.getCanvas()
                # self.a.set_autoscale_on(True)
                self.__checkWin()
                self.f = self.win.f
            else:
                from matplotlib.figure import Figure
                self.f = Figure(figsize=self.figsize, dpi=self.dpi)
            if self.as3D:
                import mpl_toolkits.mplot3d.axes3d as p3
                self.a = p3.Axes3D(self.f)
            else:
                if self.axesRect is None:
                    self.a = self.f.add_subplot(1, 1, 1, **self.axprops)
                else:
                    self.a = self.f.add_axes(self.axesRect, **self.axprops)

            if axes is not None:
                raise RuntimeError, 'do not specify axes when have not passed a window'
        else:
            self.ownCanvas = False
            self.win = window
            self.canvas = self.win.getCanvas()
            self.f = self.win.getFigure()
            if axes is None:
                if self.__debug: print 'using axprops: '+str(self.axprops)
                self.a = self.win.getNextAxes(rect=self.axesRect, attachPW=self, **self.axprops)
            elif isinstance(axes, int):
                self.a = self.win.getAxes(axes, **self.axprops)
            else:
                self.a = axes
        #
        self.clear() # sets labels and so forth

        # self.style = style # can be None
        # self.bball = bball # can be None
        #
        #self.aging = aging
        #self.agingCull = agingCull
        #self.alphaMin = alphaMin
        self.agingNumAge = -1
        if self.aging is not None:
            from math import log
            self.agingNumAge = max(int(log(self.alphaMin)/log(self.aging)),1)
        self.plotProps = {}
        # self.lineListList = [] # not needed, can, and should, use a.lines

        self.asImIJ = False
        # self.transform = None
        self.axIm = None
        self.__colorbar = None

        return
    def add_axes(self, arect, kwAddAxes={}, **kwarg):
        aNew = self.f.add_axes(arect, **kwAddAxes)
        # self.a.set_position((0.05, 0.05, 0.45, 0.9))
        new = self.__class__(window=self.win, axes=aNew, **kwarg)
        return new
    @classmethod
    def popKeyArgs(cls, kwargs):
        retval = {}
        for key in cls.getKeyArgList():
            if kwargs.has_key(key):
                retval[key] = kwargs.pop(key)
        return retval
    @classmethod
    def getKeyArgList(cls):
        return cls.__keyArgDict.keys()
    def __checkCanvas(self):
        'leave dead True, not checking for window, just for canvas'
        #from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
        if self.win is not None: return
        if self.canvas is not None: return

        from matplotlib.backends.backend_tkagg import FigureCanvasAgg

        self.canvas = FigureCanvasAgg(self.f)
        if hasattr(self.a,'mouse_init'):
            self.a.mouse_init()
        return

    def __checkWin(self):
        if self.win is not None: return
        winTitle = self.winTitle
        if winTitle is None : winTitle = self.title
        if winTitle is None : winTitle = 'plotWin'
        if hasattr(self,'f'):
            self.win = PlotWin(1,1,title=winTitle, relfigsize=self.figsize, figure=self.f, axesList=[self.a])
        else:
            self.win = PlotWin(1,1,title=winTitle, relfigsize=self.figsize, axesList=[self.a])
        #self.win = PlotWinP(title=winTitle, figure=self.f, axes=self.a)
        self.canvas = self.win.getCanvas()
        return
    def removeLines(self):
        lines = self.a.get_lines()
        for line in lines:
            line.remove()
        if self.showByDefault:
            self.show() # self.canvas.show()
        return
    def show(self):
        self.__checkWin()
        if self.legend is not None:
            pass # do not yet have this right
            # if isinstance(self.legend, str) or isinstance(self.legend, int): #  or hasattr(self.legend,'__len__')
            #     self.a.legend(loc=self.legend)
            # elif isinstance(self.legend, bool):
            #     self.a.legend()
            # elif isinstance(self.legend, list):
            #     self.a.legend(*self.legend)
            # elif isinstance(self.legend, dict):
            #     self.a.legend(**self.legend)
            # else:
            #     raise RuntimeError, 'do not know what to do with legend specification: '+str(self.legend)
        if hasattr(self.a,'mouse_init'):
            self.a.mouse_init()
        if hasattr(self.f, 'show'):
            self.f.show()
        elif hasattr(self.canvas, 'show'):
            self.canvas.show()
        else:
            raise RuntimeError, 'do not know how to do show'
        return
    def clear(self):
        self.asImIJ = False
        self.axIm = None
        # self.transform = None
        self.x_prev = None
        self.__colorbar = None
        self.x_store = [[],[]]
        if self.showByDefault:
            self.__checkWin()
        if self.a is not None:
            if hasattr(self.a,'mouse_init'):
                'doing a.clear() seems like it causes trouble with plotting collections?'
                self.a.clear() # self.a.cla()
                self.a.set_autoscale_on(True)
            else:
                self.a.clear() # self.a.cla()
                self.a.set_autoscale_on(True)
        if self.xticks is not None:
            self.a.set_xticks(self.xticks)
        if self.title is not None:
            self.a.set_title(self.title)
        if self.xlabel is not None:
            self.a.set_xlabel(self.xlabel)  # r'X axis label $\mu\mbox{lentz}$'
            if self.win is not None:
                'make some room for the label'
                self.win.haveXLabels()
        if self.yticks is not None:
            self.a.set_yticks(self.yticks)
        if self.xlog: self.a.set_xscale('log')
        if self.ylog: self.a.set_yscale('log')
        #self.a.set_ybound(self.ybound)
        self.a.set_ylim(ymin=self.ybound[0], ymax=self.ybound[1])
        self.a.set_xlim(xmin=self.xbound[0], xmax=self.xbound[1])
        if self.ylabel is not None:
            self.a.set_ylabel(self.ylabel)
            if self.win is not None:
                'make some room for the label'
                self.win.haveYLabels()
        if self.legend is not None:
            pass # do not yet have this right
            # if isinstance(self.legend, str) or isinstance(self.legend, int): #  or hasattr(self.legend,'__len__')
            #     self.a.legend(loc=self.legend)
            # elif isinstance(self.legend, bool):
            #     self.a.legend()
            # elif isinstance(self.legend, list):
            #     self.a.legend(*self.legend)
            # elif isinstance(self.legend, dict):
            #     self.a.legend(**self.legend)
            # else:
            #     raise RuntimeError, 'do not know what to do with legend specification: '+str(self.legend)
        if self.a is not None:
            self.a.set_autoscale_on(True)
        if self.showByDefault:
            self.show() # self.canvas.show()
        return
    def setLegend(self, val=True):
        # if self.legend is None:
        #     self.legend = True
        # if val is not None:
        #     self.legend = val
        self.legend = val
        return
    def save(self, **keyArgs):
        '''make hardcopy of the current figure;
        specify filename or prefix keyword argument
        '''
        import numpy as num

        filename = None
        prefix = None
        if keyArgs.has_key('filename'):
            filename = keyArgs.pop('filename')
        if keyArgs.has_key('prefix'):
            prefix = keyArgs.pop('prefix')
            filename = prefix+'.pdf' # .eps

        if prefix is not None:
            'export data'
            if len(self.x_store[0]) > 0:
                dataFilename = prefix+'.data'
                from hexrd import arrayutil
                try:
                    arrayutil.writeArray(dataFilename, num.array(self.x_store))
                except:
                    import sys
                    print 'problem writing to '+dataFilename+' : '+str(self.x_store)
                    sys.exit(1)

        if not self.ownCanvas:
            if self.__debug:
                print 'skipping print_figure because this plot does not own its canvas'
        else:
            self.__checkCanvas()
            if filename is None:
                raise RuntimeError, 'need filename or prefix entry in keyArgs'
            #dpi = self.f.get_dpi()
            #self.canvas.print_figure(filename, dpi=dpi, **keyArgs)
            self.f.savefig(filename, **keyArgs)

        return
    def destroy(self):
        'does not clean up self.a, just kills the window if this plot owns the window'
        if self.ownCanvas and self.win is not None:
            self.win.destroy()
        return
    def drawBBox(self, bbox, **kwargs):
        import numpy as num
        bbox_x = bbox[0]
        bbox_y = bbox[1]
        xBBox = num.array([ bbox_x[0], bbox_x[1], bbox_x[1], bbox_x[0], bbox_x[0] ])
        yBBox = num.array([ bbox_y[0], bbox_y[0], bbox_y[1], bbox_y[1], bbox_y[0] ])
        'go through call, instead of callXY, in case of asImIJ'
        self.__call__(xBBox, yBBox, **kwargs)
        return
    def __call__(self, *args, **keyArgs):
        import numpy as num
        noShow = False
        retVal = None
        # if keyArgs.has_key('transform'):
        #     'pop transform so that can keep it for other (overlaid) plots'
        #     self.transform = keyArgs.pop('transform')
        if keyArgs.has_key('noShow'):
            noShow = keyArgs.pop('noShow')
        if len(args) == 2:
            alphas = None
            if self.asImIJ:
                x = args[1]
                y = args[0]
            else:
                x = args[0]
                y = args[1]
            if keyArgs.has_key('alphas'):
                alphas = keyArgs.pop('alphas')
                assert len(args) == 2, 'len(args) != 2'
                assert len(alphas) == len(y), 'len(alphas) != len(y)'
                self.x_prev = None
                for iX in range(len(x)):
                    self.callXY([x[iX]],[y[iX]],alpha=alphas[iX],**keyArgs)
            else:
                self.callXY(x, y, **keyArgs)
        elif len(args) == 3:
            X = args[0]; Y = args[1]; data = args[2];
            cont = self.callContour(X, Y, data, **keyArgs)
            retVal = cont
        elif len(args) == 1 and isinstance(args[0],str):
            'interpret string as name of a file to plot in axes'
            filename = args[0]
            im = self.callImage(filename, **keyArgs)
            retVal = im
        elif len(args) == 1 and isinstance(args[0],num.ndarray):
            im = self.callIm(args[0], **keyArgs)
            retVal = im
        else:
            raise RuntimeError, 'do not know what to do with args'
        self.a.set_ylim(ymin=self.ybound[0], ymax=self.ybound[1])
        self.a.set_xlim(xmin=self.xbound[0], xmax=self.xbound[1])
        if not noShow:
            if self.showByDefault:
                self.show()
        return retVal
    def callImage(self, filename,
                  **keyArgs):
        import Image
        im = Image.open(filename)
        s = im.tostring() # convert PIL image -> string
        import numpy as num
        rgb = num.fromstring(s, dtype=num.uint8).astype(num.float)/255.0 # convert string -> array of floats
        rgb = num.resize(rgb, (im.size[1], im.size[0], 3)) # resize to RGB array
        retval = self.callIm(rgb, **keyArgs)
        return retval
    def callIm(self, im,
               interpolation='nearest', aspect='equal',
               ijAsXY=False,
               clear=True, **keyArgs):
        if clear:
            self.clear()
        self.a.axis('off')
        # self.a.set_autoscale_on(True)
        if ijAsXY:
            self.asImIJ = False
            'imshow does not yet really support transform'
            if len(im.shape) == 3:
                imT = im.transpose(1,0,2)
            else:
                imT = im.T
            axIm = self.a.imshow(imT,
                                 interpolation=interpolation, aspect=aspect, origin='lower',
                                 # transform=self.transform,
                                 **keyArgs)
            self.a.format_coord = lambda x,y: 'i=%d; j=%d; val=%s' % \
                (round(x), round(y), str(im[round(x),round(y)]))
        else:
            self.asImIJ = True
            'imshow does not yet really support transform'
            axIm = self.a.imshow(im,
                                 interpolation=interpolation, aspect=aspect,
                                 # transform=self.transform,
                                 **keyArgs)
            self.a.format_coord = lambda x,y: 'i=%d; j=%d; val=%s' % \
                (round(y), round(x), str(im[round(y),round(x)]))
        'turn off autoscale so that axis limits do not get reset on replots'
        self.axIm = axIm
        self.mappable = axIm
        self.a.set_autoscale_on(False)
        return axIm
    def callContour(self, X, Y, data,
                    interpolation=None, aspect=None,
                    **keyArgs):
        pp = {}
        pp.update(self.plotProps)
        pp.update(keyArgs) # plotProps
        #cont = self.a.contourf(X, Y, data, 200, **keyArgs)
        'imshow does not yet really support transform'
        # self.a.set_autoscale_on(True)
        cont = self.a.imshow(data, origin='lower',
                             extent=(X[0,0],X[0,-1],Y[0,0],Y[-1,0]),
                             interpolation=interpolation,
                             aspect=aspect,
                             # transform=self.transform,
                             **keyArgs)
        self.a.set_autoscale_on(False)
        self.mappable = cont
        return cont
    def discontXY(self):
        self.x_prev = None
        return
    def callXY(self, x, y, style=None, **keyArgs):
        assert len(x) == len(y), \
               'x and y must be same length'

        xUse = x
        yUse = y
        if len(x) == 1:
            if self.x_prev is not None:
                xUse = []; xUse.append(self.x_prev[0]); xUse.append(x)
                yUse = []; yUse.append(self.x_prev[1]); yUse.append(y)

        pp = {}
        pp.update(self.plotProps)
        pp.update(keyArgs) # plotProps
        if self.bball is not None:
            'first, get rid of last bball'
            lenCur = len(self.a.lines)
            if lenCur>0:
                self.a.lines = self.a.lines[0:lenCur-1]
        if self.aging is not None:
            #for lineList in self.lineListList[:-1]:
            #    for line in lineList:
            lenCur = len(self.a.lines)
            for line in self.a.lines[max(0,lenCur-self.agingNumAge):lenCur]:
                alphaCur = line.get_alpha()
                line.set_alpha(alphaCur*self.aging)
            if self.agingCull:
                if lenCur > self.agingNumAge:
                    self.a.lines = self.a.lines[lenCur-self.agingNumAge:lenCur]
        if style is not None:
            'passing transform of None can cause trouble'
            lines = self.a.plot(xUse, yUse, style,
                                # transform=self.transform,
                                **pp)
        elif self.style is not None:
            #self.lineListList.append(self.a.plot(x,y,self.style,**pp))
            lines = self.a.plot(xUse, yUse, self.style,
                                # transform=self.transform,
                                **pp)
        else:
            #self.lineListList.append(self.a.plot(x,y,**pp))
            lines = self.a.plot(xUse, yUse,
                                # transform=self.transform,
                                **pp)
        if self.bball is not None:
            'add bball at end'
            self.a.plot([x[-1]],[y[-1]], self.bball)
            # transform=self.transform
        if len(x) == 1:
            if self.x_accum:
                self.x_prev = [x, y]
            self.x_store[0] = self.x_store[0] + list(x)
            self.x_store[1] = self.x_store[1] + list(y)
        else:
            self.x_prev = None
            if len(x) == len(self.x_store[0]):
                'assume called with the same x values'
                self.x_store.append(list(y))
            else:
                self.x_store[0] = list(x)
                self.x_store[1] = list(y)
        return
    def setVMM(self, vMM):
        if type(vMM) == int:
            iCol = vMM
            vMM = self.a.collections[iCol].get_clim()
        for col in self.a.collections:
            col.set_clim(vmin=vMM[0],vmax=vMM[1])
        return
    def colorbar(self, rect=(0.80,0.1,0.05,0.8), adjustPos=True, thing=None, **kwargs):
        '''
        if set rect to None, then colorbar steals self.a
        '''
        self.__checkWin()
        w = self.win
        f = self.f
        if len(self.a.collections) > 0:
            self.setVMM(0)
        if thing is None:
            if len(self.a.collections) > 0:
                thing = self.a.collections[0]
            elif hasattr(self, 'mappable'):
                thing = self.mappable
            else:
                raise RuntimeError, 'do not know what to colobar, pass in a thing'
        if rect is None:
            self.__colorbar = f.colorbar(thing, cax=self.a, **kwargs)
        else:
            cax = w.getNextAxes(rect=rect)
            self.__colorbar = f.colorbar(thing, cax=cax, **kwargs)
            if adjustPos:
                'adjust existing position to make room for colorbar'
                bbox = self.a.get_position().get_points()
                arect = (bbox[0,0], # left
                         bbox[0,1], # bottom
                         rect[0]-bbox[0,0]-0.02, # width
                         bbox[1,1]-bbox[0,1], # height
                         )
                self.a.set_position(arect)
        self.show()
        return
Пример #4
0
class PlotWindow(plt.Figure):
    """ Tk window containing a matplotlib plot. In addition to the functions described below, also supports all
    functions contained in matplotlib's Axes_ and Figure_ objects.

    .. _Axes: http://matplotlib.sourceforge.net/api/axes_api.html
    .. _Figure: http://matplotlib.sourceforge.net/api/figure_api.html

    Args:
        title (str): The title to be used for the initial window.
        visible (bool): Whether to actually display a Tk window (set to `False` to create and save plots without
            displaying a window).
        standalone (bool, optional): If `True`, plot windows will be kept open by keeping the Tk event loop alive.
    """
    _tk_started = False  # If this is True, uses Toplevel to create the window, otherwise creates a main window

    def __init__(self, title="Plotting Window", visible=True):
        plt.Figure.__init__(self)
        self.add_subplot(111)
        self.visible = visible
        self._destroyed = False
        if self.visible:  # If visible, use Tk's frontend
            # Use the correct method to create a window, then set the tk_started flag to True
            self.canvas = FigureCanvasTkAgg(
                self,
                Toplevel() if self.__class__._tk_started else Tk())
            self.__class__._tk_started = True
            self.title(title)
            self.make_window()
            self.show()
        else:
            self.canvas = FigureCanvasAgg(self)

    def make_window(self):
        """ Pack the plot and matplotlib toolbar into the containing Tk window.

        This method is called during initialization and it is unlikely you will need to call it elsewhere.
        """
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        self.toolbar = NavigationToolbar2Tk(self.canvas, self.canvas._master)
        self.toolbar.update()
        self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)

    def destroy(self):
        """ Destroy the Tk window.

        Note that after calling this method (or manually closing the Tk window), this :py:class:`PlotWindow` cannot be
        used.
        """
        try:  # Try and destroy the window
            self.canvas._master.destroy()
        except:
            pass  # It was probably already destroyed
        self._destroyed = True

    def clear(self):
        """ Clear the plot, keeping the Tk window active. """
        self.clf()
        self.add_subplot(111)
        if self.visible:
            self.show()

    def show(self):
        """ Update the canvas image (automatically called for most functions). """
        try:
            self.canvas.draw()
        except Exception:
            self.canvas.show()

    def __getattr__(self, name):
        show = True
        if name.startswith('_'):
            name = name[1:]
            show = False
        if hasattr(self.axes[0], name):
            attr = getattr(self.axes[0], name)
            if hasattr(attr, '__call__'):
                if show:

                    def tmp(*args, **kwargs):
                        out = attr(*args, **kwargs)
                        if self.visible:
                            self.show()
                        return out

                    return tmp
                else:
                    return attr
            else:
                return attr
        else:
            raise AttributeError("PlotWindow object has no attribute %s" %
                                 name)

    def title(self, title):
        """ Change the title of the Tk window """
        self.canvas._master.title(title)

    def legend(self, *args):
        """ Create a legend for the figure (requires plots to have been made with labels) """
        handles, labels = self.axes[0].get_legend_handles_labels()
        self.axes[0].legend(handles, labels)
        if self.visible:
            self.show()

    def save(self, fname, **kwargs):
        """ Save this plot as an image.  File type determined by extension of filename passed in.

        See documentation for savefig_.

        .. _savefig: http://matplotlib.sourceforge.net/api/figure_api.html

        Args:
            fname: The file to create, which may be a path or a file-like object.
        """
        self.savefig(fname, **kwargs)

    def stay(self):
        """ Start the Tkinter window's main loop (e.g., to keep the plot open at the end of the execution of a script)
        """
        self.canvas._master.mainloop()

    def plot(self, *args, **kwargs):
        """ Plot lines and/or markers to the Axes. See pyplot_ for more information.

        .. _pyplot: https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.plot
        """
        self.__getattr__('plot')(*args, **kwargs)