Reportlab生成PDF文件

这个图表基于指标比较市场表现

- **legend.boxAncho=sw:**

锚点在左下角,左下角位置固定。如果有更多条目向上增长,无需再调整。

- **chart.lines[0].inFills=True:**

指定一条数据线的表现方式是区域,而不是折线

 

图表左侧和下侧分别加了两个长方形:

左侧长方形:

- self._add(self,Rect(0,0,self.width,self.height,

                   fillColor=self._colors[5]),name='bgrect0')

- self.bgrect0.width = self.chart.x

- self.bgrect0.height = self.height

下侧长方形:

-self._add(self,Rect(0,0,self.width,self.height,

                  fillColor=self._colors[5]),name='bgrect1')

- self.bgrect1.x = self.chart.x

- self.bgrect1.width = self.chart.width

- self.bgrect1.height = self.chart.y

 

x轴是一个日期轴,有些属性可以帮忙选择合适的日期,比如

- forceDatesEachYear

- forceEndDate

- forceFirstDate

- forceZero

- niceMonth

 

- **chart.xValueAxis.labels.angle=45:**

x轴刻度标签倾斜45度

 

图例上色块与条目的对应用方法函数getContents()完成,

这个方法函数的返回值Drawing.getContents(self)

可以用这个函数完成一些复杂的“动作”,不用调用,往画布上渲染时会自动调用

代码和注释:

"折线与面积图共存"
from reportlab.lib.colors import PCMYKColor
from reportlab.graphics.charts.lineplots import LinePlot
from reportlab.graphics.charts.legends import Legend
from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, Rect
from reportlab.lib.formatters import DecimalFormatter
from reportlab.graphics.charts.axes import NormalDateXValueAxis

class AreaChart_WithLines(_DrawingEditorMixin,Drawing):
    def __init__(self,width=648,height=306,*args,**kw):
        Drawing.__init__(self,width,height,*args,**kw)

        # 颜色列表
        self._colors = PCMYKColor(66,13,0,22, alpha=40) ,PCMYKColor(0,100,100,40) ,PCMYKColor(100,0,90,50) ,PCMYKColor(0,0,0,40) ,PCMYKColor(10,0,100,11) ,PCMYKColor(15,0,0,0) ,PCMYKColor(0,0,0,50)

        # 往画板上添加两个长方形,一个折线图对象
        self._add(self,Rect(0,0,self.width,self.height,fillColor=self._colors[5]  ,strokeColor=None),name='bgrect0',validate=None,desc=None)
        self._add(self,Rect(0,0,self.width,self.height,fillColor=self._colors[5],strokeColor=None),name='bgrect1',validate=None,desc=None)
        self._add(self,LinePlot(),name='chart',validate=None,desc=None)

        # 图表的坐标和宽高
        self.chart.x = 70
        self.chart.y = 36
        self.chart.width = 446
        self.chart.height = 225

        self.chart.lines[0].inFill=True
        # 索引为0的数据线采用面积图的表现形式
        self.chart.lines.strokeWidth     = 2.5
        # 数据线的宽度

        #  长方形的宽高、填充色和位置
        self.bgrect0.width = self.chart.x
        self.bgrect0.height = self.height
        self.bgrect0.fillColor        = PCMYKColor(10,10,10,10,alpha=100)
        self.bgrect1.x = self.chart.x
        self.bgrect1.width = self.chart.width
        self.bgrect1.height = self.chart.y
        self.bgrect1.fillColor        = PCMYKColor(10,10,10,10,alpha=100)

        # x轴
        self.chart.xValueAxis = NormalDateXValueAxis()
        self.chart.xValueAxis.bottomAxisLabelSlack = 0
        # self.chart.xValueAxis.bottomAxisLabelSlack = 2
        # self.chart.xValueAxis.bottomAxisLabelSlack = 0.5
        # 数字,按比例调整标签间距
        self.chart.xValueAxis.dailyFreq = 0
        # self.chart.xValueAxis.dailyFreq = 1
        # 布尔型,如果为真,月底那天的数据被标在刻度上
        # self.chart.xValueAxis.forceEndDate = True
        # self.chart.xValueAxis.forceFirstDate = True
        self.chart.xValueAxis.joinAxisMode='bottom'
        # 'bottom', 'top', 'value', 'points,joinAxisPos
        self.chart.xValueAxis.labels.angle = 45
        self.chart.xValueAxis.labels.boxAnchor = 'e'
        # 右边的锚点不动,绕着锚点旋转45度
        self.chart.xValueAxis.labels.dx = -2
        self.chart.xValueAxis.labels.dy = -10
        # 对标签位置做微调
        self.chart.xValueAxis.labels.fontName = 'Times-Roman'
        self.chart.xValueAxis.labels.fontSize = 10
        # 标签字体和大小
        self.chart.xValueAxis.maximumTicks = 7
        self.chart.xValueAxis.minimumTickSpacing = 20 # in points
        # 做多几个刻度,刻度腱距离要大于20个points
        self.chart.xValueAxis.strokeColor = self._colors[6]
        self.chart.xValueAxis.strokeWidth = 0.5
        # 数据线的颜色和宽度
        self.chart.xValueAxis.tickDown =  10
        # 刻度向下伸出多少
        self.chart.xValueAxis.visibleGrid = False
        # 格子线不可见
        self.chart.xValueAxis.xLabelFormat = '{mm}/{yyyy}'
        # x轴刻度标签的显示格式

        # y轴
        self.chart.yValueAxis.avoidBoundFrac = 0.1
        # self.chart.yValueAxis.avoidBoundFrac = 0.01
        # 影响坐标轴的数值表达范围,进而影响数据线
        self.chart.yValueAxis.drawGridLast          = True
        # 最后画格子线
        self.chart.yValueAxis.forceZero = True
        # 0刻度出现
        self.chart.yValueAxis.labels.dy = 0
        self.chart.yValueAxis.labels.fontName = 'Times-Roman'
        self.chart.yValueAxis.labels.fontSize = 10
        self.chart.yValueAxis.labels.rightPadding   = 10
        self.chart.yValueAxis.labelTextFormat = DecimalFormatter(places=0,thousandSep=',',decimalSep='.',prefix='$')
        # y轴方向微调刻度标签以及刻度标签的字体、大小、右留白、显示格式
        self.chart.yValueAxis.maximumTicks = 4
        # 最多4个刻度
        # self.chart.yValueAxis.valueMax = 200000
        # self.chart.yValueAxis.valueMin = 60
        # self.chart.yValueAxis.valueStep =50000
        # 刻度最大最小值,步长
        self.chart.yValueAxis.rangeRound='floor'
        # 刻度最大最小值往小了取
        self.chart.yValueAxis.tickLeft = 5
        self.chart.yValueAxis.tickRight = 0
        # 刻度线左右伸出多少
        self.chart.yValueAxis.visibleAxis = False
        # 坐标轴不可见
        self.chart.yValueAxis.visibleGrid = True
        self.chart.yValueAxis.gridStrokeWidth = 0.5
        self.chart.yValueAxis.gridStrokeColor = self._colors[6]
        # 格子线可见,格子线的颜色和宽度
        self.chart.yValueAxis.visibleTicks = True
        # 刻度线可见
        self.chart.yValueAxis.strokeColor = self._colors[6]
        self.chart.yValueAxis.strokeWidth = 0.5
        # y轴和刻度线的颜色和宽度

        # 图例
        self._add(self,Legend(),name='legend',validate=None,desc=None)
        self.legend.alignment = 'right'
        # 文字在色块右
        self.legend.boxAnchor = 'sw'
        # 锚点左下角
        self.legend.x = self.chart.x + self.chart.width + 25
        self.legend.y = self.chart.y
        # 锚点的坐标
        self.legend.columnMaximum = 10
        # 每列最多10行
        self.legend.deltax = 50
        self.legend.deltay = 0
        # 色块横纵间距
        self.legend.dx = 8
        self.legend.dy = 8
        # 色块宽高
        self.legend.dxTextSpace = 5
        # 色块与文字间距
        self.legend.strokeColor = None
        self.legend.strokeWidth = 0
        # 色块轴线宽度和颜色
        self.legend.fontName = 'Times-Roman'
        self.legend.fontSize = 12
        # 文字字体和大小
        self.legend.yGap = 0
        # 调整行间距

        # 数据表数据,三组
        self.chart.data = [[(19960901, 100000.0), (19961201, 109034.00000000001), (19970301, 110105.00000000001), (19970601, 127487.0), (19970901, 134702.0), (19971201, 136920.0), (19980301, 153788.0), (19980601, 158997.0), (19980901, 141245.0), (19981201, 171859.0), (19990301, 179215.0), (19990601, 193963.0), (19990901, 181679.0), (19991201, 202828.0), (20000301, 216832.0), (20000601, 218377.0), (20000901, 222553.0), (20001201, 220915.00000000003), (20010301, 204568.0), (20010601, 212621.0), (20010901, 185524.0), (20011201, 202977.0), (20020301, 204425.0), (20020601, 176716.0), (20020901, 143573.0), (20021201, 158079.0), (20030301, 153953.0), (20030601, 181898.0), (20030901, 186917.0), (20031201, 210109.0), (20040301, 214340.99999999997), (20040601, 217241.00000000003), (20040901, 207773.0), (20041201, 226420.99999999997), (20050301, 219802.0), (20050601, 224784.0), (20050901, 234346.0), (20051201, 238378.99999999997), (20060301, 244329.99999999997), (20060601, 237279.00000000003), (20060901, 250893.0)],
                           [(19960901, 100000.0), (19961201, 107756.00000000001), (19970301, 109009.0), (19970601, 127193.0), (19970901, 137804.0), (19971201, 140379.0), (19980301, 159140.0), (19980601, 163192.0), (19980901, 145219.0), (19981201, 177235.0), (19990301, 185424.0), (19990601, 199092.0), (19990901, 186227.0), (19991201, 217680.0), (20000301, 225952.99999999997), (20000601, 218523.99999999997), (20000901, 222131.0), (20001201, 199163.0), (20010301, 171684.0), (20010601, 182742.0), (20010901, 150187.0), (20011201, 167530.0), (20020301, 166471.0), (20020601, 141964.0), (20020901, 116748.99999999999), (20021201, 126703.00000000001), (20030301, 122520.0), (20030601, 142817.0), (20030901, 147424.0), (20031201, 165744.0), (20040301, 169164.0), (20040601, 171480.0), (20040901, 167844.0), (20041201, 183880.0), (20050301, 177886.0), (20050601, 182389.0), (20050901, 189194.0), (20051201, 194098.0), (20060301, 202789.00000000003), (20060601, 199425.0), (20060901, 208632.99999999997)],
                           [(19960901, 100000.0), (19961201, 108335.0), (19970301, 111239.0), (19970601, 130658.99999999999), (19970901, 140444.0), (19971201, 144476.0), (19980301, 164629.0), (19980601, 170065.0), (19980901, 153148.0), (19981201, 185764.0), (19990301, 195021.0), (19990601, 208768.00000000003), (19990901, 195733.0), (19991201, 224858.0), (20000301, 230015.0), (20000601, 223903.0), (20000901, 221735.00000000003), (20001201, 204384.0), (20010301, 180154.0), (20010601, 190697.0), (20010901, 162707.0), (20011201, 180094.0), (20020301, 180588.0), (20020601, 156393.0), (20020901, 129375.0), (20021201, 140290.0), (20030301, 135871.0), (20030601, 156793.0), (20030901, 160942.0), (20031201, 180538.0), (20040301, 183594.0), (20040601, 186752.0), (20040901, 183261.0), (20041201, 200178.0), (20050301, 195875.0), (20050601, 198549.0), (20050901, 205708.0), (20051201, 210001.00000000003), (20060301, 218838.0), (20060601, 215685.0), (20060901, 227904.99999999997)]]

        self._seriesNames = 'Index', 'Europe Market', 'Asia Market'
        # 数据线代表的名字列表

    def getContents(self):
        self.legend.colorNamePairs = list(zip(self._colors, self._seriesNames))
        # 图例上色块与名字一一对应
        for i in range(len(self._seriesNames)):
            self.chart.lines[i].strokeColor = self._colors[i]
            # 数据线的颜色
        return Drawing.getContents(self)

if __name__=="__main__":
    AreaChart_WithLines().save(formats=['pdf'],outDir='.',fnRoot=None)