subplot和subplots的区别

看到subplots会联想到subplot,两者的区别是什么?查一下subplot的英文含义vocabulary subplot,subplot常用作故事里的子情节。

  • stackoverflow回答,举了两者的例子说明。
  • 看subplots的例子what-is-a-subplots-in-matplotlib可知,subplots相当于直接创建一组子图。一次调用可以得到n个子图,然后在子图上绘制即可。
  • 而看subplot的csdn例子可知,你需要调用多次subplot来绘制子图,有n个待生成的子图就要调用n次subplot函数。

subplots与ax.imshow例子

所以,subplots可以直接创建画板的格局,如下例子,subplots创建了一个2行1列排版的画布,然后用ax.imshow在排版上绘制图像。
而ax.imshow的行为是能在区域ax绘制图像,其可以接受list或者numpy.ndarray类型输入的像素点,并绘制图片。

下述代码首先定义了红、绿、蓝三种像素点,再做了三种排列row1、row2、row3。然后分别赋值到list和numpy.ndarray。并用imshow展示像素图。

import matplotlib.pyplot as plt
import numpy as np

# 使用ax.imshow绘制两幅图
fig, axs = plt.subplots(2, 1)

red = [255,0,0]
green = [0,255,0]
yellow = [0,0,255]

row1 = [red,green,yellow]
row2 = [green,yellow,red]
row3 = [yellow,red,green]

#plot 1: 用list绘制一副彩色图片, 维度是[M,N,3]
axs[0].imshow([row1, row2, row3])

#plot 2: 用numpy.ndarray绘制一副彩色图片,维度是[M,N,3]
image2 = np.ndarray((3,3,3))
image2[:] = [row2, row3, row1]
print("image2 is instance of numpy array: ", isinstance(image2, np.ndarray))  # True
axs[1].imshow(image2)

plt.show()

输出如下,是两张图画,各有3*3=9个像素点,每个像素点都是彩色,所以维度[H, W, 3]=[3, 3, 3]。

这里的像素点很大,但确实符合3*3的格式。如果像素点数量变多,像素点应该会变小,图像会更像一幅图。

这里没有删除坐标轴,如果不想看到坐标轴和数字,可以代码设置axs[0].axis("off")

axs[0].axis("off")
axs[0].imshow([row1, row2, row3])

可以看到,第一幅子图的坐标轴消除了,第二幅子图的坐标轴没消除。

如果在使用subplots的情况下,想取消所有图的坐标轴,根据turn-off-axes-in-subplots ,不应该调用plot.axis("off"),而仍然应该对每个ax调用axis("off")

subplots参数探究

figsize

subplots的figsize参数主要用于设置整个画幅的大小,其中(4,4)代表400px*400px。其它单位使用参考官方文档figure_size_units

下面看下两种排版下的画幅大小。

import matplotlib.pyplot as plt

def show_blank(nrow, ncol):
    fig, axs = plt.subplots(nrow, ncol, sharex=True, sharey=True, figsize=(4, 4))
    for ax in axs:
        ax.text(0.5, 0.5, "xxxx")
    plt.show()

show_blank(2,1)
show_blank(10,1)

运行分别得到:

以及

显而易见,排版虽然是21和101(纵坐标轴因画幅太小而挤压),但整个窗口大小在两次运行中是一样的。所figsize参数指定了画幅的整体大小

sharex sharey

这两个参数指定了是否共享纵轴和横轴,尽管sharex和sharey接受字符串类型的参数,本文之探究bool类型的运行情况。
下面代码让窗口两次显示2*2排版的画幅,并对比share参数在两种bool输入下的表现。

import matplotlib.pyplot as plt

def show_blank(nrow, ncol, sharex, sharey):
    fig, axs = plt.subplots(nrow, ncol, sharex=sharex, sharey=sharey, figsize=(8, 8))
    for ax_row in axs:
        for ax in ax_row:
            ax.text(0.5, 0.5, "test text")
    plt.show()

show_blank(2, 2, True, True)
show_blank(2, 2, False, False)

其图片输出分别如下:

可见:

  • sharex会让同一列内的图片都共享横坐标轴
  • sharey会让同一行内的图片都共享纵坐标轴

具体可以自己调试一下。

imshow参数与返回值

需要探究的参数有cmap、vmin、vmax。根据官方文档。如果要显示灰色画幅,设置参数为cmap='gray', vmin=0, vmax=255

  • cmap代表图画是灰色还是彩色。如果是RGB图画,可以忽略该参数。
  • 在没有设置norm的情况下,vmin和vmax代表色域的最小值和最大值。

个人觉得只需记住灰色、彩色图的参数即可,灰色图就设置一下cmap为gray,彩色图就直接输入[H,W,3]的数据即可。对于一些奇特的用法,不必过多纠缠。

FuncAnimation

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


nrow, ncol = 2, 2
fig, axs = plt.subplots(nrow, ncol, sharex=True, sharey=True, figsize=(8, 8))
texts = ["aaaa", "bbbb", "cccc", "dddd"]

def animate_diff(i):
    # 刷新本帧
    for row in range(nrow):
        for col in range(ncol):
            axs[row, col].clear()
            # 像素属于第row * ncol + col个,偏移量为i,对len(texts)取余
            idx = (i + row * ncol + col) % len(texts)
            axs[row, col].text(0.5, 0.5, f"({row},{col}) {texts[idx]}")


# 设置动画
ani = FuncAnimation(fig, animate_diff, interval=1500, blit=False, repeat=True,
                    frames=100)

plt.show()

动态图如下,从左上到右下的四个子图,坐标分别是(0,0), (0,1), (1,0), (1,1)。各个参数的作用如下:

  1. fig参数代表动画绘制在fig对象上。
  2. 帧更新函数为animate_diff,每一帧会调用一次,在函数里可以利用axs对象更新画幅。animate_diff的参数i代表当前是第几帧
  3. repeat参数代表是否重复播放。
  4. interval=1500代表帧间隔为1500ms,frames=100代表一轮播放有100帧。

运行以后,可以看到画幅重复以下情形
5. 第一个frame,四个子图分别显示a b c d
6. 第二个frame,四个子图分别显示b c d a
7. 第三个frame,四个子图分别显示c d a b
8. 第四个frame,四个子图分别显示d a b c

留意到,并不需要为animate_diff设置返回值,也可以正常生成动画图。但有的例子中会不止更新画幅,而且设置返回值,这里留个疑问。

Logo

NVIDIA官方入驻,分享最新的官方资源以及活动/会议信息,精选收录AI相关技术内容,欢迎大家加入社区并参与讨论。

更多推荐