• 『科学计算』科学绘图库matplotlib学习之绘制动画


    基础

    1.matplotlib绘图函数接收两个等长list,第一个作为集合x坐标,第二个作为集合y坐标

    2.基本函数:

    animation.FuncAnimation(fig, update_point,data)

    • fig是画布
    • update是绘画函数需自己定义,需要一个参数,会自动接收data,需要返回plt.plot对象,描述比较费解,看例子就好
    • data种类很多,包括总帧数(例1)、当前帧数(即不设定data的默认参数,例2)、返回迭代器的函数(例3)、list(作业2)
    • frames=200 总帧数(非update参数)
    • interval=20  帧间隔(毫秒)

    示例代码

    简单调用帧数绘图

    from matplotlib import pyplot as plt
    import matplotlib.animation as animation
    import numpy as np
    
    
    def update_point(num):
        fig_points.set_data(data[:, 0:num])
        return fig_points,
    
    fig1 = plt.figure()
    
    num_point = 50
    data = np.random.rand(2, num_point)
    fig_points, = plt.plot([], [], 'ro')
    
    plt.xlim(0, 1)
    plt.ylim(0, 1)
    plt.xlabel('x')
    plt.title('Scatter Point')
    
    # interval
    # repeat
    # frames
    # fargs
    # init_func
    anim = animation.FuncAnimation(fig1, update_point,num_point)
    
    #anim = animation.FuncAnimation(fig1, update_point,frames=num_point, interval=50, blit=False, repeat=False)
    
    plt.show()
    

     

    利用帧做参数绘制

    这种方式每经过interval的时间后会调用函数(传入当前帧号)绘制一幅新图更新原图:

    1. 建立子图、空白线
    2. 创建动画发生时调用的函数

      Init()是我们的动画在在创建动画基础框架(base frame)时调用的函数。这里我们们用一个非常简单的对line什么都不做的函数。这个函数一定要返回line对

      象,这个很重要,因为这样就能告诉动画之后要更新的内容,也就是动作的内容是line。--来自( http://mytrix.me/2013/08/matplotlib-animation-tutorial/

    3. 动画函数

      在这个动画函数中修改你的图

    4. 调用函数生成动态图

    绘制正弦波函数:

    可以使用多个线对象来同时更新多个子图于同一个动画生成器之中,不过这需要上面1~3步同时支持(就是写出来)多个线对象

    import numpy as np
    from matplotlib import pyplot as plt
    from matplotlib import animation
    
    # 1.First set up the figure, the axis, and the plot element we want to animate
    fig = plt.figure()
    ax = plt.axes(xlim=(0,2),ylim=(-2,2))
    line, = ax.plot([],[],lw=2)
    
    
    # 2.initialization function: plot the background of each frame
    def init():
        line.set_data([],[])
        return line,
    
    
    # 3.animation function.  This is called sequentially
    # note: i is framenumber
    def update(i):
        x = np.linspace(0,2,1000)
        y = np.sin(2 * np.pi * (x - 0.01 * i))  # 调整x相当于向右平移图像
        line.set_data(x,y)
        return line,
    
    
    # call the animator.  blit=True means only re-draw the parts that have changed.
    # 画布, 使用帧数做参数的绘制函数, init生成器.。
    anim = animation.FuncAnimation(fig,update,init_func=init,frames=200,interval=20,blit=False)
    # frames=200   帧数
    # interval=20  间隔
    
    # anim.save('anim3.mp4', fps=30, extra_args=['-vcodec', 'libx264'])      # 保存为mp4
    # anim.save('anim3.gif', writer='imagemagick')                           # 保存为gif
    
    plt.show()
    

     

    迭代器绘制法

    绘制衰减波

    这里的update函数仅仅绘制图像,数据生成被移植到函数data_gen中了,而上面的帧方法中update得到帧号后会自己生成数据。

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    
    def data_gen():
        t = 0
        cnt = 0
        while cnt < 200:
            cnt += 1
            t += 0.1
            yield t,np.sin(2 * np.pi * t) * np.exp(-t / 10.)
    
    
    def init():
        ax.set_ylim(-1.1,1.1)
        ax.set_xlim(0,10)
        line.set_data([],[])
        return line,
    
    
    def update(datag):
        # update the data,默认接受后面的yield
        t,y = datag
        xdata.append(t)
        ydata.append(y)
        line.set_data(xdata,ydata)
    
        if max(xdata) > 10:
            ax.set_xlim(max(xdata) - 10,max(xdata))
        return line,
    
    
    fig,ax = plt.subplots()
    line, = ax.plot([],[],lw=2)
    ax.grid()
    xdata,ydata = [],[]
    
    # 参数:{画布,绘制图像函数,更新数据函数,时间间隔,重复标识,初始化函数}
    ani = animation.FuncAnimation(fig,update,data_gen,interval=10,repeat=False,init_func=init)
    plt.show()
    

    作业

    冒泡排序算法动画演示

    使用迭代器更新方式:

    参考:

      
    import numpy as np  
    import matplotlib.pyplot as plt  
    import matplotlib.animation as animation  
      
    fig = plt.figure()  
    axes1 = fig.add_subplot(111)  
    line, = axes1.plot(np.random.rand(10))  
      
    #因为update的参数是调用函数data_gen,所以第一个默认参数不能是framenum  
    def update(data):  
        line.set_ydata(data)  
        return line,  
    # 每次生成10个随机数据  
    def data_gen():  
        while True:  
            yield np.random.rand(10)  
      
    ani = animation.FuncAnimation(fig, update, data_gen, interval=2*1000)  
    plt.show()  
    

    代码:

    import numpy as np
    from matplotlib import pyplot as plt
    from matplotlib import animation
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    line, = ax.plot(np.zeros(9),'bo')  # 由于没有使用init_fun,所以初始帧有数据,且尺寸与后续帧一致才行
    ax.set_xlim(0,10)
    ax.set_ylim(0,10)
    ax.set_xticks(np.linspace(0,10,11))
    ax.set_yticks(np.linspace(0,10,11))
    ax.grid(True)
    
    # update的参数是调用函数data_gen
    def update(data):
        line.set_xdata(np.linspace(1,9,9))
        line.set_ydata(data)
        return line,
    
    def data_gen():
        x = [9,8,3,1,2,4,6,5,7]
        for i in range(len(x)-1):
            for j in range(len(x)-1):
                if x[j]>x[j+1]:
                    x[j],x[j+1]=x[j+1],x[j]
                yield(x)
    
    # {画布,绘制函数(数据函数yield),数据函数,帧间隔(毫秒),重复标识}
    ani = animation.FuncAnimation(fig,update,data_gen,interval=1000,repeat=False)
    plt.show()
    

    快速排序算法动画演示

    使用数组更新方式:

    • 不把数据以迭代器的方式传入,而是list,则每次会把list的子项依次传入update。list形式是[ [list1], [list2], ... ... ]。
    • 另外使用了init_fun,使用这个函数了后不用绘制初始帧,即可以使用:line = ax.plot([],[],'go'),而不用指定初始化数据,但是这样的话x轴数据update需要设定好才行(因为默认继承初始帧的x轴)。

    参考:

    例子使用list(metric),每次会从metric中取一行数据作为参数送入update中

        import numpy as np  
        import matplotlib.pyplot as plt  
        import matplotlib.animation as animation  
          
        start = [1, 0.18, 0.63, 0.29, 0.03, 0.24, 0.86, 0.07, 0.58, 0]  
          
        metric =[[0.03, 0.86, 0.65, 0.34, 0.34, 0.02, 0.22, 0.74, 0.66, 0.65],  
                 [0.43, 0.18, 0.63, 0.29, 0.03, 0.24, 0.86, 0.07, 0.58, 0.55],  
                 [0.66, 0.75, 0.01, 0.94, 0.72, 0.77, 0.20, 0.66, 0.81, 0.52]  
                ]  
          
        fig = plt.figure()  
        window = fig.add_subplot(111)  
        line, = window.plot(start)  
        #如果是参数是list,则默认每次取list中的一个元素,即metric[0],metric[1],...  
        def update(data):  
            line.set_ydata(data)  
            return line,  
          
        ani = animation.FuncAnimation(fig, update, metric, interval=2*1000)  
        plt.show()  
    

    代码:

    import numpy as np
    from matplotlib import pyplot as plt
    from matplotlib import animation
    import copy
    
    obj = [49,38,65,97,76,13,27,49]
    res = []
    
    def fast_sort(ob,start,end):
        # print(ob,start,end)
        if  end - start <= 1:
            return
        # i,j,k = 0,(len(ob)-1),ob[0]
        i,j,k = start,end,ob[start]
        while j-i != 1:
            for j_r in range(j,i,-1):
                j = j_r
                if ob[j_r]<k:
                    ob[i],ob[j_r] = ob[j_r],ob[i]
                    break
            # print(ob,i,j)
            for i_r in range(i,j):
                i = i_r
                if ob[i_r]>k:
                    ob[i_r],ob[j] = ob[j],ob[i_r]
                    break
        res.append(copy.deepcopy(ob))  # 这里发现添加进res的list对象是浅拷贝,或者说向数据结构中添加的list都是浅拷贝,需要注意
        if ob[i] == k:
            fast_sort(ob,start,i-1)
            fast_sort(ob,i+1,end)
        else:
            fast_sort(ob,start,j-1)
            fast_sort(ob,j+1,end)
    
    fast_sort(obj,0,(len(obj)-1))
    print(res)
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.set_xlim(0,8)
    ax.set_ylim(0,100)
    ax.set_xticks(np.linspace(0,8,9))
    ax.set_yticks(np.linspace(0,100,11))
    ax.grid()
    line, = ax.plot([],[],'go')
    
    def init():
        line.set_data([], [])
        return line,
    
    def update(data):  # update函数参数默认接收其后的函数或是list
        line.set_xdata(np.linspace(0,7,8))
        line.set_ydata(data)
        return line
    
    ani = animation.FuncAnimation(fig,update,res,init_func=init,interval=2*1000,repeat=False)
    

     冒泡排序&快速排序代码

    两种排序具体定义自行百度,不过比较重要的一点是快速排序属于递归过程,蛮好玩的。

    冒泡排序

    import numpy as np
    
    ob = [9,8,3,1,2,4,6,5,7]
    def oppo_sort(x):
        for i in range(len(x)-1):
            for j in range(len(x)-1):
                if x[j]>x[j+1]:
                    x[j],x[j+1]=x[j+1],x[j]
                yield((i,j),x)
    for t,obj in oppo_sort(ob):
        print(t,obj)
    
    (0, 0) [8, 9, 3, 1, 2, 4, 6, 5, 7]
    (0, 1) [8, 3, 9, 1, 2, 4, 6, 5, 7]
    (0, 2) [8, 3, 1, 9, 2, 4, 6, 5, 7]
    (0, 3) [8, 3, 1, 2, 9, 4, 6, 5, 7]
    (0, 4) [8, 3, 1, 2, 4, 9, 6, 5, 7]
    (0, 5) [8, 3, 1, 2, 4, 6, 9, 5, 7]
    (0, 6) [8, 3, 1, 2, 4, 6, 5, 9, 7]
    (0, 7) [8, 3, 1, 2, 4, 6, 5, 7, 9]
    (1, 0) [3, 8, 1, 2, 4, 6, 5, 7, 9]
    (1, 1) [3, 1, 8, 2, 4, 6, 5, 7, 9]
    (1, 2) [3, 1, 2, 8, 4, 6, 5, 7, 9]
    (1, 3) [3, 1, 2, 4, 8, 6, 5, 7, 9]
    (1, 4) [3, 1, 2, 4, 6, 8, 5, 7, 9]
    (1, 5) [3, 1, 2, 4, 6, 5, 8, 7, 9]
    (1, 6) [3, 1, 2, 4, 6, 5, 7, 8, 9]
    (1, 7) [3, 1, 2, 4, 6, 5, 7, 8, 9]
    (2, 0) [1, 3, 2, 4, 6, 5, 7, 8, 9]
    (2, 1) [1, 2, 3, 4, 6, 5, 7, 8, 9]
    (2, 2) [1, 2, 3, 4, 6, 5, 7, 8, 9]
    (2, 3) [1, 2, 3, 4, 6, 5, 7, 8, 9]
    (2, 4) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (2, 5) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (2, 6) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (2, 7) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 0) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 1) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 2) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 3) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 4) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 5) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 6) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (3, 7) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 0) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 1) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 2) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 3) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 4) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 5) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 6) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (4, 7) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 0) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 1) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 2) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 3) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 4) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 5) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 6) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (5, 7) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 0) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 1) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 2) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 3) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 4) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 5) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 6) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (6, 7) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 0) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 1) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 2) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 3) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 4) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 5) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 6) [1, 2, 3, 4, 5, 6, 7, 8, 9]
    (7, 7) [1, 2, 3, 4, 5, 6, 7, 8, 9]

    快速排序

    有坑,不仅是因为快速排序本身比较复杂的原因,由于python的拷贝机制,实现起来也有一些注意的地方,注意在探究python拷贝机制的时候id()是个有用的函数。

    本段方法出错了,原因试python在给函数传入list的时候按照是浅拷贝的(即对同一id操作),但是,一旦传入的是切片,那么就会分配id进行深拷贝,其实不难理解,毕竟对于一个函数可以看作一个较为独立的节点,其中的元素都要有自己完整的标识,即自己的id:

    obj = [49,38,65,97,76,13,27,49]
    
    def fast_sort(ob):
        # print(id(ob))
        if len(ob) <= 1:
            return
        i,j,k = 0,(len(ob)-1),ob[0]
        while j-i != 1:
            for j_r in range(j,i,-1):
                j = j_r
                if ob[j_r]<k:
                    ob[i],ob[j_r] = ob[j_r],ob[i]
                    break
            # print(ob,i,j)
            for i_r in range(i,j):
                i = i_r
                if ob[i_r]>k:
                    ob[i_r],ob[j] = ob[j],ob[i_r]
                    break
            print(ob)
        if ob[i] == k:
            fast_sort(ob[:i])
            fast_sort(ob[i+1:])
        else:
            fast_sort(ob[:j])
            fast_sort(ob[j+1:])
    
    fast_sort(obj)
    
    [27, 38, 49, 97, 76, 13, 65, 49]
    [27, 38, 13, 49, 76, 97, 65, 49]
    [27, 38, 13, 49, 76, 97, 65, 49]
    [13, 27, 38]
    [49, 76, 65, 97]
    [49, 65, 76, 97]

    可以清晰地验明上述结论:

    ls = [1,2,3,4,5]
    i = 0
    
    def print_id(l1,l2):
        global i
        i += 1
        if i == 10:return
        print(id(l1),'  ',id(l2))
        print_id(l1,l2[1:2])
    
    print_id(ls,ls)
    2424669584200    2424669584200
    2424669584200    2424669684168
    2424669584200    2424669616008
    2424669584200    2424669615880
    2424669584200    2424669614984
    2424669584200    2424669548040
    2424669584200    2424669614792
    2424669584200    2424669584712
    2424669584200    2424669497992

    python凡是涉及到修改数据结构都应该遵循如下方式:传入原始数据结构,传入索引,在函数内部使用索引修改数据结构而不是直接传入数据结构的一部分,下面是正确的写法。

    顺便注意一下递归函数的写法:终止判断+主函数体+递归调用分部

    import copy
    obj = [49,38,65,97,76,13,27,49]
    res=[]
    def fast_sort(ob,start,end):
        # print(ob,start,end)
        if  end - start <= 1:
            return
        # i,j,k = 0,(len(ob)-1),ob[0]
        i,j,k = start,end,ob[start]
        while j-i != 1:
            for j_r in range(j,i,-1):
                j = j_r
                if ob[j_r]<k:
                    ob[i],ob[j_r] = ob[j_r],ob[i]
                    break
            # print(ob,i,j)
            for i_r in range(i,j):
                i = i_r
                if ob[i_r]>k:
                    ob[i_r],ob[j] = ob[j],ob[i_r]
                    break
        print(ob)
        res.append(copy.deepcopy(ob)) # 注意深拷贝
        print(res)
        if ob[i] == k:
            fast_sort(ob,start,i-1)
            fast_sort(ob,i+1,end)
        else:
            fast_sort(ob,start,j-1)
            fast_sort(ob,j+1,end)
            
    fast_sort(obj,0,(len(obj)-1))
    print(obj)
    
    [27, 38, 13, 49, 76, 97, 65, 49]
    [[27, 38, 13, 49, 76, 97, 65, 49]]
    [13, 27, 38, 49, 76, 97, 65, 49]
    [[27, 38, 13, 49, 76, 97, 65, 49], [13, 27, 38, 49, 76, 97, 65, 49]]
    [13, 27, 38, 49, 49, 65, 76, 97]
    [[27, 38, 13, 49, 76, 97, 65, 49], [13, 27, 38, 49, 76, 97, 65, 49], [13, 27, 38, 49, 49, 65, 76, 97]]
    [13, 27, 38, 49, 49, 65, 76, 97]
    
  • 相关阅读:
    Flask框架总结
    spring boot 批量新增
    Visual Studio Code代码格式化Vue文件设置快捷键ctrl+alt+l
    Visual Studio Code安装插件!!!
    JavaScript:改变 HTML 内容
    使用JavaScript脚本在页面上显示输出
    将redis添加到linux系统服务
    虚拟机VMware下CentOS6.6安装教程图文详解
    CentOS-6.5下portal连接mysql失败,报permission denied
    2017-03-22、Linux同步当前服务器时间
  • 原文地址:https://www.cnblogs.com/hellcat/p/7086850.html
Copyright © 2020-2023  润新知