β

练习项目03:绘制生成PDF折线图(上)

Python自动化运维 39 阅读

这个练习项目来自《Python基础教程(第2版)》,案例原名为“画副好画”。

不过因为Python版本差异,原文中的一些代码无法使用,而且不能够支持中文。

本篇教程在这个项目基础之上进行了修正,能够完美的呈现目标效果。

一、绘制文字

在绘制折线图之前,我们先尝试生成一个指定尺寸的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文件,打开之后就是前面所看到的示例效果。

这里需要注意的是,示例代码中注册字体的两个参数分别是调用该字体时使用的名称(可以自定义)和文件路径。

因为示例中使用的都是系统内默认包含的字体,所以路径中只写了文件名称(包含扩展名)。

如果使用一些系统中没有安装的字体,必须先进行字体安装或者放到项目文件夹中,通过名称进行调用。

或者,可以将字体文件放在某个目录中,通过相对或绝对路径进行调用。

二、绘制折线

我们先来看一下示例效果:

呃……效果看上去很低级……

不过,通过这样的一个效果,我们能够更简单的掌握折线的绘制。

完成这个示例,我们需要做到以下几点:

1、,我们先完成测试数据的添加和画布的创建。

测试数据是太阳黑子活动信息,数据下载地址是:ftp://ftp.swpc.noaa.gov/pub/weekly/Predict.txt

原书中地址已失效,为了避免再次失效我准备了一个备用地址:http://www.charmpy.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折线图(上)

作者:Python自动化运维
写python,然后喝茶,指挥千军万马~
原文地址:练习项目03:绘制生成PDF折线图(上), 感谢原作者分享。

发表评论