python - python 中的 Animate 显示静态图

标签 python matplotlib animation

我们一直在尝试为水箱中不同时间间隔的参数绘制动画图表。它绘制时没有错误,但不随时间变化。

动画代码如下:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

T= [0*60,5*60,8*60,10*60,12*60]     #minutes                                   #Time correspondeing to I (inflow) below. The (*60) is to convert the time from hours to minutes
I= [0.08,0.06,0.05,0.00,0.00]       #cubic meter/sec                           #Inflow values corresponding to the above T (time)
h0= 11.0     #meters                                                           #Initial water head value
dt= 10.0     #minutes                                                          #time step 
k= 0.01*60   #sqm/min                                                          #Flow coefficient  
R= 8.0       #meters                                                           #Sphere radius 
Tmax= 12.0*60       #minutes                                                   #Total estimation time 
n= int(Tmax/dt)+1                 


ts = np.linspace(0,10,101)
h_th=[h0]
t_th=[0]
Area_th= [np.pi*(R**2 - (abs(R - h0))**2)]
Q_th= [k*np.sqrt(h0)]
inflow_th=[I[0]*60]

for i in range (1,n):                                                          #looping through the steps
    t_th.append(i*dt)
    h_th.append(h_th[i-1]+(dt*(inflow_th[i-1]-Q_th[i-1]))/(Area_th[i-1]))
    Area_th.append(np.pi*(R**2 - (abs(R - h_th[i]))**2))
    Q_th.append(k*(np.sqrt(h_th[i])))
    inflow_th.append((np.interp(i*dt,T,I))*60)

fig=plt.figure(1,figsize=(12,5))

i=0
ax1=plt.subplot(4,1,1)
pl1,=plt.plot(t_th[0:i+1],h_th[0:i+1],'r-',linewidth=3,label='water level')
plt.ylabel('Head Level (m)')
plt.legend(loc='best')
ax1.set_ylim(-1,1)
ax2=plt.subplot(4,1,2)
pl2,=plt.plot(t_th[0:i+1],inflow_th[0:i+1]*60,'b--',linewidth=3,label='inflow')
plt.ylabel('Inflow in (m3/min)')    
plt.legend(loc='best')
ax3=plt.subplot(4,1,3)
ax3.set_xlim(ts[0], ts[100])
ax3.set_ylim(-5,5)
pl3,=plt.plot(t_th[0:i+1],Q_th[0:i+1],'g-',linewidth=3,label='outflow')
plt.ylabel('Outflow (m3/min)')
plt.xlabel('Time (min)')
plt.legend(loc='best')        
ax4=plt.subplot(4,1,4)
ax4.set_xlim(ts[0], ts[100])
pl4,=plt.plot(ts[0:i+1],h_th[0:i+1],'y-',linewidth=3,label='overflow')
plt.ylabel('Overflow')
plt.xlabel('Time (min)')
plt.legend(loc='best')
#plt.legend(loc='best')


def myAnimation(i):
    if i<1: return [] # No need to update frame 0, we already drawn it
    pl1.set_data(t_th[0:i+1], h_th[0:i+1])
    ax1.set_xlim(t_th[0],t_th[i])
    pl2.set_data(t_th[0:i+1], inflow_th[0:i+1])
    ax2.set_xlim(ts[0],ts[i])
    ax2.set_ylim(min(inflow_th[0:i+1]), max(inflow_th[0:i+1]))
    pl3.set_data(t_th[0:i+1], Q_th[0:i+1])
    pl4.set_data(t_th[0:i+1], h_th[0:i+1])
    ax4.set_ylim(min(h_th[0:i+1]), max(h_th[0:i+1]))
    return [pl1, pl2, pl3, pl4]


theAnim = animation.FuncAnimation(fig, myAnimation, frames=100, interval=100, repeat=False)
plt.show()

时间间隔甚至暂停间隔都已重新定义。除了动画之外,一切正常。

最佳答案

最小示例

因此,例如,这里是一个最小的可重现示例,其外观尽可能与您的代码相同。

import numpy as np
import matplotlib.pyplot as plt

ts = np.linspace(0,10,101)
h=np.sin(ts)
inflow=np.cos(ts)
Q=np.tan(ts)
h_th=np.exp(ts)

plt.figure(1,figsize=(12,5))
plt.ion()
plt.show()

for i in range(100):
    plt.clf()
    plt.subplot(4,1,1)
    plt.plot(ts[0:i+1],h[0:i+1],'r-',linewidth=3,label='water level')
    plt.ylabel('Head Level (m)')
    plt.legend(loc='best')
    plt.subplot(4,1,2)
    plt.plot(ts[0:i+1],inflow[0:i+1]*60,'b--',linewidth=3,label='inflow')
    plt.ylabel('Inflow in (m3/min)')    
    plt.legend(loc='best')
    plt.subplot(4,1,3)
    plt.plot(ts[0:i+1],Q[0:i+1],'g-',linewidth=3,label='outflow')
    plt.ylabel('Outflow (m3/min)')
    plt.xlabel('Time (min)')
    plt.legend(loc='best')        
    plt.subplot(4,1,4)
    plt.plot(ts[0:i+1],h_th[0:i+1],'y-',linewidth=3,label='overflow')
    plt.ylabel('Overflow')
    plt.xlabel('Time (min)')
    plt.legend(loc='best')
    #plt.legend(loc='best') # I don't think you need it twice
    plt.pause(0.1) # Reduced to 0.1, because I am not patient.
    # plt.show() #Not really needed, but works also with it

请注意,它可以在我的计算机上运行。与您的代码的唯一区别(除了注释的轻微更改外,但这对动画工作或不工作没有任何改变;当然,创建一个最小的示例,但我假设您的完整代码包含计算 Q 所需的内容) , inflow ,...,并且不知何故,您迭代 i ,否则您不会期望任何动画。很难确定,因为即使您的完整代码也不包含此类内容,只有静态图,和一些评论部分尝试动画它,与我已经提到的相同问题,例如,没有定义 i ),与您的代码的唯一其他区别,所以,是我取消注释了初始 plt.ion()plt.show() 。但我认为,既然您输入了该代码(并对其进行了注释),您就已经尝试过了。

但是,我的最小示例确实生成了动画。

更新数据

现在,这还不是正确的方法。 因为在这里,您在每次迭代时都会重建整个图。包括图例、标签等等,太重了。

你应该做的就是只绘制一次。然后只更新数据。

import numpy as np
import matplotlib.pyplot as plt

ts = np.linspace(0,10,101)
h=np.sin(ts)
inflow=np.cos(ts)
Q=np.tan(ts)
h_th=np.exp(ts)

plt.figure(1,figsize=(12,5))
plt.ion()
plt.show()

i=0
plt.clf()
ax1=plt.subplot(4,1,1)
pl1,=plt.plot(ts[0:i+1],h[0:i+1],'r-',linewidth=3,label='water level')
plt.ylabel('Head Level (m)')
plt.legend(loc='best')
ax1.set_ylim(-1,1)
ax2=plt.subplot(4,1,2)
pl2,=plt.plot(ts[0:i+1],inflow[0:i+1]*60,'b--',linewidth=3,label='inflow')
plt.ylabel('Inflow in (m3/min)')    
plt.legend(loc='best')
ax3=plt.subplot(4,1,3)
ax3.set_xlim(ts[0], ts[100])
ax3.set_ylim(-5,5)
pl3,=plt.plot(ts[0:i+1],Q[0:i+1],'g-',linewidth=3,label='outflow')
plt.ylabel('Outflow (m3/min)')
plt.xlabel('Time (min)')
plt.legend(loc='best')        
ax4=plt.subplot(4,1,4)
ax4.set_xlim(ts[0], ts[100])
pl4,=plt.plot(ts[0:i+1],h_th[0:i+1],'y-',linewidth=3,label='overflow')
plt.ylabel('Overflow')
plt.xlabel('Time (min)')
plt.legend(loc='best')
#plt.legend(loc='best')

for i in range(100):
    pl1.set_data(ts[0:i+1], h[0:i+1])
    ax1.set_xlim(ts[0],ts[i])
    pl2.set_data(ts[0:i+1], inflow[0:i+1])
    ax2.set_xlim(ts[0],ts[i])
    ax2.set_ylim(min(inflow[0:i+1]), max(inflow[0:i+1]))
    pl3.set_data(ts[0:i+1], Q[0:i+1])
    pl4.set_data(ts[0:i+1], h_th[0:i+1])
    ax4.set_ylim(min(h_th[0:i+1]), max(h_th[0:i+1]))
    plt.pause(0.1)

x 和 y 限制具有不同的样式(固定或非固定)。

与之前相比的变化是,我只绘制了一次。并在变量中保留两件事:我需要调用的轴( ax1, ax2, ax3, ax4 ) set_xlimset_ylim 。而“艺术家”即plot的返回。我需要更新数据。

因此无需每次都重新创建布局、图例、轴、样式、子图……。只是为了更新数据。

动画

这也是重新发明轮子。不过我有时也会这样做。例如,当我想将其集成到另一个“主循环”(用于 GUI 或其他东西)中时。

有一个专门的动画模块。这和我做的一模一样。但更有效(仅更新发生变化的像素,与主循环交互而无需显式暂停,等等)。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation


ts = np.linspace(0,10,101)
h=np.sin(ts)
inflow=np.cos(ts)
Q=np.tan(ts)
h_th=np.exp(ts)

fig=plt.figure(1,figsize=(12,5))

i=0
ax1=plt.subplot(4,1,1)
pl1,=plt.plot(ts[0:i+1],h[0:i+1],'r-',linewidth=3,label='water level')
plt.ylabel('Head Level (m)')
plt.legend(loc='best')
ax1.set_ylim(-1,1)
ax2=plt.subplot(4,1,2)
pl2,=plt.plot(ts[0:i+1],inflow[0:i+1]*60,'b--',linewidth=3,label='inflow')
plt.ylabel('Inflow in (m3/min)')    
plt.legend(loc='best')
ax3=plt.subplot(4,1,3)
ax3.set_xlim(ts[0], ts[100])
ax3.set_ylim(-5,5)
pl3,=plt.plot(ts[0:i+1],Q[0:i+1],'g-',linewidth=3,label='outflow')
plt.ylabel('Outflow (m3/min)')
plt.xlabel('Time (min)')
plt.legend(loc='best')        
ax4=plt.subplot(4,1,4)
ax4.set_xlim(ts[0], ts[100])
pl4,=plt.plot(ts[0:i+1],h_th[0:i+1],'y-',linewidth=3,label='overflow')
plt.ylabel('Overflow')
plt.xlabel('Time (min)')
plt.legend(loc='best')
#plt.legend(loc='best')


def myAnimation(i):
    if i<1: return [] # No need to update frame 0, we already drawn it
    pl1.set_data(ts[0:i+1], h[0:i+1])
    ax1.set_xlim(ts[0],ts[i])
    pl2.set_data(ts[0:i+1], inflow[0:i+1])
    ax2.set_xlim(ts[0],ts[i])
    ax2.set_ylim(min(inflow[0:i+1]), max(inflow[0:i+1]))
    pl3.set_data(ts[0:i+1], Q[0:i+1])
    pl4.set_data(ts[0:i+1], h_th[0:i+1])
    ax4.set_ylim(min(h_th[0:i+1]), max(h_th[0:i+1]))
    return [pl1, pl2, pl3, pl4]


theAnim = animation.FuncAnimation(fig, myAnimation, frames=100, interval=100, repeat=False)
plt.show()

这里的主要变化是我导入了 animation ,将数字保存在变量 fig 中,并创建一个回调来更新数据(循环是 animation 的工作)。 请注意,该回调需要返回“艺术家”已更改内容的数组。在这里,所有的,即[pl1, pl2, pl3, pl4] .

另请注意,即使我从不使用该变量(至少目前如此),我也需要保存 FuncAnimation 的结果调用变量theAnim 。因为如果我不这样做,垃圾收集器会在一段时间后删除该返回值。这种破坏也意味着动画本身的破坏。

创建 gif(或 mp4,...)

你还没有问过这个问题。但是代码中失败的尝试和注释表明,一旦动画正常工作,您希望能够将结果保存在电影中(或 gif,我将在此处执行此操作,以便能够在此处包含结果)

animation模块,这非常简单。

只需添加到代码的最后

theAnim.save("anim.gif")

(如果同时保留 .saveplt.show ,则只有在关闭绘图窗口后动画才会保存到文件中。如果注释 plt.show() 行,则不会打开任何窗口,但创建包含动画的文件)

enter image description here

关于python - python 中的 Animate 显示静态图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74886493/

相关文章:

Python 将类序列化为 JSON

javascript - 如何沿路线制作自定义 Google map 标记的动画?

javascript - 使用js手动将弹跳动画应用于div元素

javascript - Three.js - 蒙皮骨架网格实例、动画和混合

python - matplotlib 热图的中心对齐刻度标签

python - 如何在 Python OpenCV 中读取图像

python - 将 qsub 变量传递给调用 python 的 .pbs 脚本

python - 无法将 python 应用程序容器连接到本地 postgres

python - 带有 *args 函数的装饰器

python - Python 新手……Python 3 和 Matplotlib