初识绘图
本章对基本的 Matplotlib 绘图进行介绍,包括点型、线型与多图绘制。
本章加载的库如下所示:
[1]:
import os
import numpy as np
from matplotlib import pyplot as plt
import matplotlib as mpl
以上加载的库中,mpl 一般是不用加载的。本章由于需要介绍全局参数,故需要加载。在使用 Jupyter Notebook 时,我们往往还需要指定图像的输出尺寸,以获得较好的视觉效果:
[2]:
plt.rcParams['figure.figsize'] = [10, 6]
在本章最后更新时,使用的 Matplotlib 版本是:
[3]:
mpl.__version__
[3]:
'3.0.2'
基础的 plt.plot()
本小节仅介绍简单的绘制命令,包括线型与颜色。关于添加标题、图例、文字等内容,请参阅后续章节。
Matplotlib 的大部分绘图命令都是通过 plt
下的功能实现的,而最简单的函数就是 plt.plot()
。比如一个二次函数图像:
[4]:
x = np.linspace(0, 2, 100)
y1 = x ** 2
plt.plot(x, y1)
plt.show() # 记得在最后用 plt.show() 输出图像
从上面也能看出,我们使用 plt.show()
函数来输出图像。
我们也可以在一幅图上绘制多个函数,它们会自动以不同的颜色绘制:
[5]:
y2 = 2 + 2 * np.sin(np.pi * x)
plt.plot(x, y1)
plt.plot(x, y2)
plt.show()
也就是说,“叠加绘制”默认是开启的——如果有读者使用过 MatLab,那么恭喜你,在 Matplotlib 这里不需要再惦记着什么 hold on 命令了。
如果我们不需要叠加绘制,我们可以随时插入 plt.close()
命令,来关闭当前绘制。或者使用 plt.close('all')
来清除所有绘制。
点型与线型
在有多个曲线时,我们往往通过更改点型或线型来区分它们。尤其是需要黑白打印的场合,线的颜色并不是有效的方案。下面是一个极端的例子:
[6]:
plt.plot(x, y1, color="b", linestyle=":", linewidth=3, dashes=(2,1), # 线的属性
marker="d", ms=10, mew=1.5, mec="g", mfc="w", # 点的属性
markevery=10)
plt.plot(x, y2, "#bf242a", ls="-", lw=1)
plt.show()
以上的参数(括号中是参数的缩写)的含义分别是:
color
:线的颜色(详细请参考“颜色”一节)。基础的有红r,绿g,蓝b,青c,洋红m,黄y,黑k,白w。以及其他的表述:HTML 码:例如
"#66ccff"
标准化后的 RGB 元组:例如
(1, 0, 0)
灰度字串:
"0.5"
linestyle (ls)
:线型。实线”-“,虚线”–“,点划线”-.”,点线”:“。dashes
: 虚线比例。传入元组 (a,b),那么划线长与间隔长之比为 a/b。linewidth (lw)
:线宽。marker
:点样式。实心”.”,像素”,“,圆点”o”,方块”s”,上折/下折箭头”v”/“^”,左折/右折箭头”<“/”>“,五边形”p”,六边形”h”,星”*“,加号”+“,叉号”x”,(瘦)钻石”d/D”,竖线”|“,横线”_“。markevery
:每几个点才绘制一个点。markersize (ms)
:点大小。markeredgewidth (mew)
:点边缘线宽。markeredgecolor (mec)
:点边缘颜色。默认与线同色。markerfacecolor (mfc)
:点填充颜色。默认与线同色。
颜色
Matplotlib 的颜色使用是个复杂的话题。通常来说,直接调用的颜色包括:
标准化的 RGB:以三元元组的形式,比如
(0, 0, 1)
代表 (0, 0, 255),即纯蓝。HTML 16进制颜色码:以字符串的形式,比如
"#0F0F0F"
。标准化的灰度值:以字符串形式,比如
0.5
。RGB 与 CMYK 标准色字符:以单个字符形式,有:
r,g,b,c,m,y,k,w
八种,其中 w 是白色。X11/CSS4 标准的颜色名:参考下面的图像。
XKCD 颜色调查(参考此页面):例如”xksd:sky blue”。
以及 matplotlib 采用的色环:
matplotlib 默认的十色环:“C0”, “C1”, …,“C9”。这是 matplotlib 绘图默认依次使用的颜色。
十色环的另一种形式:‘tab:blue’, ‘tab:orange’, ‘tab:green’, ‘tab:red’, ‘tab:purple’, ‘tab:brown’, ‘tab:pink’, ‘tab:gray’, ‘tab:olive’, ‘tab:cyan’。
以上字符串(除16进制码外)均是大小写敏感的。
下图是一个 X11 颜色表。该颜色表是我用 Matplotlib 生成的,不过为了排版简洁,我把这个代码块在生成网站时隐藏了;感兴趣的读者可以访问本章对应的 ipynb 文件进行查看。
子图绘制 plt.subplots()
需要将多张子图绘制到一张图内时,使用 plt.subplots()
函数。
语句 fig, axarr = plt.subplots(...)
可以设置一个 nrows 行、ncols 列个子图组成的大图:
参数:
nrows=1, ncols=1
: 子图矩阵的行数与列数。默认一行一列。sharex/sharey=False
:共享 x/y 轴。True
是所有子图共享,'row'
是每行共享,'col'
是每列共享。
返回值:
fig
:所有子图组成的总图像,可以用于保存为图像文件。axarr
:一个 \(nrows\times ncols\) 的矩阵,其第 \(j\) 个元素即是第 \(j\) 个子图。
下面是一个例子,展示了绘制 2 个图(两行一列)的情况:
[8]:
x = np.linspace(0, 4 * np.pi, 100)
y = [np.sin(x), np.sin(2*x)]
plt.close('all')
f, (ax1, ax2) = plt.subplots(2)
ax1.plot(x, y[0])
ax2.plot(x, y[1])
plt.show()
对于多行多列的情况,可以利用 for 循环,并使用 axarr.ravel()
来展平矩阵。下列是一个两行两列的 4 子图例子,展示了 sharex/sharey
参数的使用:
[9]:
x = [np.linspace(0, k*2*np.pi, 100) for k in (1, 2)]
y = [
np.sin(x[0]), 2*np.cos(x[0]),
np.sin(2*x[1]), np.cos(2*x[1])
]
plt.close('all')
# 所有子图 x 轴共享,每一行内的子图 y 轴共享
f, axarr = plt.subplots(2, 2, sharex=True, sharey='row')
for i, ax in enumerate(axarr.ravel()):
ax.plot(x[i//2], y[i])
plt.show()
由于子图操作还有很多细节,我将在后文中单独开启章节进行讨论。
保存绘图 f.savefig()
上述多图绘制的例子中,返回的 f, axarr
中的 f.savefig(fname, ...)
即可帮助我们保存图像到文件 fname
。该函数的常用参数包括:
transparent=False
:是否使用透明背景。format
:如果文件名fname
中不包含扩展名,那么可以通过该参数指定。例如jpg/jpeg, png, pdf, svg
。bbox_inches
:设置图像的 bounding box 数值。当设置为'tight'
时会自动设置,以达到“减少图像外侧白边”的效果。题外话:如果仅是为了达到减少白边的效果,也可以尝试在savefig()
之前使用f.tight_layout()
进行处理。
下面是一个保存图片的例子:
[10]:
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
f, ax = plt.subplots()
ax.plot(x, y)
fig_file = os.path.join("pics", "saved_fig.png") # 保存在 pics/saved_fig.png
f.savefig(fig_file, transparent=True, bbox_inches='tight')