约定
我们导入matplotlib时,推荐使用:
import matplotlib as mpl
因此,简洁起见,在后面我们将经常使用 mpl 代表 matplotlib。
还将用:
- figure ,表示matplotlib绘制的图形;
- Image,表示位图图像,或栅格图像,保存方式为点阵存储,也称为点阵图像;
- Graphic,表示矢量图形,用数学方法描述的图形。
有一部分初学者,因为对位图、矢量图、分辨率、DPI、PPI、图像尺寸、坐标等概念的不清晰,也造成了学习、使用mpl的一些困扰。
将会专门以一篇文章,用草根的语言讨论一下这些基本概念,理清这些概念对理解matplotlib框架非常有好处。
Matplotlib基础架构
Matplotlib是基于Pythony语言,旨在为Python提供一个数据绘图包的开源项目,它以Python的一个库包的形式分发、安装、调用。
mpl是Python的一个包,记住:Python包就是一个定义了__init__.py文件的文件夹而已,包中的各个模块都会保存在这个文件夹中。
matplotlib 实际上就是提供了 3 种API,用于不同的绘图场景。
- The pyplot API
- The object-oriented API
- The pylab API (已弃用)
mpl需要其它包的支持,主要有:
- numpy,用于提供绘图数据,你要用于绘图的数据都应转换化numpy 的 ndarray,才传递给mpl;。事实上,一幅图像也可以保存为一个ndarray(将专门介绍)。
- backend,后端,简单地说就是将mpl代码转换为图形的后台算法,如mpl中最常用的FigureCanvasAgg,将专文讨论backend。
函数式绘图 pyplot API
matplotlib是受MATLAB的启发构建的,MATLAB语言是面向过程的,利用函数的调用,MATLAB中可以轻松的利用一行命令来绘制直线,然后再用一系列的函数调整结果。
matplotlib通过matplotlib.pyplot模块,完全仿照MATLAB的函数形式,提供了一套绘图接口。这套函数接口方便MATLAB用户过度到matplotlib包。
Python中的函数式编程是通过封装对象实现的。matplotlib中的函数式调用其实也是如此。matplotlib本质上还是构建对象来构建图像。只不过pyplot函数将构建对象的过程封装在函数中,从而让我们觉得很方便。
pyplot函数式绘图创造了一个仿真MATLAB的工作环境,并有许多成形的绘图函数,如果只是作为Matplotlib的一般用户,pyplot可以满足大部分的需求。
但利用函数式绘图会有以下缺点:
- 增加了一层“函数”调用,降低了效率。
- 隶属关系被函数掩盖。整个matplotlib包是由一系列有组织有隶属关系的对象构成的。函数掩盖了原有的隶属关系,将事情变得复杂、模糊。
- 细节被函数掩盖。pyplot并不能完全复制对象体系的所有功能,图像的许多细节调整最终还要回到对象。
- 每件事情都可以有至少两种方式完成,用户很容易混淆。
- 封装,掩盖了真相,蒙蔽了很多初学者的双眼,让他们迷失在mpl世界的边缘,始终不能达到自由操控mpl的境界。
第4、5组成了一个陷阱,它就是困住很多初学者的那个最大的坑。
再看下面的函数绘图的示例:
import matplotlib.pyplot as pltplt.plot([1, 2, 3, 4])plt.show()
对于初学者来说,它很简单,也很容易模仿,但很多人不知道,函数封装的一些东西在后台做了些什么,因此长时间只能照猫画虎。
面向对象(OO, object-oriented)绘图
我们改用面向对象(OO, object-oriented)绘图方式绘制上面的直线图。
from matplotlib.figure import Figurefrom matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfig = Figure()canvas = FigureCanvas(fig)ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])line, = ax.plot([1, 2, 3, 4])s, (width, height) = canvas.print_to_buffer() from PIL import Image im = Image.frombytes("RGBA