欢迎来到专栏《Python进阶》。在这个专栏中,我们会讲述Python的各种进阶操作,包括Python对文件、数据的处理,Python各种好用的库如NumPy、Scipy、Matplotlib、Pandas的使用等等。我们的初心就是带大家更好的掌握Python这门语言,让它能为我所用。
今天是《Python进阶》专栏的第五期,在本期中,我们将主要介绍如何使用Matplotlib这个第三方库进行数据可视化。
作者&编辑 | 汤兴旺
“美丽的可视化可反映出所描述数据的品质,显式地揭示出源数据中内在和隐式的属性和关系,读者了解了这些属性和关系之后,可以因此而获取新的知识、洞察力和乐趣。”
以上是书籍《数据可视化之美》对可视化的解读。说的很有道理,相信大家听说过“一图胜千言”这句话,当看到一堆数据时,若你对数字不够敏感,肯定会费劲半天找不到规律,但若用一张图来表达时,相信你一定会一目了然。下面我就大家使用Matplotlib对数据进行美丽的可视化。
1 Matplotlib 的基本操作
在Matplotlib中有三个基本概念,分别是Figure、axes和axis。
下面我来详细解释下这三个基本概念。在Matplotlib中,figure你可以理解成一个画布或者一个窗口,axes是指画布上的一个区域,你画的图就在这个区域上。你可以把figure看成一张白纸,在纸上的任何区域画图,确定画图区域并确定作图的一些方式的东西的就是axes,即坐标对象(坐标系)。
由于在一张白纸上可以有几个区域进行画图,另外画图区域必须存在于白纸上才有意义。因此在figure上可有多个axes,axes必在figure上,要画图必有axes。
另外axis就是我们平时常见的坐标轴,如x轴、y轴等。
对于上面的概念我们可以用下图进行直观理解。
通过上面的讲解,我们知道在Matplotlib中的图像都位于figure画布中,因此可以使用plt.figure创建一个新画布。如果要在一个图表中绘制多个子图,可使用subplot。
话不多说,我们直接看下面代码:
import matplotlib.pyplot as plt
ax4 = fig.add_subplot(2, 2, 4)
首先,创建了一个figure,然后在这个figure上画了四个区域,即四个子图,分别是直方图、三点图、折线图,还有一个是只有坐标轴的图。
如果我想要画多个figure应该怎么办呢?实际上如果要同时绘制多个图表,可以给figure()传递一个整数参数指定figure对象的序号。如下例所示:
import matplotlib.pyplot as plt
import numpy as np
plt.figure(1) # 创建图表1
plt.figure(2) # 创建图表2
ax1 = plt.subplot(211) # 在图表2中创建子图1
ax2 = plt.subplot(212) # 在图表2中创建子图2
x = np.linspace(0, 3, 100)
for i in range(5):
plt.figure(1) # 选择图表1
plt.plot(x, np.exp(i * x / 3))
plt.sca(ax1) # 选择图表2的子图1
plt.plot(x, np.sin(i * x))
plt.sca(ax2) # 选择图表2的子图2
plt.plot(x, np.cos(i * x))
plt.show()
执行完上面代码后,如下图。
2 Matplotlib的进阶操作
在1中的两个示例中,我们会发现手动创建figure,都使用了plt.figure()。如果没有plt.figure()可以吗?请看下面的示例:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-np.pi, 5*np.pi, num = 100)
y = np.sin(x)
plt.plot(x,y)
plt.show()
我们会发现这段代码中,没有plt.figure()也画出了图,WHY?难道前面误导了大家?我在前面说过,若没有figure就没有axes!
当然这个锅我不背,实际上这里plt.plot()是通过plt.gca()获得当前axes对象的ax,如果没有会自动创建一个,可以理解为就是figure。然后再调用ax.plot方法实现真正的绘图。
Matplotlib实际上是一套面向对象的绘图库,它所绘制的图表中每个图表元素,如线条 Line2D、文字Text、刻度等在内存中都有一个对象与之对应。为将面向对象的绘图库包装成只使用函数的调用接口,pyplot模块内部保存了当前图表以及当前子图等信息。当前的图表和子图可以使用plt.gcf()和plt.gca()获得,分别表示"Get Current Figure"和"Get Current Axes"。在pyplot模块中,许多函数都是对当前的figure或axes对象进行处理,比如说:
plt.plot()实际上会通过plt.gca()获得当前的axes对象ax,然后再调用ax.plot()方法实现真正绘图。
2.1 对图进行装扮
上面3个示例中均没有展示图例、标注等,下面我们通过下面的示例来分享如何对一个图进行装扮。
import matplotlib.pyplot as plt
import numpy as np
fig, ax1 = plt.subplots(figsize=(8, 4))
r = np.linspace(0, 10, 100)
a = 4 * np.pi * r ** 2 # area
v = (4 * np.pi / 3) * r ** 3 # volume
ax1.set_title("surface area and volume of a sphere", fontsize=16)
ax1.set_xlabel("radius [m]", fontsize=16)
ax1.plot(r, a, lw=2, color="blue")
ax1.set_ylabel(r"surface area ($m^2$)", fontsize=16, color="blue")
for label in ax1.get_yticklabels():
label.set_color("blue")
ax2 = ax1.twinx()
ax2.plot(r, v, lw=2, color="red")
ax2.set_ylabel(r"volume ($m^3$)", fontsize=16, color="red")
for label in ax2.get_yticklabels():
label.set_color("red")
fig.tight_layout()
plt.show()
在上面的示例中我们通过set.title()设置了图的标题,通过set_xlabel和set_ylabel设置了y轴的标签,另外也通过get_yticklabels()和get_xticklabels()设置了坐标轴上刻度的不同的属性。
2.2、对图的某个细节进行放大
平时我们在处理图的时候,有时候需要对图的局部细节进行查看,这时候就需要对细节进行放大,对于这个问题该怎么解决呢?请看下面的案例:
import matplotlib.pyplot as plt
如果我想要对上图的横纵标在4附近的局部峰值进行放大查看,即下图圈红部分进行放大查看,应该如何操作呢?
代码如下:
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
fig = plt.figure(figsize=(8, 4))
def f(x):
return 1 / (1 + x ** 2) + 0.1 / (1 + ((3 - x) / 0.1) ** 2)
def plot_and_format_axes(ax, x, f, fontsize):
ax.plot(x, f(x), linewidth=2)
ax.xaxis.set_major_locator(mpl.ticker.MaxNLocator(5))
ax.yaxis.set_major_locator(mpl.ticker.MaxNLocator(4))
ax.set_xlabel(r"$x$", fontsize=fontsize)
ax.set_ylabel(r"$f(x)$", fontsize=fontsize)
ax = fig.add_axes([0.1, 0.15, 0.8, 0.8], facecolor="#f5f5f5")
x = np.linspace(-4, 14, 1000)
plot_and_format_axes(ax, x, f, 18)
x0, x1 = 2.5, 3.5
ax = fig.add_axes([0.5, 0.5, 0.38, 0.42], facecolor='none')
x = np.linspace(x0, x1, 1000)
plot_and_format_axes(ax, x, f, 14)
plt.show()
代码区红色部分即实现放大部分的代码。实际是添加了另外一个axes,只不过这个axes包含在主图的axes中。
总结
本期我们介绍了Matplotlib中的一些应用,希望您能借助这个工具画出精美的图表。
下期预告:Python库Pandas的高级应用
转载文章请后台联系
侵权必究