matplotlib python中的动画显示静态图形

tmb3ates  于 2022-12-23  发布在  Python
关注(0)|答案(1)|浏览(136)

我们一直在尝试制作一个水箱中沿着时间间隔参数的动画图,它的绘制没有错误,但没有随时间变化的动画效果。
动画的代码如下所示:

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()

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

5lhxktic

5lhxktic1#

最小示例

例如,这里是一个最小的可重复示例,尽可能地使其看起来像您的代码。

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

请注意,它是在我的电脑上工作。唯一的区别与您的代码(除了轻微的变化注解,但这不会改变任何动画工作与否;当然,创建一个最小的例子,但是我假设你的完整代码包含了计算Qinflow,......所需的内容,并且,不知何故,你迭代了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限制的样式不同(固定或不固定)。
与之前的变化是,我只画一次,变量中保留两个东西:axes(ax1, ax2, ax3, ax4),我需要调用set_xlimset_ylim。“artist”是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等)

你还没有问过这个问题,但是失败的尝试和代码中的注解表明,一旦你让动画工作起来,你希望能够把结果保存在movie中(或者gif中,我在这里会这样做,以便能够在这里包含结果)
使用animation模块,这非常简单。
只需在代码的最后添加

theAnim.save("anim.gif")

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

相关问题