Reportlab生成PDF文件

这个图表使用LinePlot的子类SimpleTimeSeriesPlot生成时间序列图,表达的时间数据放在一个列表中:

[[['20120101', 100.0], ['20120102', 101.0], ……], [['20120101', 100], ['20120102', 102.0],……]]

[[(19971202, 100.0), (19971231, 100.1704367), ……], [(19971202, 100.0), (19971231, 100.0),……]]
列表里的元素还是一个列表,代表每一条数据线的数据。每条数据线的数据(放在一个列表里)由小列表或小元组组成,小列表或小元组内的数据由x,y组成:x是日期,格式yyyymmdd,可以是整数20120101也可以是字符串'20120101'。

数据放在csv文件里,一个csv文件存放一条数据线的数据:

所有csv文件存放在文件夹userData下,userData放在当前文件夹下(所谓当前文件夹就是跟代码相同的文件夹下):

也给图表添加了标题:
- **self._add(self,String(10,10,'text'),name='title',validate=None,desc=None):添加字符串
- **self.title.text = 'Simple Time Series Plot':定义字符串的内容

- **self.title.x,self.title.y:指定字符串左下角的坐标

代码及注释:

from reportlab.graphics.shapes import Drawing, _DrawingEditorMixin, String
from reportlab.graphics.charts.lineplots import SimpleTimeSeriesPlot
# SimpleTimeSeriesPlot是LinePlot的一个子类,x轴是日期轴,y轴是数值轴
from reportlab.lib.colors import PCMYKColor
from myStyle import *

class LineChart_TimeSeriesPlot(_DrawingEditorMixin,Drawing):
    ‘’‘
    时间序列图
    ’‘’
    def __init__(self, dataFolder = None, width=400,height=200,*args,**kw):
        Drawing.__init__(self,width,height,*args,**kw)      # 添加画板
        self._add(self,SimpleTimeSeriesPlot(),name='chart')
        # 添加时间序列图表,名字叫做chart,接下来设置它的属性

        # 设置图表的坐标
        self.chart.x                = 30
        self.chart.y                = 45

        # 设置图表的宽高
        self.chart.height           = 90
        self.chart.width           = 335

        self.chart.yValueAxis.forceZero = 0     # y数值轴不必从0开始

        self.chart.lines.strokeWidth     = 2    # 数据线宽度

        # 两条数据线的颜色
        self.chart.lines[0].strokeColor = PCMYKColor(100,0,90,50)
        self.chart.lines[1].strokeColor = PCMYKColor(0,100,100,40)

        self.chart.xValueAxis.xLabelFormat            = '{mm}/{YY}'
        # x是日期轴,属性xLabelFormat设置日期显示的格式
        self.chart.xValueAxis.niceMonth               = 1
        # nicely"优雅"的显示月份

        # 这个SimpleTimeSeriesPlot类的图表的data属性有个默认值:
        # [[(19971202, 100.0), (19971231, 100.1704367), ……], [(19971202, 100.0), (19971231, 100.0),……]]
        # 这个程序里存放数据的文件是csv文件,一个csv文件存放一条数据线的数据
        if dataFolder is not None:
            self.chart.data = self.getData(dataFolder)
            # 调用方法函数getData把csv文件里的数据取出放进列表中赋给图表的data属性
            # 实参是csv数据文件的路径字串,返回值是整理好的数据
        print(self.chart.data[1])
        # 整理好的数据长这样:
        #  [[['20120101', 100], ['20120102', 100], ……], [['20120101', 100], ['20120102', 100],……]]

        self._add(self,String(10,10,'text'),name='title',validate=None,desc=None)
        # 添加一行字符串
        self.title.text       = '时间序列图'     # 字符串的内容
        self.title.fontSize   = 16              # 字符串中字符的大小
        self.title.fontName   = 'apple'         # apple是myStyle.py里注册的字体,支持中文
        self.title.y          = 160             # 字符串左下角的x,y坐标
        self.title.x          = 155

    def getData(self, dataLoc):
        # 形参dataLoc接收数据文件的路径字串
        import csv                  # 支持对csv文件的操作
        from pathlib import Path    # 支持对文件路径的操作
        dataFolder = Path(dataLoc)  # dataFolder是Path路径对象,指向数据文件csv所在路径
        dataList = []               # dataList存放整理好的数据,初值为空
        for f in dataFolder.iterdir():  # 遍历dataFolder指向的文件夹
            if not f.name.endswith('.csv'): # 不是csv文件,直接略过
                continue  # 跳过非CSV文件
            csvFileObj = open(f)            # 是csv文件,则打开文件生成文件对象
            readerObj = csv.reader(csvFileObj)  # csv文件的读对象
            usrList = []                    # usrList存放一个用户数据的列表,初值为空
            for row in readerObj:           # 一行一行读csv文件
                d, num = row
                # csv文件里的每一行读出来后放进循环变量row中,长这样['20120101', '100']
                # 分别读进d和num中
                usrList.append([d, float(num)])
                # num转换成数值,d可以保留字符串类型,但格式要为yyyymmdd
            dataList.append(usrList)
            # 将每个用户的列表数据加进到大列表dataList
        return dataList         # 返回大列表,每个元素是每个用户的列表数据

if __name__=="__main__": #NORUNTESTS
    LineChart_TimeSeriesPlot('./userData').save(formats=['pdf'],outDir='.',fnRoot=None)
    # 与之前帖子给的列子不同之处在于生成对象时给了路径字串
    # 路径字串是存放用户数据的csv文件所在文件夹的路径字串
    # .是当前文件夹,当前文件夹就是代码所在的文件夹