在reportlab的官方网站(https://www.reportlab.com/chartgallery/pie/)上给出生成各种图表的例子,对于我这种不经常跟图表打交道的人来说还是挺开眼界的,我们拿出几个做中文注释。在即将推出的reportlab的教学视频里会详细介绍每个程序,先来看都生成了哪些图表。
直方图(Bar Chart):
折线图(Line Plot):
饼形图(Pie Chart):
雷达图(Radar Chart或蛛网图Spider Chart):
散点图(Scatter Plot):
分区图(Area Chart):
生成每个图表的程序都放在独立的代码文件里,用自定义的类来完成,程序runall.py把当前文件夹下的所有生成图表的.py的程序逐个运行,生成指定类型的图表文件(可以是pdf、pict或png)。runall.py和注释如下:
# 运行代码所在目录下所有的生成图表的py程序
import sys
import glob # 查找符合特定规则的文件路径名
import inspect # inspect.getmembers()可以获取模块、类或对象的成员或参数信息
def moduleClasses(mod):
"""
:参数mod: 引进的模块
:返回值: 返回模块里定义的类
"""
def P(obj, m=mod.__name__, CT=type):
"""
:参数obj: 可以是模块自己定义的类成员,比如2-2lineChart_withMarkers.py里定义的LineChart_WithMarkers
也可是引用的模块里的成员,比如PCMYKColor(0,0,0,24,alpha=100)
:参数m: mod.__name__得到的模块名,比如'2-2lineChart_withMarkers'
:参数CT: type是元类,type(3)是int类型,type(int)是type类型
:返回值: 真或假
"""
return (type(obj)==CT and obj.__module__==m)
# obj.__module__得到obj所在的模块名
# obj.__module__== m,m是mod.__name__,mod是调用函数给的模块
# 所以这个判断条件确保只提取给出模块的类成员
# type(obj)是obj的类型,obj的类型是元类type
try:
return inspect.getmembers(mod, P)[0][1]
# inspect.getmembers()检查第一个参数mod(module的前三个字母)的成员或参数,
# 这里的mod接收的是模块,比如<module '2-2lineChart_withMarkers' from '/Users/……/2-2lineChart_withMarkers.py'>
# 如果有第二个参数(P是函数名),则只返回使P为真的成员或参数
# inspect.getmembers(mod, P))返回:
# [('LineChart_WithMarkers', <class '2-2lineChart_withMarkers.LineChart_WithMarkers'>)]
except:
return None
def getclass(f):
"""
:参数f: 引入的模块
:返回值: 返回模块里定义的类
"""
return moduleClasses(__import__(f))
# import导入Python模块时,调用的是__import__()函数,只有动态加载模块时才直接使用该函数
# __import__(f)引入f, 如__import__('2-2lineChart_withMarkers')
# 将2-2lineChart_withMarkers.py的内容引入程序
# 这里为了讲课方便,引进的模块名称用数字序号开头标识顺序
# 如果直接在程序中用import 2 - 2lineChart_withMarkers是会报错的
# 但像__import__('2-2lineChart_withMarkers')这样动态引入就可以
# __import__(f)返回引进模块,比如<module '2-2lineChart_withMarkers' from '/Users/……/2-2lineChart_withMarkers.py'>
def run(format, VERBOSE=0):
"""
:参数format: 生成文件的类型,比如pdf,png……
:参数VERBOSE: VERBOSE是冗长、啰嗦,默认为0;如果调用run()时指定为1,则会输出文件的类型
"""
formats = format.split(',')
# 假如接收到的format是' PDF, png',则format被用','分开后得到的formats为[' PDF', 'png']
for i in range(0, len(formats)):
formats[i] == formats[i].strip().lower()
# 剥掉列表formats的每个字符串元素左右的空格,并变成小写,formats变成['pdf', 'png']
allfiles = glob.glob('*.py')
# glob.glob('*.py')将当前文件夹下的py文件名字符串取出来,放进allfiles
# 比如allfiles的内容可能为['2-2lineChart_withMarkers.py', '5-1areaChart_withDynamicLabel.py', ……]
allfiles.sort()
# 对列表allfiles的元素进行排序
for fn in allfiles: # 进入循环一个一个文件处理
f = fn.split('.')[0]
# fn.split('.')把文件名与扩展名分开,比如['2-2lineChart_withMarkers', 'py']
# 索引为0取出文件名放入变量f,即'2-2lineChart_withMarkers'
c = getclass(f)
# 调用自己定义的函数getclass('2-2lineChart_withMarkers')
# 这个函数的行参是名字为f的模块,返回名字为f内的类,比如<class '2-2lineChart_withMarkers.LineChart_WithMarkers'>
if c != None: # 如果fn里确实有定义的类和模块,则存放返回值的变量c就不为None
print(c.__name__) # 显示fn里定义的类名称,比如LineChart_WithMarkers
try:
for fmt in formats:
# 理论上formats是存放着文件格式字串的列表,比如['pdf', 'png']
if fmt: # 如果列表元素不为空
c().save(formats=[fmt],outDir='.',fnRoot=c.__name__)
# c是引入的fn里定义的一个类,c()是类c生成的一个对象
# 调用c类对象的方法函数save()将对象内容生成指定格式的文件
# formats=格式参数,outDir=指定输出文件的路径,.是指当前路径,fnRoot=文件名
if VERBOSE: # 如果调用函数时给的VERBOSE为1
print(" %s.%s" % (c.__name__, fmt))
# 则输出文件名及格式
except:
print(" COULDN'T CREATE '%s.%s'!" % (c.__name__, format))
# 出错输出提示无法生成该格式的文件,继续处理下一个
if __name__ == "__main__":
if len(sys.argv) == 1:
# 以下情况if语句的条件为真:
# 1、在pycharm(或其他集成开发环境)
# 2、在终端/命令窗口进入runall.py所在目录,敲入:python3 runall.py
run('pdf,pict,png')
# 依次声称PDF、PICT和PNG文件类型的图表
else:
try:
if sys.argv[1] == "-h":
# if语句条件为真的情况:
# 在命令行或终端进入runall.py所在目录,运行: python3 runall.py -h
# sys.argv[0]为'runall.py',sys.argv[1]为'-h'
print('usage: runall.py [FORMAT] [-h]')
print(' if format is supplied is should be one or more of pdf,gif,eps,png etc')
print(' if format is missing the following formats are assumed: pdf,pict,png')
print(' -h prints this message')
else:
t = sys.argv[1:]
# 比如命令:python3 runall.py PDF PNG
# sys.argv[1]为'PDF',sys.argv[2]为'PNG',t的值为['PDF', 'PNG']
for f in t:
run(f)
# 进入循环,依次运行run('PDF')和run('PNG'),指定生成的文件类型
except: # 给出出错提示,输出跟python3 runall.py -h一样
print('usage: python3 runall.py [FORMAT][-h]')
print(' if format is supplied is should be one or more of pdf,gif,eps,png etc')
print(' if format is missing the following formats are assumed: pdf,pict,png')
print(' -h prints this message')
raise