Reportlab生成PDF文件

这个图表看着挺高档,其实就是两个带图例的饼形图加上几条直线而已:

"Pie within a pie"
from reportlab.graphics.charts.legends import Legend
from reportlab.graphics.charts.piecharts import Pie
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, Line
from reportlab.lib.colors import PCMYKColor, CMYKColor

class PieChart_WithinPie(_DrawingEditorMixin,Drawing):
    '''
        派里有派
        --------------

        这个图表由两个派和一些直线组成

    '''
    def __init__(self,width=155,height=262,*args,**kw):
        Drawing.__init__(self,width,height,*args,**kw)
        fontName = 'Helvetica'
        fontSize = 7
        # 大饼的颜色列表
        colorsList1= [PCMYKColor(100,60,0,50), PCMYKColor(66,13,0,22), PCMYKColor(0,100,100,40), PCMYKColor(100,0,90,50), PCMYKColor(10,0,49,28), PCMYKColor(47,64,28,0), PCMYKColor(10,10,73,0), PCMYKColor(22,3,0,0), PCMYKColor(22,0,100,8)]
        # 小饼的颜色列表
        colorsList2= [CMYKColor(0,0,0,.64,density=.8,alpha=1), CMYKColor(0,0,0,.48, density=.6,alpha=1), CMYKColor(0,0,0,.32, density=.4,alpha=1), CMYKColor(0,0,0,.2, density=.25,alpha=1), CMYKColor(0,0,0,.8,spotName='XXX X',alpha=1)]
        # density:墨水的浓度

        # 添加两个派两个图例
        self._add(self,Pie(),name='pie1',validate=None,desc=None)
        self._add(self,Legend(),name='legend1',validate=None,desc=None)
        self._add(self,Pie(),name='pie2',validate=None,desc=None)
        self._add(self,Legend(),name='legend2',validate=None,desc=None)

        # 大饼
        self.pie1.data              = [65.7, 4.5, 21.1999, 8.6001]
        self.pie1.width             = 77
        self.pie1.height            = 77
        self.pie1.sameRadii=1
        self.pie1.slices.strokeColor              = PCMYKColor(0,0,0,0)
        self.pie1.slices.strokeWidth              = 0.5
        # 填充大饼的颜色
        for i, color in enumerate(colorsList1):
            self.pie1.slices[i].fillColor = color


        # 小饼
        self.pie2.data              = [86.0, 14.0]
        self.pie2.width             = 46
        self.pie2.height            = 46
        self.pie2.sameRadii         = 1
        # 这个参数的作用只有在饼形图的宽高设值不同时才能显现
        self.pie2.slices.strokeColor              = PCMYKColor(0,0,0,0)
        self.pie2.slices.strokeWidth              = 0.5
        for i, color in enumerate(colorsList2):
            self.pie2.slices[i].fillColor = color

        # 规定图例上的数据显示格式,小数点显示一位,后附百分号
        from reportlab.lib.formatters import DecimalFormatter
        formatter = DecimalFormatter(places=1, suffix='%')

        # 图例1(参考图例属性简解的帖子)
        self.legend1.alignment        ='right'
        self.legend1.fontName         = fontName
        self.legend1.fontSize         = fontSize
        self.legend1.dx               = 7
        self.legend1.dy               = 7
        self.legend1.yGap             = 0
        self.legend1.deltax           = 10
        self.legend1.deltay           = 20
        self.legend1.strokeWidth      = 0
        self.legend1.strokeColor       = PCMYKColor(0,0,0,0)
        self.legend1.columnMaximum    = 10

        # 将数据转换成百分号格式,而后放进列表
        percentDatas = list(map(formatter, self.pie1.data))
        entries = ['Government\nFunds: ', 'Contributions: ', 'Investments: ', 'other: ']
        # 连接entries和对应的数据
        items = [entry+percentData for entry, percentData in zip(entries, percentDatas)]
        # items = list(zip(entries, percentDatas))
        self.legend1.colorNamePairs = list(zip(colorsList1, items))
        # 对应色块颜色和条目

        # 图例2
        self.legend2.alignment        = 'right'
        self.legend2.fontName         = fontName
        self.legend2.fontSize         = fontSize
        self.legend2.dx               = 7
        self.legend2.dy               = 7
        self.legend2.yGap             = 0
        self.legend2.deltax           = 10
        self.legend2.deltay           = 20
        self.legend2.strokeWidth      = 0
        self.legend2.strokeColor       = PCMYKColor(0,0,0,0)
        self.legend2.columnMaximum    = 10      # 最多可以有多少行,默认是3行

        percentDatas = map(formatter, self.pie2.data)
        entries = ['Grants: ', 'Loans: ']
        items = list(zip(entries, percentDatas))
        self.legend2.colorNamePairs   = list(zip(colorsList2, items))

        # 组成括号的直线,括号的位置后面有调整
        self._add(self,Line(85,230,85,184),name='vline',validate=None,desc=None)
        self.vline.strokeColor        = PCMYKColor(0,0,0,75)      # 竖线
        self._add(self,Line(85,230,93,230),name='topline',validate=None,desc=None)
        self.topline.strokeColor      = PCMYKColor(0,0,0,75)    # 上横线
        self._add(self,Line(77,207,85,207),name='midline',validate=None,desc=None)
        self.midline.strokeColor      = PCMYKColor(0,0,0,75)    # 中横线
        self._add(self,Line(85,184,93,184),name='butline',validate=None,desc=None)
        self.butline.strokeColor      = PCMYKColor(0,0,0,75)    # 下横线

        self.width       = 400
        self.height      = 200

        # 调整图例各部分的位置
        self.pie1.y                 = 112
        self.pie1.x                 = 110
        self.legend1.boxAnchor      = 'nw'
        self.legend1.y              = 100
        self.legend1.x              = 110

        self.pie2.x                 = 230
        self.pie2.y                 = 112
        self.legend2.y              = 100
        self.legend2.x              = 240


        # 调整四条直线的位置
        self.topline.x1               = 197
        self.topline.x2               = 205
        self.topline.y1               = 112
        self.topline.y2               = 112
        self.butline.y2               = 160
        self.butline.y1               = 160
        self.butline.x1               = 197
        self.butline.x2               = 205
        self.vline.x1                 = 197
        self.vline.x2                 = 197
        self.vline.y2                 = 112
        self.vline.y1                 = 160
        self.midline.y1               = 137
        self.midline.y2               = 137
        self.midline.x1               = 189
        self.midline.x2               = 197

if __name__=="__main__": #NORUNTESTS
    PieChart_WithinPie().save(formats=['pdf'],outDir='.',fnRoot=None)
    # formats=指定保存的文件格式,outDir=指定保存的路径
    # fnRoot=保存的文件名,为None时用定义的类名加上三位数字,从000开始