21 第三个折线图(Line Plot)
这个图表使用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文件所在文件夹的路径字串
# .是当前文件夹,当前文件夹就是代码所在的文件夹