Python绘图笔记——1.基础
matplotlib 介绍
matplotlib
大致是类似 matlab 风格的 2D 绘图库(3D
的功能比较弱,还是基于 2D 引擎勉强实现的),同时提供了两套 api:
- 一个是面向过程的,主要调用
matplotlib.pyplot
的函数; - 一个是面向对象的,主要调用
matplotlib
的两个子类:matplotlib.figure.Figure
和matplotlib.axes.Axes
,使用它们的方法进行细节操作。
面向过程的 api
适合简易使用的场景,但是不容易弄清原理;为了更复杂的绘图要求,这里主要采用面向对象的
api。关于绘图的呈现方式,在 Jupyter 中很可能会自动绘图而不需要
plt.show()
,这与魔法指令 %matplotlib inline
有关。
在这一系列笔记中,需要使用如下模块: 1
2
3import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
由于 matplotlib
的内容太多太杂,这里只会介绍最容易理解的,最本质的面向对象的接口,然后作为辅助会介绍其它等价的,或者更方便的调用方式。但是
matplotlib
的面向对象其实有很多层,在每一层都可能为同一个功能提供了等价的接口,这里为了简化笔记,主要考虑
Figure
和 Axes
层面提供的接口。
简单例子
面向过程风格的绘图例子如下,主要是 plt
的函数调用:
1
2
3
4
5plt.plot(
np.linspace(0, 5, 100),
(lambda x: np.cos(2 * np.pi * x) * np.exp(-x))(np.linspace(0, 5, 100)),
)
plt.title("eg-1-1")
面向对象风格的绘图例子如下,主要是画布和子图的方法调用:
1
2
3
4
5
6fig, ax = plt.subplots()
ax.plot(
np.linspace(0, 5, 100),
(lambda x: -np.cos(2 * np.pi * x) * np.exp(-x))(np.linspace(0, 5, 100)),
)
ax.set_title("eg-1-2")
基本概念
对于一个图像,matplotlib
将其分成了两层主要的概念:
Figure
层,可以理解为整个画布,控制整体的尺寸,标题等;Axes
层,可以理解为一个子图或者子图的数组,这里的子图通常有两个坐标轴,以及具体数据图像和细节组成,因此名称为Axes
。一个Figure
对象可以包括多个子图,达到多个子图并列放置的效果。
这两个概念非常难以翻译,因此下面主要使用英文。
一个 Figure
上主要有如下的元素:
Title
标题,这里存在Figure
标题和Axes
标题的区分Legend
图例x Axis, y Axis
坐标轴xlabel, ylabel
坐标轴标签Grid
网格Line
线条Markers
标记Major tick, Minor tick
主刻度,副刻度Major tick label
主刻度标签Spine
边框线
各个元素如下图所示
创建 Figure 和 Axes
创建 Figure
创建 Figure 对象的函数原型如下 1
2
3
4
5def figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)
...
fig = plt.figure()
fig = plt.figure(figsize=(4,3))
常用参数的含义:
figsize
尺寸,依次为横向宽度和纵向高度,单位为英寸,例如figsize=(5,2.7)
dpi
分辨率facecolor
背景颜色edgecolor
边框颜色frameon
是否显示边框
添加 Axes
Figure 上必须有至少一个 Axes 对象,才能进行绘图,绘图的数据终归是要基于 Axes 的坐标轴体系来完成。
在Figure上添加一个 Axes 对象可以使用下面的语句 1
2fig = plt.figure()
ax = fig.add_subplot(111)
多个 Axes 在同一个 Figure 上是按照矩阵格式排列布局的,例如 3 行 2
列一共 6 个位置,当然并不要求填满所有位置。 可以使用如下方式,依次添加
Axes 对象,需要给出整体的行列数以及自身的序号(从 1 开始)
1
2
3
4
5
6
7
8fig = plt.figure()
ax1 = fig.add_subplot(3,2,1) # 3行2列,位置1
ax2 = fig.add_subplot(3,2,2)
ax3 = fig.add_subplot(3,2,3)
ax4 = fig.add_subplot(3,2,4)
ax5 = fig.add_subplot(3,2,5)
ax6 = fig.add_subplot(3,2,6)
得到的空给框架如下(这里的刻度尺都是动态的,会随着填入数据的范围而调整)
对于上面函数中小的个位数索引(即总位置不超过 9
个),可以直接拼成一个三位数参数,例如 1
2
3
4ax1 = fig.add_subplot(3,2,1)
# i.e.
ax1 = fig.add_subplot(321)
注意:如果反复添加 Axes,它们可能会相互重叠显示,显得非常混乱。
一次性创建 Figure 并添加 Axes
对于多行多列的矩阵布局,先创建 Figure,然后一个个添加 Axes
非常繁琐,可以使用pyplot
提供的 plt.subplots
接口一次性完成。
例如,创建一个Figure并添加一个Axes 1
2
3fig, ax = plt.subplots()
type(ax) # matplotlib.axes._axes.Axes
例如,创建一个Figure并添加多个Axes 1
2
3
4fig, axes = plt.subplots(3,2)
type(axes) # numpy.ndarray
print(axes.shape) # (3,2)
通过访问这个数组的分量来实现对每一个 Axes 的修改。
需要注意的是,还有一个名称非常相似的接口
plt.subplot
,它是面向过程绘图的接口,含义是为当前的 Figure 添加一个 Axes。