• 理解subplots, ax.imshow, FuncAnimation


    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    输出如下,是两张图画,各有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])
    
    • 1
    • 2

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

    如果在使用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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行分别得到:

    以及

    显而易见,排版虽然是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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其图片输出分别如下:

    可见:

    • 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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    动态图如下,从左上到右下的四个子图,坐标分别是(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设置返回值,也可以正常生成动画图。但有的例子中会不止更新画幅,而且设置返回值,这里留个疑问。

  • 相关阅读:
    二分搜索树节点删除(Java 实例代码)
    pandas 怎么样扩展数据,就是把加权数据,转换成个案数据
    C++异常
    多任务环境中如何喂看门狗?
    一个软件打磨了24年,被安装超过100亿次,居然赚不到钱?
    【跨模态】Jina VCED
    现有文章汇总
    Acrobat中的颜色转换和油墨管理功能以及专色转换
    网络安全内网渗透之DNS隧道实验--dnscat2直连模式
    会员营销中,数字会员模式如何打造差异化会员服务
  • 原文地址:https://blog.csdn.net/duoyasong5907/article/details/127543807