这个练习项目来自《Python基础教程(第2版)》,案例原名为“画副好画”。
不过因为Python版本差异,原文中的一些代码无法使用,而且不能够支持中文。
本篇教程在这个项目基础之上进行了修正,能够完美的呈现目标效果。
一、绘制文字
在绘制折线图之前,我们先尝试生成一个指定尺寸的PDF文件,并前显示一些文字。
当然文字是中文的。
示例效果:
完成这个示例,我们需要做到以下几点:
- 支持中文内容
- 创建指定尺寸的画布
- 添加指定的文字并设置样式与位置
- 生成PDF文件
绘制PDF文件需要使用到reportlab模块中的很多功能。
在下方的示例代码中,我做了详细的注释,大家可以通过注释进行理解。
示例代码:
from reportlab.graphics.shapes import Drawing, String, colors from reportlab.graphics import renderPDF from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont '''--- 添加中文支持 ---''' pdfmetrics.registerFont(TTFont('msyh', 'msyh.ttf')) # 注册要使用的字体 pdfmetrics.registerFont(TTFont('g', 'futurama.ttf')) '''--- 创建画布 ---''' d = Drawing(300, 200) # 创建画布并设置画布尺寸 '''--- 创建文本内容并设置样式与位置 ---''' s1 = String(150, 100, '这一行使用字体的字体是微软雅黑!') # 创建字符串并设置坐标、内容 s1.fontName = 'msyh' # 设置字体 s1.fontSize = 14 # 设置字号 s1.fillColor = colors.red # 设置字体颜色 s1.textAnchor = 'middle' # 设置锚点为中心(即位置坐标为文本中心点坐标) s2 = String(150, 120, 'axure!', fontName='g', fontSize=16, fillColor=colors.red, textAnchor='middle') # 另一种设置方式 '''--- 添加内容到画布并生成PDF文件 ---''' d.add(s1) # 将字符串添加到画布 d.add(s2) renderPDF.drawToFile(d, 'myPDF.pdf', '我的第一个PDF文件。') # 生成PDF文件并设置文件名称与文档描述
运行以上代码,在项目文件夹下就会生成一个PDF文件,打开之后就是前面所看到的示例效果。
这里需要注意的是,示例代码中注册字体的两个参数分别是调用该字体时使用的名称(可以自定义)和文件路径。
因为示例中使用的都是系统内默认包含的字体,所以路径中只写了文件名称(包含扩展名)。
如果使用一些系统中没有安装的字体,必须先进行字体安装或者放到项目文件夹中,通过名称进行调用。
或者,可以将字体文件放在某个目录中,通过相对或绝对路径进行调用。
二、绘制折线
我们先来看一下示例效果:
呃……效果看上去很低级……
不过,通过这样的一个效果,我们能够更简单的掌握折线的绘制。
完成这个示例,我们需要做到以下几点:
- 添加测试数据
- 创建指定尺寸的画布
- 完成每一条线坐标点的创建
- 生成PDF文件
1、,我们先完成测试数据的添加和画布的创建。
测试数据是太阳黑子活动信息,数据下载地址是:ftp://ftp.swpc.noaa.gov/pub/weekly/Predict.txt
原书中地址已失效,为了避免再次失效我准备了一个备用地址:http://www.opython.com/downloads/predict.txt
从下载到的文本文档中复制一些数据,并改成下方示例代码中的格式,也就是每一条数据都是一个元组。
from reportlab.graphics.shapes import Drawing, PolyLine, colors from reportlab.graphics import renderPDF '''--- 添加测试数据 ---''' data = [ # 年份,月份,预测,最高,最低 (2017, 10, 15.0, 20.0, 10.0), (2017, 11, 14.9, 20.9, 8.9), (2017, 12, 15.2, 22.2, 8.2), (2018, 1, 15.3, 22.3, 8.3), (2018, 2, 15.1, 23.1, 7.1), (2018, 3, 14.1, 23.1, 5.1), (2018, 4, 13.7, 22.7, 4.7) ] '''--- 创建画布 ---''' draw = Drawing(400, 240)
2、我们需要做的是把元组中每一列的信息绘制为一条线。
画布的坐标如下图所示:
画布中x轴与y轴的坐标原点为左下方,然后,在画布中任何一个点都有x轴和y轴的坐标。
我们绘制折线图,需要考虑不仅仅要考虑画布尺寸,还要考虑图表的尺寸以及x轴每一点的间隔(线是由点连接而成)。
例如,我们需要在画布两侧各留40像素的空白。
这个计算方法,应该是画布总宽度减去两侧留白,然后根据数据列表中元组的数量对剩余的空间进行均分。
不过要注意,如果数据是8个元组,间隔要划分为7个。
了解了这个计算方法,我们先把所有点的x轴坐标列表创建出来。
还记得列表推导式吗?
示例代码:
pos_x = [320 / (len(data) - 1) * x + 40 for x in range(len(data))] # 每条线x轴各点坐标列表
上方代码中,我们通过图表总宽度除以间隔数量,再乘以点的序号,最后加上左侧的留白宽度形成了一个x轴各点坐标的列表。
然后,是每一条线y轴坐标列表的创建。
示例代码:
predict = [row[2] for row in data] # 预测线y轴各点的列表 high = [row[3] for row in data] # 最高线y轴各点的列表 low = [row[4] for row in data] # 最低线y轴各点的列表
在上方代码中,同样通过列表推导式,将测试数据中每个元组的每一列数据分别存入到了不同的列表中。
有了每条线的x轴与y轴坐标的列表,接下来,我们把x轴坐标列表和y轴坐标列表混合,形成每条线的各点坐标列表。
然后,将线的坐标列表作为参数,对PolyLine类进行实例化,创建每条线段的对象。
示例代码:
predict_line = PolyLine(list(zip(pos_x, predict)), strokeColor=colors.green) # 预测线对象的创建 high_line = PolyLine(list(zip(pos_x, high)), strokeColor=colors.red) # 最高线对象的创建 low_line = PolyLine(list(zip(pos_x, low)), strokeColor=colors.blue) # 最低线对象的创建
注意:zip()函数返回结果是zip对象,需要通过list()函数转换为列表。否则不能使用在PolyLine类的实例化中。
最后,我们只需要把线段对象添加到画布对象,并生成PDF文件就可以了。
本节练习源代码:【点此下载】
转载请注明:魔力Python » 练习项目03:绘制生成PDF折线图(上)