⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wxpyplot.py

📁 PyChem是用Python语言编写的多元变量分析软件。它包括一个前端图形界面用于管理和保存试验数据
💻 PY
📖 第 1 页 / 共 4 页
字号:
        titleWH, xLabelWH, yLabelWH= self._titleLablesWH(dc, graphics)

        #TextExtents for Legend
        legendBoxWH, legendSymExt, legendTextExt = self._legendWH(dc, graphics)

        #room around graph area
        rhsW= max(xTextExtent[0], legendBoxWH[0]) #use larger of number width or legend width
        lhsW= yTextExtent[0]+ yLabelWH[1]
        bottomH= max(xTextExtent[1], yTextExtent[1]/2.)+ xLabelWH[1]
        topH= yTextExtent[1]/2. + titleWH[1]
        textSize_scale= scipy.array([rhsW+lhsW,bottomH+topH]) #make plot area smaller by text size
        textSize_shift= scipy.array([lhsW, bottomH])          #shift plot area by this amount

        #drawing title and labels text
        dc.SetFont(self._getFont(self._fontSizeTitle))
        titlePos= (self.plotbox_origin[0]+ lhsW + (self.plotbox_size[0]-lhsW-rhsW)/2.- titleWH[0]/2.,
                 self.plotbox_origin[1]- self.plotbox_size[1])
        dc.DrawText(graphics.getTitle(),titlePos[0],titlePos[1])
        dc.SetFont(self._getFont(self._fontSizeAxis))
        xLabelPos= (self.plotbox_origin[0]+ lhsW + (self.plotbox_size[0]-lhsW-rhsW)/2.- xLabelWH[0]/2.,
                 self.plotbox_origin[1]- xLabelWH[1])
        dc.DrawText(graphics.getXLabel(),xLabelPos[0],xLabelPos[1])
        yLabelPos= (self.plotbox_origin[0],
                 self.plotbox_origin[1]- bottomH- (self.plotbox_size[1]-bottomH-topH)/2.+ yLabelWH[0]/2.)
        if graphics.getYLabel():  #bug fix for Linux

            dc.DrawRotatedText(graphics.getYLabel(),yLabelPos[0],yLabelPos[1],90)

        #drawing legend makers and text
        if self._legendEnabled:
            if len(graphics) > self._legendItems:
                self._drawLegend(dc,graphics,rhsW,topH,legendBoxWH, legendSymExt, legendTextExt, self._legendItems)
            else:
                self._drawLegend(dc,graphics,rhsW,topH,legendBoxWH, legendSymExt, legendTextExt)

        #allow for scaling and shifting plotted points
        scale = (self.plotbox_size-textSize_scale) / (p2-p1)* scipy.array((1,-1))
        shift = -p1*scale + self.plotbox_origin + textSize_shift * scipy.array((1,-1))
        self._pointScale= scale  #make available for mouse events
        self._pointShift= shift        
        self._drawAxes(dc, p1, p2, scale, shift, xticks, yticks)
        
        graphics.scaleAndShift(scale, shift)
        graphics.setPrinterScale(self.printerScale)  #thicken up lines and markers if printing
        
        #set clipping area so drawing does not occur outside axis box
        ptx,pty,rectWidth,rectHeight= self._point2ClientCoord(p1, p2)
        dc.SetClippingRegion(ptx,pty,rectWidth,rectHeight)
        #Draw the lines and markers
        #start = time.clock()
        graphics.draw(dc)
        #print "entire graphics drawing took: %f second"%(time.clock() - start)
        #remove the clipping region
        dc.DestroyClippingRegion()
        dc.EndDrawing()
        
    def Redraw(self, dc= None):
        """Redraw the existing plot."""
        if self.last_draw is not None:
            graphics, xAxis, yAxis= self.last_draw
            self.Draw(graphics,xAxis,yAxis,dc)

    def Clear(self):
        """Erase the window."""
        dc = wx.wxBufferedDC(wx.wxClientDC(self), self._Buffer)
        dc.Clear()
        self.last_draw = None

    def Zoom(self, Center, Ratio):
        """ Zoom on the plot
            Centers on the X,Y coords given in Center
            Zooms by the Ratio = (Xratio, Yratio) given
        """
        x,y = Center
        if self.last_draw != None:
            (graphics, xAxis, yAxis) = self.last_draw
            w = (xAxis[1] - xAxis[0]) * Ratio[0]
            h = (yAxis[1] - yAxis[0]) * Ratio[1]
            xAxis = ( x - w/2, x + w/2 )
            yAxis = ( y - h/2, y + h/2 )
            self.Draw(graphics, xAxis, yAxis)
        

    # event handlers **********************************
    def OnMotion(self, event):
        if self._zoomEnabled and event.LeftIsDown():
            if self._hasDragged:
                self._drawRubberBand(self._zoomCorner1, self._zoomCorner2) #remove old
            else:
                self._hasDragged= True
            self._zoomCorner2[0], self._zoomCorner2[1] = self.GetXY(event)
            self._drawRubberBand(self._zoomCorner1, self._zoomCorner2) #add new

    def OnMouseLeftDown(self,event):
        self._zoomCorner1[0], self._zoomCorner1[1]= self.GetXY(event)

    def OnMouseLeftUp(self, event):
        if self._zoomEnabled:
            if self._hasDragged == True:
                self._drawRubberBand(self._zoomCorner1, self._zoomCorner2) #remove old
                self._zoomCorner2[0], self._zoomCorner2[1]= self.GetXY(event)
                self._hasDragged = False  #reset flag
                minX, minY= scipy.minimum( self._zoomCorner1, self._zoomCorner2)
                maxX, maxY= scipy.maximum( self._zoomCorner1, self._zoomCorner2)
                if self.last_draw != None:
                    self.Draw(self.last_draw[0], xAxis = (minX,maxX), yAxis = (minY,maxY), dc = None)
            #else: # A box has not been drawn, zoom in on a point
            ## this interfered with the double click, so I've disables it.
            #    X,Y = self.GetXY(event)
            #    self.Zoom( (X,Y), (self._zoomInFactor,self._zoomInFactor) )

    def OnMouseDoubleClick(self,event):
        if self._zoomEnabled:
            self.Reset()
        
    def OnMouseRightDown(self,event):
        if self._zoomEnabled:
            X,Y = self.GetXY(event)
            self.Zoom( (X,Y), (self._zoomOutFactor, self._zoomOutFactor) )

    def OnPaint(self, event):
        # All that is needed here is to draw the buffer to screen
        dc = wx.wxBufferedPaintDC(self, self._Buffer)        

    def OnSize(self,event):
        # The Buffer init is done here, to make sure the buffer is always
        # the same size as the Window
        Size  = self.GetClientSizeTuple()

        # Make new offscreen bitmap: this bitmap will always have the
        # current drawing in it, so it can be used to save the image to
        # a file, or whatever.
        self._Buffer = wx.wxEmptyBitmap(Size[0],Size[1])
        self._setSize()
        if self.last_draw is None:
            self.Clear()
        else:
            graphics, xSpec, ySpec = self.last_draw
            self.Draw(graphics,xSpec,ySpec)

        
    #Private Methods **************************************************
    def _setSize(self, width=None, height=None):
        """DC width and height."""
        if width == None:
            (self.width,self.height) = self.GetClientSizeTuple()
        else:
            self.width, self.height= width,height    
        self.plotbox_size = 0.97*scipy.array([self.width, self.height])
        xo = 0.5*(self.width-self.plotbox_size[0])
        yo = self.height-0.5*(self.height-self.plotbox_size[1])
        self.plotbox_origin = scipy.array([xo, yo])
    
    def _setPrinterScale(self, scale):
        """Used to thicken lines and increase marker size for print out."""
        #line thickness on printer is very thin at 600 dot/in. Markers small
        self.printerScale= scale
     
    def _printDraw(self, printDC):
        """Used for printing."""
        if self.last_draw != None:
            graphics, xSpec, ySpec= self.last_draw
            self.Draw(graphics,xSpec,ySpec,printDC)

    def _drawLegend(self,dc,graphics,rhsW,topH,legendBoxWH, legendSymExt, legendTextExt, items=None):
        """Draws legend symbols and text"""
        #top right hand corner of graph box is ref corner
        trhc= self.plotbox_origin+ (self.plotbox_size-[rhsW,topH])*[1,-1]
        legendLHS= .091* legendBoxWH[0]  #border space between legend sym and graph box
        lineHeight= max(legendSymExt[1], legendTextExt[1]) * 1.1 #1.1 used as space between lines
        dc.SetFont(self._getFont(self._fontSizeLegend))
        if items is None:
            length = len(graphics)
        else:
            length = items
            
        for i in range(length):
            o = graphics[i]
            s= i*lineHeight
            if isinstance(o,PolyMarker):
                #draw marker with legend
                pnt= (trhc[0]+legendLHS+legendSymExt[0]/2., trhc[1]+s+lineHeight/2.)
                o.draw(dc, self.printerScale, coord= scipy.array([pnt]))
            elif isinstance(o,PolyLine):
                #draw line with legend
                pnt1= (trhc[0]+legendLHS, trhc[1]+s+lineHeight/2.)
                pnt2= (trhc[0]+legendLHS+legendSymExt[0], trhc[1]+s+lineHeight/2.)
                o.draw(dc, self.printerScale, coord= scipy.array([pnt1,pnt2]))
            else:
                raise TypeError, "object is neither PolyMarker or PolyLine instance"
            #draw legend txt
            pnt= (trhc[0]+legendLHS+legendSymExt[0], trhc[1]+s+lineHeight/2.-legendTextExt[1]/2)
            dc.DrawText(o.getLegend(),pnt[0],pnt[1])
        dc.SetFont(self._getFont(self._fontSizeAxis)) #reset

    def _titleLablesWH(self, dc, graphics):
        """Draws Title and labels and returns width and height for each"""
        #TextExtents for Title and Axis Labels
        dc.SetFont(self._getFont(self._fontSizeTitle))
        title= graphics.getTitle()
        titleWH= dc.GetTextExtent(title)
        dc.SetFont(self._getFont(self._fontSizeAxis))
        xLabel, yLabel= graphics.getXLabel(),graphics.getYLabel()
        xLabelWH= dc.GetTextExtent(xLabel)
        yLabelWH= dc.GetTextExtent(yLabel)
        return titleWH, xLabelWH, yLabelWH
    
    def _legendWH(self, dc, graphics):
        """Returns the size in screen units for legend box"""
        if self._legendEnabled != True:
            legendBoxWH= symExt= txtExt= (0,0)
        else:
            #find max symbol size
            symExt= graphics.getSymExtent(self.printerScale)
            #find max legend text extent
            dc.SetFont(self._getFont(self._fontSizeLegend))
            txtList= graphics.getLegendNames()
            txtExt= dc.GetTextExtent(txtList[0])
            for txt in graphics.getLegendNames()[1:]:
                txtExt= scipy.maximum(txtExt,dc.GetTextExtent(txt))
            maxW= symExt[0]+txtExt[0]    
            maxH= max(symExt[1],txtExt[1])
            #padding .1 for lhs of legend box and space between lines
            maxW= maxW* 1.1
            maxH= maxH* 1.1 * len(txtList)
            dc.SetFont(self._getFont(self._fontSizeAxis))
            legendBoxWH= (maxW,maxH)
        return (legendBoxWH, symExt, txtExt)

    def _drawRubberBand(self, corner1, corner2):
        """Draws/erases rect box from corner1 to corner2"""
        ptx,pty,rectWidth,rectHeight= self._point2ClientCoord(corner1, corner2)
        #draw rectangle
        dc = wx.wxClientDC( self )
        dc.BeginDrawing()                 
        dc.SetPen(wx.wxPen(wx.wxBLACK))
        dc.SetBrush(wx.wxBrush( wx.wxWHITE, wx.wxTRANSPARENT ) )
        dc.SetLogicalFunction(wx.wxINVERT)
        dc.DrawRectangle( ptx,pty,rectWidth,rectHeight)
        dc.SetLogicalFunction(wx.wxCOPY)
        dc.EndDrawing()

    def _getFont(self,size):
        """Take font size, adjusts if printing and returns wxFont"""
        s = size*self.printerScale
        of = self.GetFont()
        #Linux speed up to get font from cache rather than X font server
        key = (int(s), of.GetFamily (), of.GetStyle (), of.GetWeight ())
        font = self._fontCache.get (key, None)
        if font:
            return font                 # yeah! cache hit
        else:
            font =  wx.wxFont(int(s), of.GetFamily(), of.GetStyle(), of.GetWeight())
            self._fontCache[key] = font
            return font


    def _point2ClientCoord(self, corner1, corner2):
        """Converts user point coords to client screen int coords x,y,width,height"""
        c1= scipy.array(corner1)
        c2= scipy.array(corner2)
        #convert to screen coords
        pt1= c1*self._pointScale+self._pointShift
        pt2= c2*self._pointScale+self._pointShift
        #make height and width positive
        pul= scipy.minimum(pt1,pt2) #Upper left corner
        plr= scipy.maximum(pt1,pt2) #Lower right corner
        rectWidth, rectHeight= plr-pul
        ptx,pty= pul
        return int(ptx),int(pty),int(rectWidth),int(rectHeight) #return ints
    
    def _axisInterval(self, spec, lower, upper):
        """Returns sensible axis range for given spec"""
        if spec == 'none' or spec == 'min':
            if lower == upper:
                return lower-0.5, upper+0.5
            else:
                return lower, upper
        elif spec == 'auto':
            range = upper-lower
            if range == 0.:
                return lower-0.5, upper+0.5
            log = scipy.log10(range)
            power = scipy.floor(log)
            fraction = log-power
            if fraction <= 0.05:
                power = power-1
            grid = 10.**power
            lower = lower - lower % grid
            mod = upper % grid
            if mod != 0:
                upper = upper - mod + grid
            return lower, upper
        elif type(spec) == type(()):
            lower, upper = spec
            if lower <= upper:
                return lower, upper
            else:
                return upper, lower
        else:
            raise ValueError, str(spec) + ': illegal axis specification'

    def _drawAxes(self, dc, p1, p2, scale, shift, xticks, yticks):
        
        penWidth= self.printerScale        #increases thickness for printing only
        dc.SetPen(wx.wxPen(wx.wxNamedColour('BLACK'),int(penWidth)))
        
        #set length of tick marks--long ones make grid
        if self._gridEnabled:
            x,y,width,height= self._point2ClientCoord(p1,p2)
            yTickLength= width/2.0 +1
            xTickLength= height/2.0 +1
        else:
            yTickLength= 3 * self.printerScale  #lengthens lines for printing
            xTickLength= 3 * self.printerScale
        
        if self._xSpec is not 'none':
            lower, upper = p1[0],p2[0]
            text = 1
            for y, d in [(p1[1], -xTickLength), (p2[1], xTickLength)]:   #miny, maxy and tick lengths
                a1 = scale*scipy.array([lower, y])+shift
                a2 = scale*scipy.array([upper, y])+shift
                dc.DrawLine(a1[0],a1[1],a2[0],a2[1])  #draws upper and lower axis line
                for x, label in xticks:
                    pt = scale*scipy.array([x, y])+shift
                    dc.DrawLine(pt[0],pt[1],pt[0],pt[1] + d) #draws tick mark d units
                    if text:
                        dc.DrawText(label,pt[0],pt[1])
                text = 0  #axis values not drawn on top side

        if self._ySpec is not 'none':
            lower, upper = p1[1],p2[1]
            text = 1
            h = dc.GetCharHeight()
            for x, d in [(p1[0], -yTickLength), (p2[0], yTickLength)]:
                a1 = scale*scipy.array([x, lower])+shift
                a2 = scale*scipy.array([x, upper])+shift
                dc.DrawLine(a1[0],a1[1],a2[0],a2[1])
                for y, label in yticks:
                    pt = scale*scipy.array([x, y])+shift
                    dc.DrawLine(pt[0],pt[1],pt[0]-d,pt[1])
                    if text:
                        dc.DrawText(label,pt[0]-dc.GetTextExtent(label)[0],
                                    pt[1]-0.5*h)
                text = 0    #axis values not drawn on right side

    def _ticks(self, lower, upper):
        ideal = (upper-lower)/7.
        log = scipy.log10(ideal)
        power = scipy.floor(log)
        fraction = log-power
        factor = 1.
        error = fraction
        for f, lf in self._multiples:
            e = scipy.fabs(fraction-lf)
            if e < error:
                error = e
                factor = f
        grid = factor * 10.**power
        if power > 4 or power < -4:
            format = '%+7.1e'        
        elif power >= 0:
            digits = max(1, int(power))
            format = '%' + `digits`+'.0f'
        else:
            digits = -int(power)
            format = '%'+`digits+2`+'.'+`digits`+'f'
        ticks = []
        t = -grid*scipy.floor(-lower/grid)
        while t <= upper:
            ticks.append( (t, format % (t,)) )
            t = t + grid

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -