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

丶灬走出姿态 提交于 2020-04-02 07:32:33

基础

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]

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!