刚好最近准备整理一下matplotlib的一些心得,这里先码一部分。
现在你这里建立了一个大的主图Figure对象,下面包含一个2x2的4张子图Axes对象。如果直接使用plt方法,由于它只会作用在活动的子图上,所以只会影响到整个子图序列的最后一张图上。
这里,解决的方案至少有两个:第一种,就是换一个思路,通过指定子图的方式,调用子图的绘图方法来绘制;第二种,就是更换活动子图的焦点,把焦点切换到别的子图上然后用plt方法绘制。
第一种:
一般创建子图的时候,我们会用fig, ax = plt.subplots(2,2)这样的句法。这里其实是调用plt函数下的subplots命令创建了一张大图,以及大图下的2x2共4张小图的命令。所以这个命令其实做了两件事,同时生成了一个元组,包含fig这个“大图”对象,以及ax这个2x2子图对象。
当需要设置某个子图对象的时候,就可以用ax[x][y]这样的格式来指定具体是哪个子图。因为我们创建子图的时候用的是 (2,2)这样的格式,所以子图组其实是一个2x2的二维结构,于是指定子图的时候我们就要用[x][y]这样的调用二维数组的方式。
如果在一开始用plt.subplots(4)这样的语法,那么子图会默认排成一列。这个时候,用ax[x]这种一维数组的调用方式就可以了。
第二种:
另一方面,我们也可以用plt.subplot()命令来指定到底是哪一个子图subplot。注意前面是创建多个子图,用的subplots,这里是指定到某个具体的子图,用的是subplot。具体的用法是plt.subplot(行列索引),比如plt.subplot(224),就是说我现在选中的是这个2x2子图的第二行、第二列、索引号为4的子图。三个连续的整数缺一不可。
不过,当子图横向、纵向数量大于10的时候,这个方法就不能用了 。这个时候还是需要ax_index = plt.subplot(x, y, index)这种写法,在大图的指定位置选中(如果该位置没有子图,则创建一个新的子图),然后再进行绘制。
第一种方法,可以直接ax[0][0].plot进行绘制;而第二种,需要先plt.subplot(x,y,index)选中子图,然后plt.plot进行绘制,就是说需要分两步走。我个人比较喜欢第一种,因为可以直接选中并绘制图形;但第二种subplot方法里面可以传递别的参数,比如sharex=ax1可以用来指定和ax1子图对象共享x轴,或者projection='polar' 来指定该子图为极坐标系。
在了解基本的指定焦点的语法之后,我们就可以扩展一下和别的语法结合起来使用了。比如遍历多个子图:
假设有一个数据集(x, y1, y2, y3, y4),现在想画四张子图,数据集分别是(x, y1), (x, y2), (x, y3) 和 (x, y4)。如果不会遍历,那就只能手动一张张画。
plt.subplots(2,2) # 先创建一张2x2的包含4个子图的大图
x = data['x'] #假设我们通过这个方式拿到x对应的数据
for num, data in enumerate(y):
plt.subplot(221+i) #从 221 位置开始,遍历所有子图,假设子图是2x2
# plt.subplot(2, 2, 1+i) 当然这么写去选中子图也ok
plt.plot(x, data) # 前面已经选中子图了,这里传入数据就行
plt.title(title_list[i]) #如果你有标题列表,那么这样传入对应位置的标题,也可以实现自动加标题
当然,这个例子里面用两重循环:for x in rows, for y in columns来遍历也可以。就是索引位置要用 x,y 的组合来表达了。
通过这个例子可以举一反三,比如因为某些原因,第一行的图只能是柱状图,第二行的图只能是散点图的话。我们也可以通过循环来控制第一行的所有列,在绘制的时候都是创建一个柱状图;而第二行的时候,则都是创建散点图
fig, ax = plt.subplots(2,3) # 先创建一张 2x3 的包含 6 个子图的大图
for x,p in zip(range(ax.shape[0]), [plt.bar, plt.scatter]): # 规定第一行为柱状图,第二行为散点图
# 注意 plt.bar 没有括号的情况下,是一个函数对象;所以这是一个由不同函数对象组成的列表
for y in range(ax.shape[1]):
seq = x*ax.shape[1] + y +1
plt.subplot(ax.shape[0], ax.shape[1], seq)
p([1,2,3], [4,7,10]) # 这里 p 随着循环次数的不同,可以是 plt.bar 也可以是 plt.scatter
plt.show()
当然了,生产环境下肯定不建议这么循环。因为这些绘图函数接收的参数格式可能不一样。这里主要还是掌握怎么选中子图。
我不太熟悉别的编程语言,以py自学为例,我始终觉得自学和有人带着学,这两者的学习方法应该是不一样的。自学我更建议先浏览相关手册的全部内容,然后结合实际例子多点开花。如果按照学校里读书那样一个点一个点的学,最后知识很难串成线(因为没有“老师”帮你做这个),实际应用的时候就会抓瞎。
关于学习方法,可以参考下我的这个回答:如何系统地学习Python 中 matplotlib, numpy, scipy, pandas?www.zhihu.com