一、实验介绍
1.1 实验内容
Matplotlib 是支持 Python 语言的开源绘图库,因为其支持丰富的绘图类型、简单的绘图方式以及完善的接口文档,深受 Python 工程师、科研学者、数据工程师等各类人士的喜欢。这是 Matplotlib 绘图课程的第 2 章节,将带你学会如何使用参数绘出更复杂的 2D 图像。
1.2 实验知识点
- Matplotlib 绘制 2D 图像
1.3 实验环境
- python2.7
- Xfce 终端
- ipython 终端
1.4 适合人群
本课程难度为一般,属于初级级别课程,适合具有 Python 基础,并对使用 Matplotlib 绘图感兴趣的用户。
二、二维绘图进阶
在前一个章节中,我们已经了解到了如何使用 Matplotlib 绘出常用的图像,包括线型图、饼状图、散点图等。但是,Matplotlib 默认的样式的确算不上美观。所以,这一个章节就是如何设置绘图方法的参数,从而画出更漂亮和自己想要的图形。
2.1 线型图样式
我们已经知道了,线型图通过 matplotlib.pyplot.plot(*args, **kwargs)
方法绘出。其中,args
代表数据输入,而 kwargs
的部分就是用于设置样式参数了。
二维线型图包含的参数超过 40 余项(文档 P1390)。其中常用的也有 10 余项,选取一些比较有代表性的参数列举如下:
参数 | 含义 |
---|---|
alpha= |
设置线型的透明度,从 0.0 到 1.0 |
color= |
设置线型的颜色 |
fillstyle= |
设置线型的填充样式 |
linestyle= |
设置线型的样式 |
linewidth= |
设置线型的宽度 |
marker= |
设置标记点的样式 |
…… | …… |
对于上面提到的这几项。
线型颜色 color =
的预设值(文档 P1527)有:
color = 参数值 |
颜色 |
---|---|
b | 蓝色 |
g | 绿色 |
r | 红色 |
w | 白色 |
m | 洋红色 |
y | 黄色 |
k | 黑色 |
…… | …… |
其实,大部分都是所颜色所对应的英文名称首字母。当然,你也可以通过color = '#008000'
的方式来设置任何你想要的颜色。
线型的样式 linestyle =
预设的参数值(文档 P1250)有:
linestyle = 参数值 |
线型 |
---|---|
'-' | 默认实线 |
'--' | 虚线 |
'-.' | 间断线 |
':' | 点状线 |
下图展示了 4 种常见线型的样式
样本点标记样式 marker =
预设的参数值(文档 P1527)就更多了:
marker = 参数值 |
样本点标记 |
---|---|
'.' | 实心点 |
',' | 像素点 |
'o' | 空心点 |
'p' | 五角形 |
'x' | x 形 |
'+' | + 形 |
…… | …… |
下图展示了所有标记对应的参数值和样式
下面,我们来重新画一遍正弦函数的图像。添加几个参数,希望它不再那么单调。由于在线环境的 Matplotlib 版本较低,在本地环境运行的最新版本画出来的默认图像样式会更好看一些。
# -*- coding: utf-8 -*
from matplotlib import pyplot as plt # 载入 pyplot 绘图模块
import numpy as np # 载入数值计算模块
# 在 -2PI 和 2PI 之间等间距生成 1000 个值,也就是 X 坐标
X = np.linspace(-2 * np.pi, 2 * np.pi, 1000)
# 计算 sin() 对应的纵坐标
y1 = np.sin(X)
# 计算 cos() 对应的纵坐标
y2 = np.cos(X)
# 向方法中 `*args` 输入 X,y 坐标
plt.plot(X, y1, color='r', linestyle='--', linewidth=2, alpha=0.8)
plt.plot(X, y2, color='b', linestyle='-', linewidth=2)
plt.show()
2.2 散点图样式
除了线型图以外,散点图也是常用图形之一。例如,我们在使用机器学习算法聚类的时候,往往就会通过散点图将样本数据展示出来。
Matplotlib 中,绘制散点图的方法我们已经知道了,那就是 matplotlib.pyplot.scatter()
。接下来,我们就看一看它包含有哪些参数。
参数 | 含义 |
---|---|
s= |
散点大小 |
c= |
散点颜色 |
marker= |
散点样式 |
cmap= |
定义多类别散点的颜色 |
alpha= |
点的透明度 |
edgecolors= |
散点边缘颜色 |
其中,散点的大小通过设置数值大小控制。散点的颜色可以是一种,参数值和线型的颜色设置类似。散点的颜色也可以是多种,可以使用一个列表对每一个点的颜色单独设置。
# -*- coding: utf-8 -*
from matplotlib import pyplot as plt # 载入 pyplot 绘图模块
import numpy as np # 载入数值计算模块
x = np.random.rand(100) # 随机在 0 到 1 之间生成 100 个数值
y = np.random.rand(100) # 随机在 0 到 1 之间生成 100 个数值
colors = np.random.rand(100) # 随机在 0 到 1 之间生成 100 个数值
size = np.random.normal(20, 30, 100) # 随机在 20 到 30 之间生成 100 个数值
# 绘制散点图
plt.scatter(x, y, s=size, c=colors)
plt.show()
2.3 饼状图样式
饼状图通过 matplotlib.pyplot.pie()
绘出。我们也可以进一步设置它的颜色、标签、阴影等各类样式。下面就绘出一个示例。
# -*- coding: utf-8 -*
import matplotlib.pyplot as plt
label = 'Cat', 'Dog', 'Cattle', 'Sheep', 'Horse' # 各类别标签
color = 'r', 'g', 'r', 'g', 'y' # 各类别颜色
size = [1, 2, 3, 4, 5] # 各类别占比
explode = (0, 0, 0, 0, 0.2) # 各类别的偏移半径
# 绘制饼状图
plt.pie(size, colors=color, explode=explode, labels=label, shadow=True, autopct='%1.1f%%')
# 饼状图呈正圆
plt.axis('equal')
# 显示图
plt.show()
2.4 组合图
上面演示了三种常见图像的绘制。实际上,我们往往会遇到将几种类型的一样的图放在一张图内显示,也就是组合图的绘制。
其实很简单,你只需要将需要或者的组合图样式放在一起就好了,比如柱形图和折线图。
# -*- coding: utf-8 -*
import matplotlib.pyplot as plt
x = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
y_bar = [3, 4, 6, 8, 9, 10, 9, 11, 7, 8]
y_line = [2, 3, 5, 7, 8, 9, 8, 10, 6, 7]
plt.bar(x, y_bar)
plt.plot(x, y_line, '-o', color='y')
plt.show()
2.5 子图绘制
上面提到了组合图绘制,但有一些图是无法组合直接放在一起的,这时就需要子图了。子图,就是将几张独立的图放在一张大图中呈现。在一些需要对比的情形下,子图非常有效。
Matplotlib 中,绘制子图的方法为matplotlib.pyplot.subplot()
,我们通过该方法来控制各子图的显示顺序。其中:
subplot(行序号, 列序号, 图序号)
下面列举了三种常见子图的位置关系示意图。
接下来,我们绘制了一个由 4 个子图(2 行 x 2 列)组成的大图。
import numpy as np
import matplotlib.pyplot as plt
# 生成数据
x = np.linspace(-2*np.pi, 2*np.pi)
y1 = np.sin(x)
y2 = np.cos(x)
# 子图 1
plt.subplot(2, 2, 1)
plt.plot(x, y1, 'k')
# 子图 2
plt.subplot(2, 2, 2)
plt.plot(x, y2, 'r')
# 子图 3
plt.subplot(2, 2, 3)
plt.plot(x, y2, 'y')
# 子图 4
plt.subplot(2, 2, 4)
plt.plot(x, y2, 'g')
plt.show()
除了这类平行或垂直排列的子图,我们还可以通过 matplotlib.pyplot.subplot()
绘制出更复杂的样式。比如,大图套小图。
import numpy as np
import matplotlib.pyplot as plt
# 生成数据
x = np.linspace(-2 * np.pi, 2 * np.pi)
y1 = np.sin(x)
y2 = np.cos(x)
# 大图
plt.axes([.1, .1, .8, .8])
plt.plot(x, y1, 'k')
# 小图
plt.axes([.6, .6, .3, .3])
plt.plot(x, y2, 'r')
plt.show()
2.6 绘制图例
一般情况下,当绘制好图案后,还需要绘制图例。Matplotlib 中,图例可以通过 matplotlib.pyplot.legend()
方法绘制。我们又拿上面的正弦和余弦曲线举例。
# -*- coding: utf-8 -*
from matplotlib import pyplot as plt # 载入 pyplot 绘图模块
import numpy as np # 载入数值计算模块
# 生成数据
X = np.linspace(-2 * np.pi, 2 * np.pi, 1000)
y1 = np.sin(X)
y2 = np.cos(X)
# 使用 label= 添加标签
plt.plot(X, y1, color='r', linestyle='--', linewidth=2, label='sin 函数')
plt.plot(X, y2, color='b', linestyle='-', linewidth=2, label='cos 函数')
# 绘制图例
plt.legend(loc='upper left')
plt.show()
在这里,我们需要修改两个地方,也就是通过 label=
为每一条曲线添加标签。然后,增加一条 plt.legend(loc='upper left')
就可以了。其中,loc='upper left'
是指明图例的位置,例如这里是左上方。你还可以通过 down
和 right
组合实现位置的变换。
上方绘制出来的最终图像如下所示:
当然,这只是图例中的样式之一。你可以浏览官方文档 1237 页查看其他样式的绘制方法。
2.7 图像标注
当我们绘制一些较为复杂的图像时,阅读对象往往很难全面理解图像的含义。而此时,图像标注往往会起到画龙点睛的效果。图像标注,就是在画面上添加文字注释、指示箭头、图框等各类标注元素。
Matplotlib 中,文字标注的方法由 matplotlib.pyplot.text()
实现。最基本的样式为 matplotlib.pyplot.text(x, y, s)
,其中 x, y 用于标注位置定位,s 代表标注的字符串。除此之外,你还可以通过 fontsize=
, horizontalalignment=
等参数调整标注字体的大小,对齐样式等。
下面,我们举一个对柱形图进行文字标注的示例。
# -*- coding: utf-8 -*
from matplotlib import pyplot as plt # 载入绘图模块
x_bar = [10, 20, 30, 40, 50] #柱形图横坐标
y_bar = [0.5, 0.6, 0.7, 0.4, 0.6] #柱形图纵坐标
bars = plt.bar(x_bar, y_bar, color='blue', label=x_bar, width=2) # 绘制柱形图
for i, rect in enumerate(bars):
x_text = rect.get_x() # 获取柱形图横坐标
y_text = rect.get_height() + 0.01 # 获取柱子的高度并增加 0.01
plt.text(x_text, y_text, '%.1f' % y_bar[i]) # 标注文字
plt.show()
除了文字标注之外,还可以通过 matplotlib.pyplot.annotate()
方法向图像中添加箭头等样式标注。接下来,我们向上面的例子中增添一行增加箭头标记的代码。
# -*- coding: utf-8 -*
from matplotlib import pyplot as plt # 载入绘图模块
x_bar = [10, 20, 30, 40, 50] #柱形图横坐标
y_bar = [0.5, 0.6, 0.7, 0.4, 0.6] #柱形图纵坐标
bars = plt.bar(x_bar, y_bar, color='blue', label=x_bar, width=2) # 绘制柱形图
for i, rect in enumerate(bars):
x_text = rect.get_x() # 获取柱形图横坐标
y_text = rect.get_height() + 0.01 # 获取柱子的高度并增加 0.01
plt.text(x_text, y_text, '%.1f' % y_bar[i]) # 标注文字
# 增加箭头标注
plt.annotate('Max', xy=(32, 0.6), xytext=(38, 0.6), arrowprops=dict(facecolor='black', width=1, headwidth=7))
plt.show()
上面的示例中,xy=()
表示标注终点坐标,xytext=()
表示标注起点坐标。另外,arrowprops=()
用于设置箭头样式,facecolor=
设置颜色,width=
设置箭尾宽度,headwidth=
设置箭头宽度。
在箭头绘制的过程中,还有一个 arrowstyle=
用于改变箭头的样式。下图展示了常见的箭头样式。
另外,connectionstyle=
的参数可以用于更改箭头连接的样式。下图展示了常见的箭头连接样式。
2.8 动态图绘制
动态图是绘图中不可缺少的一部分,虽然演示环境要求高且使用频率低,但在一些特定的场景下,动图传达的信息量远大于静态图片。
举个例子来讲,数值计算中,我们往往会使用到梯度下降法。如果用语言和公式描述梯度下降的过程,会非常枯燥。要是通过绘制一张演示梯度下降过程的动图,就算第一次接触该方法,也会很快的理解。
Matplotlib 很早开始就支持动态图了,下面就通过简单的小例子来演示一下动态图的绘制。
动态图主要是通过 animation 模块实现。具体就是 matplotlib.animation.FuncAnimation(fig, func)
。其中,fig 代表所绘制的图像。而 func 可以看作是更新函数,它刷新每一帧的值。
# -*- coding: utf-8 -*
# 载入模块
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# 生成数据并建立绘制类型的图像
fig, ax = plt.subplots()
x = np.arange(0, 2 * np.pi, 0.01)
line, = plt.plot(x, np.sin(x))
# 更新函数
def update(i):
line.set_ydata(np.sin(x + i / 10.0))
return line,
# 绘制动图
animation = animation.FuncAnimation(fig, update)
# 显示图
plt.show()
三、实验总结
本次实验对 2D 绘图中,常见方法包含的参数进行的熟悉,方便绘制出样式更为复杂的图像。当然,这些内容依旧较为初级,可能无法完全满足实际需要。而真正的绘图过程中,我们需要从实际需求出发,善于组合 Matplotlib 中提供的绘图方法,从而画出更加漂亮的图像。
四、课后习题
1.亲自动手,尝试通过 Matplotlib 绘制出下图这副图像。
上图参考代码:
$ wget http://labfile.oss.aliyuncs.com/courses/892/sin_cos_functions.py