第二章 学习指南
本页包含更多使用Matplotlib的深入指南。它分为初级、中级和高级部分,以及涵盖特定主题的部分。
有关较短的示例,请参阅我们的示例页面。您还可以在我们的用户指南中找到外部资源和FAQ。
2.1介绍
这些教程涵盖了使用Matplotlib创建可视化的基础知识,以及有效使用该包的一些最佳实践。
2.1.1使用指南
本教程涵盖了一些基本的使用模式和最佳实践,以帮助您开始使用Matplotlib。
import matplotlib.pyplot as plt
import numpy as np
一个简单的例子
Matplotlib将数据绘制到图形(figure)(即窗口、Jupyter小部件等)上,每个图形(figure)都可以包含一个或多个绘图区域(axes)(即,可以用x-y坐标指定点的区域,或者用极坐标中的theta-r,或者用3D图中的x-y-z等指定点)。创建具有绘图区域的图形,最简单方法是使用pyplot.subplots。我们可以使用Axes.plot在绘图区域上绘制一些数据:
fig, ax = plt.subplots() # 创建包含单个绘图区域的图形。
ax.plot([1, 2, 3, 4], [1, 4, 2, 3]) # 在绘图区域上画一些数据。plot是画线的函数
输出:
[<matplotlib.lines.Line2D object at 0x7f5eff0589d0>]
许多其他绘图库或语言不需要显式地创建绘图区域。例如,在MATLAB中,我们可以这样做得到想要的图形:
plot([1, 2, 3, 4], [1, 4, 2, 3]) % MATLAB plot.
实际上,您可以在Matplotlib中做同样的事情:对于每个Axes绘图方法,在matplotlib.pyplot中都有一个相应的函数,它在“当前”绘图区域执行该绘图,如果绘图区域(Axes)及其父图形(figure)还不存在,则创建它们。因此,前面的例子可以写得更简短:
plt.plot([1, 2, 3, 4], [1, 4, 2, 3]) # Matplotlib绘制图表
输出:
[<matplotlib.lines.Line2D object at 0x7f5eff2dacd0>]
图的组成部分
现在,让我们更深入地看看Matplotlib图的组件。
Figure
Figure即整个图形,可以理解为整张画纸。Axes相当于画纸上的某个区域。
Figure会跟踪所有的子坐标轴、少数“特殊”的设计(标题、图例等)和画布。(不要太担心画布,这是至关重要的,因为它是真正为你绘制图形的对象,但作为用户,它或多或少对你是隐形的)。Figure可以包含任意数量的绘图区域,但通常至少有一个。
创建新图形最简单的方法是使用pyplot:
fig = plt.figure() # 一个空白的图形,上面没有绘图区域
fig, ax = plt.subplots() # 图形上,有一块绘图区域
fig, axs = plt.subplots(2, 2) # 图形上有2*2块绘图区域
与整个图形一起创建绘图区域很方便,但你也可以稍后添加绘图区域,允许更复杂的绘图区域布局。
Axes
这就是你认为的’a plot’,它是图像的数据空间区域。给定的figure可以包含多个Axes,但给定的Axes对象只能在一个figure中。Axes包含两个(在3D情况下是三个)Axis(坐标轴对象),它们负责数据限制。
注意Axes 和 Axis之间的区别
数据限制也可以通过axes.Axes.set_xlim()
和axes.Axes.set_ylim()
方法进行控制。每个Axes都有一个标题(通过set_title()设置)、一个x标签(通过set_xlabel()设置)和一个y标签(通过set_ylabel()设置)。
Axes类及其成员函数是使用OO接口的主要入口点。
Axis
这些是类似于数轴的对象。它们负责设置图形限制和生成刻度(轴上的标记)和标记标签(标记刻度的字符串)。标记的位置由Locator对象确定,而标记标签字符串由Formatter格式化。正确的Locator和Formatter的组合可以很好地控制标记位置和标签。
Artist
基本上,您在figure上看到的一切都是一个艺术家(甚至是figure、Axes和Axis对象)。
Text objects, Line2D objects, collections objects, Patch objects ...
这包括文本对象,Line2D对象,集合对象,补丁对象…(你懂的)。
当人物被渲染时,所有的艺术家都被吸引到画布上。大多数艺术家都被绑定在一个绘画区域中;这样的艺术家不能被多个绘画区域共享,或从一个绘画区域移动到另一个绘画区域。
绘图函数的输入类型
所有的绘图函数的输入数据都希望是 numpy.array或numpy.ma.masked_array。
其他类似的数组,如pandas数据对象和numpy.matrix(矩阵),可能会,也可能不会按预期工作。在绘图之前,最好将它们转换为 numpy.array对象。
例如:转换一个pandas.DataFrame:
a = pandas.DataFrame(np.random.rand(4, 5), columns = list('abcde'))
a_asarray = a.values
转换一个 numpy.matrix:
b = np.matrix([[1, 2], [3, 4]])
b_asarray = np.asarray(b) # 将输入转为数组格式:ndarray类型
面向对象的接口和pyplot接口
如上所述,有两种使用Matplotlib的方法:
- 显式地创建图形(figure)和绘图区域(axes),并在它们上调用方法(“面向对象(OO)风格”)。
- 依赖pyplot自动创建和管理图形(figure)和绘图区域(axes),并使用pyplot函数进行绘图。
所以我们可以这样绘图(oo风格):
x = np.linspace(0, 2, 100)
# 注意,即使在oo风格中,我们也使用.pyplot来创建figure
fig, ax = plt.subplots() # 创建图形和绘图区域
ax.plot(x, x, label='linear') # 在绘图区域上画一些数据
ax.plot(x, x**2, label='quadratic') # 在绘图区域上画更多的数据
ax.plot(x, x**3, label='cubic') # ... 绘制更多
ax.set_xlabel('x label') # 在绘图区域添加x轴标签
ax.set_ylabel('y label') # 在绘图区域添加y轴标签
ax.set_title("Simple Plot") # 在绘图区域添加标题
ax.legend() # 添加图例
输出:
<matplotlib.legend.Legend object at 0x7f5eff043970>
或者 (pyplot-style):
x = np.linspace(0, 2, 100)
plt.plot(x, x, label='linear') # 在隐藏的绘图区域画一些数据
plt.plot(x, x**2, label='quadratic') # 绘制更多
plt.plot(x, x**3, label='cubic')
plt.xlabel('x label')
plt.ylabel('y label')
plt.title("Simple Plot")
plt.legend()
输出:
<matplotlib.legend.Legend object at 0x7f5efdc033a0>
此外,还有第三种方法,在GUI应用程序中嵌入Matplotlib来创建图形,这种方法完全放弃了pyplot。我们不在这里讨论;有关更多信息,请参见图库中相应的部分(用户界面)。
Matplotlib的文档和示例同时使用了OO和pyplot方法(这两种方法同样强大),您可以随意使用任何一种方法(不过,最好选择其中一种并坚持使用,而不是混合使用)。一般来说,我们建议将pyplot限制为交互式绘图(例如,在Jupyter笔记本中),而对于非交互式绘图(在打算作为大型项目一部分重用的函数和脚本中)更倾向于oo风格。
注意:在较早的例子中,你可能会发现一些例子使用了所谓的pylab接口:from pylab import *。因为这个命令可以从pyplot和numpy导入所有内容,所以这样做更像matlab的风格。这种方法现在被大家强烈反对,这里提到它只是因为你可能还会偶尔遇到它。
通常情况下,人们会发现自己反复绘制相同的图,但使用不同的数据集,这导致需要编写专门的函数来绘制图。推荐的函数写法是这样的:
def my_plotter(ax, data1, data2, param_dict):
"""
绘图帮助
参数
----------
ax : Axes
绘图区域
data1 : array
数据x
data2 : array
数据y
param_dict :dict
要传递给ax.plot的关键字参数的字典
返回
-------
输出 : list
增加的绘图列表
"""
out = ax.plot(data1, data2, **param_dict)
return out
你可以这样用:
data1, data2, data3, data4 = np.random.randn(4, 100)
fig, ax = plt.subplots(1, 1)
my_plotter(ax, data1, data2, {'marker': 'x'})
输出:
[<matplotlib.lines.Line2D object at 0x7f5efef5a520>]
或者如果你想有两个副图:
fig, (ax1, ax2) = plt.subplots(1, 2) # 1行2列
my_plotter(ax1, data1, data2, {'marker': 'x'})
my_plotter(ax2, data3, data4, {'marker': 'o'})
输出:
[<matplotlib.lines.Line2D object at 0x7f5eff2bf1f0>]
对于这些简单的例子来说,这种风格似乎有些过头,但是一旦图表变得稍微复杂一些,它就会得到回报。