18 Reportlab生成图表之派里有派
这个图表看着挺高档,其实就是两个带图例的饼形图加上几条直线而已:
"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开始