Reportlab生成PDF文件

这个是reportlab给的示例程序(略加改动),我们添加中文注释稍作解释,便于从自己的需要出发在示例程序的基础上做个性化调整。图表用的是饼形图,添加的多列的图例见下图:

可以看到图例上的数据说明分成了几列,可以指定饼形图表现哪一列的数据。这个多列图例在程序中生成了两个Legend类的对象legend和legendHeader,legend表现图例上的数据,legendHeader表现表头。通过对象legend和legendHeader的subCol[X]的属性设置规定每一列的对齐方式和宽度。

程序和注解如下:

# 图例上包含多列数据

from reportlab.graphics.charts.piecharts import Pie     # 饼形图
from reportlab.lib.colors import PCMYKColor             
# CMYK颜色模式:Cyan、Magenta、Yellow、Black
from reportlab.graphics.charts.legends import Legend    # 图例
from reportlab.graphics.shapes import Drawing
from reportlab.lib.formatters import DecimalFormatter

# 准备好画布
width = 420
height = 200
d = Drawing(width,height)

# 定义用到的颜色参数
chart_colors = [PCMYKColor(100,55,0,55), PCMYKColor(55,24,0,9), PCMYKColor(0,70,60,5), 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), PCMYKColor(0,64,100,0), PCMYKColor(0,100,99,4), PCMYKColor(0,30,72,11), PCMYKColor(50,0,25,30), PCMYKColor(64,100,0,14), PCMYKColor(75,0,7,0), PCMYKColor(23,2,0,77), PCMYKColor(30,56,100,37), PCMYKColor(0,4,22,32), PCMYKColor(0,30,100,0),]
# 字体和字体大小
fontSize = 7
fontName = 'Times-Roman'

# 添加饼形图,饼形图的名字叫做chart
chart = Pie()

# 设置饼形图chart的参数
chart.width            = 120
chart.height           = 120
chart.sameRadii         = 1    
# radii是radius的复数,当chart.width与chart.height不相等时,饼形图会变形
# 除非sameRadii设置为1,默认是0

# 位置坐标
chart.y                = 40
chart.x                = 12
# 饼形图的线条颜色和宽度,线条颜色白色
chart.slices.strokeColor  = PCMYKColor(0,0,0,0)
chart.slices.strokeWidth  = 0.5

# 添加两个图例对象,一个处理数据(legend)一个处理表头(legendHeader)
legend = Legend()
legendHeader = Legend()
# 图例表头位置坐标
legendHeader.x         = 160
legendHeader.y         = d.height-15
# 表头字体和字体大小
legendHeader.fontSize  = fontSize
legendHeader.fontName  = 'Times-Bold'
# 每一列的宽度和对齐方式,表头各列都是字符串,左对齐
legendHeader.subCols[0].minWidth = 100      # 列宽
legendHeader.subCols[0].align = 'left'
legendHeader.subCols[1].minWidth = 60
legendHeader.subCols[1].align = 'left'
legendHeader.subCols[2].minWidth = 50
legendHeader.subCols[2].align = 'left'
legendHeader.subCols[3].minWidth = 50
legendHeader.subCols[3].align = 'left'
black = PCMYKColor(0,0,0,100)   # 黑色,不透明
# 表头全部用黑色
legendHeader.colorNamePairs = [(black, ('Company','Previous Year','This Year','Change'))]

legend.x                = 160
legend.y                = d.height-30
legend.fontSize         = fontSize
legend.fontName         = fontName
legend.dx               = 6    # 图例上颜色块的宽度
legend.dy               = 6    # 图例上颜色块的高度
legend.dxTextSpace      = 5    # 图示文字和色标的间距
legend.yGap             = 0    # 调整图例上的行间距
legend.deltay           = 12   # 调整图例上的行间距
legend.strokeColor      = PCMYKColor(0,0,0,0)
# 图例上色块的边线,白色
legend.strokeWidth      = 0    # 色块的边线宽度
legend.columnMaximum    = 99   # 最多可以有这么多行
legend.alignment        = 'right'  # 图示说明文字在颜色图示的右边
legend.variColumn       = 0
legend.dividerDashArray = None
# 分割线的样式,可以是点线,用列表定义,如[2, 4];None就是直线
legend.dividerWidth     = 0.5
# 分割线的宽度
legend.dividerOffsX     = (0, 5)
# 定义分割线左右线头伸出的长度,左边没伸右边伸出5
legend.dividerLines     = 7
# 定义间隔线怎样间隔,7跟1|2|4效果同,感觉1|2|4是二进制表达:
# 2的0次方1次方2次方的位置都为1,二进制的111为7出(0),,
# 可参见"Reportlab生成带图例的图表到PDF文件中"
legend.dividerOffsY     = 6
# 间隔线Y轴上的位移
legend.subCols[0].align = 'left'        # 其实字符串默认靠左
legend.subCols[0].minWidth = 90         # 列宽
legend.subCols[1].align='numeric'
# 这一列放数值,跟excel一样数值靠右对齐
legend.subCols[1].dx = -45              # 往左移了45
legend.subCols[1].minWidth = 60
legend.subCols[2].align='numeric'
legend.subCols[2].dx = -40
legend.subCols[2].minWidth = 50
legend.subCols[3].align='numeric'
legend.subCols[3].dx = -15

# 图表上图例的数据序列,四列数据
seriesNames = ('BP', 'Shell Transport & Trading', 'Liberty International', \
                    'Persimmon', 'Royal Bank of Scotland', 'Land Securities', \
                    'BT', 'Standard Chartered', 'Bovis Homes', 'HSBC Holdings', \
                    'Natwest', 'Barclays', 'Sainsburys')
seriesData1 = (27.40, 3.6, 10.33, 7.38, 8.21, 9.30, 3.65, 10.37, 2.4, 2.5, 2.4, 2.55, 1.6)
seriesData2 = (37.89, 4.74, 12.73, 8.71, 6.94, 7.87, 3.4, 11.45, 1.79, 1.8, 1.81, 1.82, 0.5)
seriesData3 = [x-y for (x,y) in zip(seriesData1, seriesData2)]
# zip(序列1, 序列2)将两个序列seriesData1, seriesData2象拉链拉起来一样同步取数据
# for (x,y) in zip()每次同步取出一对数据放进(x,y)
# [x-y for ……]用取出的各对数值的差值组成一个序列

formatter = DecimalFormatter(places=2,thousandSep=',',decimalSep='.',suffix='%')
# 规定显示的格式:两位,千的位置用 ',',小数点用'.',加一个后缀'%'
names = list(zip(seriesNames,
map(formatter, seriesData1),
map(formatter, seriesData2),
map(formatter, seriesData3)))
# 用zip()同步四个序列,数值序列用map()定义数据的显示格式为formatter

legend.colorNamePairs = list(zip(chart_colors, names))
# 定义图例上色块对应的数据,此时指定格式的数据已经全部集中到names里了

chart.data  = seriesData1
# 指定饼形图表达的数据列

for i, v in enumerate(chart.data):
    chart.slices[i].fillColor = chart_colors[i]
# 定义饼形图上的色块

# 将饼形图、图例头和数据填进画布上
d.add(chart)
d.add(legendHeader)
d.add(legend)

# 生成PDF文件
from reportlab.graphics import renderPDF
renderPDF.drawToFile(d, 'pieChartWithMulti-columnLegend.pdf')