目录
0. 前言
1. 创建Figure的两种基本方法
1.1 第1种方法
1.2 第2种方法
2. Figure的解剖图及各种基本概念
2.1 Figure
2.2 Axes
2.3 Axis
2.4 Artist
3. 绘图函数的输入
4. 面向对象接口与pyplot接口
5. 绘图复用实用函数例
0. 前言
本文介绍Python Matplotlib库的入门求生级使用方法。
为了方便以下举例说明,我们先导入需要的几个库。以下代码在Jupyter Notebook中运行。
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
1. 创建Figure的两种基本方法
1.1 第1种方法
注意,Figure在Matplotlib中是一个专有名词(后面会有解释),Matplotlib把你的数据以图的形式绘制在Figure(比如说,windows, Jupyter widgets, etc.)中。创建一个Figure的基本方式之一就是使用pyplot.subplots.
如下所示,我们用pyplot.subplots创建了一个Figure,其中包含一个axes(同样,这是一个Matplotlib专有名词,后面再进行解释),然后再利用axes.plot画图。
fig, ax = plt.subplots() # Create a figure containing a single axes.
x = np.arange(100)
Fs = 100 # 100Hz sampling rate
Fsin = 2 # 2Hz
y = np.sin(2*np.pi*Fsin*(1/Fs)*x)
ax.plot(x, y) # Plot some data on the axes.
以上代码画了一个正弦波的波形。
1.2 第2种方法
许多其它的绘图工具库或者语言并不要求你必须显式地(explicity)先创建一个Figure以及axes,比如说在Matlab中,你直接如下所示一样直接调用plot()函数就一步到位地得到所想要的图,如果现成的axes的话,matlab会为你创建一个.
plot([1, 2, 3, 4], [1, 4, 2, 3]) % MATLAB plot.
事实上,你也可以以这种方式使用Matplotlib。对于每一个axes的绘图方法,matplotlib.pyplot模块中都有一个对应的函数执行在当前axes上画一个图的功能,如果还没有已经创建好的axes的话,就先为你创建一个Figure和axes,正如在Matlab中一样。因此以上例子可以更简洁地写为:
plt.plot(x, y) # Call plt.plot() directly
同样会得到以上相同的图。
2. Figure的解剖图及各种基本概念
上图出自Ref1。图中给出了matplotlib中Figure(没有想好这个到底应该怎么翻译。本来想是不是可以译成画布,但是画布对应英文中的Canvas。而Figure的说明中明确指出了Figure包含了Canvas,如果说Canvas是指画布的话,那Figure其实是指整个一幅画。还是不勉强吧,直接用英语单词好了)
2.1 Figure
The whole figure.整幅画或整个图。Figure保持其中所有的child axes的信息,以及一些特殊的artists (titles, figure legends, etc)(这里artist又是很难翻译的一个词,指的是标题、图例等图的说明性信息对象),以及画布(canvas)。
可以说Figure是幕后的大Boss管理着所有的信息,是它真正执行为你绘制图画的动作。但是作为用户,它反而是不太显眼的,对你来说多少有点隐形的样子。一个Figure中可以包含任意多个axes,通常至少包含一个。
以下是创建Figure的几种方式,其中前两种在上面的例子已经介绍,也是常用的。
最后一种是创建一个空的Figure,可以在之后给它添加axes。这种做法不常见,属于高阶用法,方便高阶用户进行更加灵活的axes布局。
fig, ax = plt.subplots() # a figure with a single Axes
fig, axs = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes
fig = plt.figure() # an empty figure with no Axes
2.2 Axes
Axes原本是axis(坐标)的复数,所以可以翻译成坐标系?就这么理解着吧。一个给定的Figure可以包含多个axes,但是一个axes对象只能存在于一个Figure中。(按坐标系理解的话,故名思意)一个Axes包含多个axis,比如说在2D(2维)的图中有两个坐标轴,在3D(3维)图中有三个坐标轴。
在一个axes中可以通过以下一些方法来设置图的一些属性:
set_xlim(),set_ylim():分别用于设置x轴、y轴的表示范围
set_title():设置图的标题
set_xlabel(),set_ylabel(): 分别用于设置x轴和y轴的标签
Axes类和它的成员函数是matplolib的面向对象的界面的主要入口(关于面向对象接口与pyplot接口参见后面的说明)
2.3 Axis
这个就是我们常说的坐标轴。不再赘述。事实上,越解释越糊涂。。。有兴趣的小伙伴可以看看matplotlib文档的原始说明,反正我是越看越晕。。。还不如直接看代码例直到怎么使用就可以了。
2.4 Artist
Basically, everything you can see on the figure is an artist (even the Figure, Axes, and Axis objects). This includes Text objects, Line2D objects, collections objects, Patch objects ... (you get the idea). When the figure is rendered, all of the artists are drawn to the canvas. Most Artists are tied to an Axes; such an Artist cannot be shared by multiple Axes, or moved from one to another.
晕菜。。。同上,还不如直接看代码例直到怎么使用就可以了^-^
3. 绘图函数的输入
所有的绘图函数都接受numpy.array or numpy.ma.masked_array作为输入。
像pandas中的数据对象以及numpy.matrix等类似于数组('array-like')的对象如果直接用于绘图函数的输入的话有可能会产生意想不到的结果。所以最好把它们先转换成numpy.array对象再传递给绘图函数。
# For example, to convert a pandas.DataFrame
a = pd.DataFrame(np.random.rand(4, 5), columns = list('abcde'))
a_asarray = a.values
# and to convert a numpy.matrix
b = np.matrix([[1, 2], [3, 4]])
b_asarray = np.asarray(b)
4. 面向对象接口与pyplot接口
如上所述,有两种基本的使用Matplotlib的方法。
(1) 显式地创建Figure和axes,然后调用方法作用于它们,这个称之为面向对象风格。
(2) 直接调用pyplot进行绘图,这个姑且称之为快捷风格吧
面向对象风格的使用方法示例:
x = np.linspace(0, 2, 100)
# Note that even in the OO-style, we use `.pyplot.figure` to create the figure.
fig, ax = plt.subplots() # Create a figure and an axes.
ax.plot(x, x, label='linear') # Plot some data on the axes.
ax.plot(x, x**2, label='quadratic') # Plot more data on the axes...
ax.plot(x, x**3, label='cubic') # ... and some more.
ax.set_xlabel('x label') # Add an x-label to the axes.
ax.set_ylabel('y label') # Add a y-label to the axes.
ax.set_title("Simple Plot") # Add a title to the axes.
ax.legend() # Add a legend.
快捷(pyplot)风格的使用方法示例:
x = np.linspace(0, 2, 100)
plt.plot(x, x, label='linear') # Plot some data on the (implicit) axes.
plt.plot(x, x**2, label='quadratic') # etc.
plt.plot(x, x**3, label='cubic')
plt.xlabel('x label')
plt.ylabel('y label')
plt.title("Simple Plot")
plt.legend()
以上代码中同时给出了两种风格中的label、title、legend等设置的方法或函数使用例。
以上两段代码示例产生同样的绘图效果:
此外,还有第三种方法,用于在GUI应用中的嵌入式Matplotlib。这个属于进阶用法,在本文就不做介绍了。
面向对象风格和pyplot风格功能相同同样好用,你可以选择使用任何一种风格。但是最好选定其中一种使用,不要昏庸。一般来说,建议仅在交互式绘图(比如说在Jupyter notebook)中使用pyplot风格,而在面向非交互式绘图中则推荐使用面向对象风格。
注意,在一些比较老的代码例中,你还可以看到使用pylab接口。但是现在不建议这样用了(This approach is strongly discouraged nowadays and deprecated)。这里提一嘴只是因为偶尔你还可能看到它,但是,在新的代码不要用就好了。
5. 绘图复用实用函数例
通常我们会发现需要重复绘制很多相类似的图,只是采用不同的数据而已。为了提高效率减少错误,可以考虑将一些绘图处理封装成一个函数,以便于重复使用,避免过多的冗余代码。以下是一个这样的模板例子:
def my_plotter(ax, data1, data2, param_dict):
"""
A helper function to make a graph
Parameters
----------
ax : Axes
The axes to draw to
data1 : array
The x data
data2 : array
The y data
param_dict : dict
Dictionary of kwargs to pass to ax.plot
Returns
-------
out : list
list of artists added
"""
out = ax.plot(data1, data2, **param_dict)
return out
然后你可以以如下方式使用:
x = np.linspace(0, 5, 20)
fig, ax = plt.subplots()
x2 = x**2
x3 = x**3
my_plotter(ax, x, x2, {'marker': 'o'})
my_plotter(ax, x, x3, {'marker': 'd'})
或者,如果你需要多个子图的话,
x = np.linspace(0, 5, 20)
x2 = x**2
x3 = x**3
fig, (ax1, ax2) = plt.subplots(1, 2)
my_plotter(ax1, x, x2, {'marker': 'x'})
my_plotter(ax2, x, x3, {'marker': 'o'})
fig, ax = plt.subplots(1, 2)
my_plotter(ax[0], x, x2, {'marker': 'x'})
my_plotter(ax[1], x, x3, {'marker': 'o'})
注意,如以上代码例所示,当创建了多个子图时,有两种引用axes的方式。第一种方式中,创建时直接将两个axes(每个子图对应一个axes)赋给ax1和ax2。第一种方式中,创建时直接将两个axes赋给一个axes数组ax,然后以ax[0]和ax[1]的格式进行引用。
Ref1: Usage Guide — Matplotlib 3.4.3 documentation
关于Matplotlib的进阶使用,参见:
Matplotlib进阶:利用rcParams控制图形属性https://blog.csdn.net/chenxy_bwave/article/details/121406448