表面动画和使用 matplotlib 保存
Surface animation and saving with matplotlib
我尝试做一个很简单的动画,用matplotlib保存,但是没有成功。例如,我想看到一些振荡:这是我能做的最好的
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
#Define x,y vectors and meshgrid with function u on it
x = np.arange(0,10,0.1)
y = np.arange(0,10,0.1)
X,Y = np.meshgrid(x,y)
u = np.sin(X + Y)
#Create a figure and an axis object for the surface
#(which by the way is not initialized, because I don't know were to)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
#Define a kind-of animation function, imitating what I saw many times
def animate(n):
global u
for n in (1,20):
u = np.sin((X + Y)*n)
return fig,
#I'm missing many commands, I'm just putting what I know
anim = animation.FuncAnimation(fig,animate)
anim.save('A.mp4',fps=10)
我阅读了大量在线文档,包括官方文档,但我找不到表面随时间演变的明确示例。我还发现很难掌握使用 matplotlib 构建绘图背后的逻辑(我阅读了有关图形、关联的对象、轴、其他对象……我感到困惑),但我也在自学它以备考试和我不是一个真正的技术人员,所以也许这就是我遇到这么多麻烦的原因;从根本上说,如果您回答并能多花两分钟更详细地描述您在做什么,您会让我非常高兴。非常感谢您的帮助。
首先,你要设置表面的数学域,它对于每个动画帧都是不变的,所以你可以在开始的时候做:
x = np.arange(0,10,0.1)
y = np.arange(0,10,0.1)
X,Y = np.meshgrid(x,y)
然后就可以初始化图了:
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
这里是动画的东西,你必须定义一个函数来描述一个动画帧和下一帧之间的变化。首先你必须从图中清除你在前一帧中已经绘制的内容,所以你可以使用 ax.cla()
.
然后是数学部分:您必须定义您的函数以及它如何随时间变化。注意 animate
函数有一个参数,在你的例子中是 n
,它在每一帧中增加 1
,你可以用它来描述连续帧之间的变化。例如,如果我写 u = np.sin((X + Y) + n)
那么正交曲面将在每次迭代中增加其相位,因此它将“向前移动”;您可以重新定义此等式,以便通过正确使用 n
参数来实现您的目标。
然后是用 ax.plot_surface(X, Y, u)
绘制表面的时候了。这不是强制性的,但我建议修复轴限制,以改进动画,ax.set_zlim(-2, 2)
。
这样 animate
函数定义为:
def animate(n):
ax.cla()
u = np.sin((X + Y) + n)
ax.plot_surface(X, Y, u)
ax.set_zlim(-2, 2)
return fig,
最后,您必须使用您想要的参数设置 FuncAnimation
对象:
anim = FuncAnimation(fig = fig, func = animate, frames = 10, interval = 1, repeat = False)
完整代码
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.arange(0,10,0.1)
y = np.arange(0,10,0.1)
X,Y = np.meshgrid(x,y)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
def animate(n):
ax.cla()
u = np.sin((X + Y) + n)
ax.plot_surface(X, Y, u)
ax.set_zlim(-2, 2)
return fig,
anim = FuncAnimation(fig = fig, func = animate, frames = 10, interval = 1, repeat = False)
anim.save('A.mp4',fps=10)
另一个改变曲面公式的例子,如果你使用:
u = np.sin(5/2/np.pi*n)*np.sin((X + Y))
在animate
函数中,表面相位保持不变,但正弦表面振幅会发生变化,遵循正弦函数,所以你会得到:
这是另一个例子。我从JavaScript库vis3d的图库借来的,感谢@Zephyr的回答,我把它变成了Python。
from math import pi, cos, sin
import numpy as np
import matplotlib.colors as mcolors
from matplotlib import cm
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x_ = np.linspace(0, 314, 50)
y_ = np.linspace(0, 314, 50)
X, Y = np.meshgrid(x_, y_)
t_ = np.linspace(0, 2*pi, 90)
def f(x, y):
return np.sin(x/50) * np.cos(y/50) * 50 + 50
def g(x, y, t):
return f(x*cos(t) - y*sin(t), x*sin(t) + y*cos(t))
fig = plt.figure()
ax = fig.add_subplot(projection = "3d")
def animate(n):
ax.cla()
Z = g(X, Y, t_[n])
colorfunction = (X**2+Y**2+Z**2)
norm = mcolors.Normalize(colorfunction.min(), colorfunction.max())
ax.plot_surface(
X, Y, Z, rstride = 1, cstride = 1, facecolors=cm.jet(norm(colorfunction))
)
ax.set_zlim(0, 100)
return fig
anim = FuncAnimation(
fig = fig, func = animate, frames = len(t_), interval = 1, repeat = False
)
anim.save("Anim.mp4", fps = 10)
(感谢网站 ezgif.com,我将 mp4 转换为 gif,但是 gif 对于 SO 来说太大了,所以我用 压缩了它gifsicle 质量下降。)
编辑
更好的 gif:
我尝试做一个很简单的动画,用matplotlib保存,但是没有成功。例如,我想看到一些振荡:这是我能做的最好的
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
#Define x,y vectors and meshgrid with function u on it
x = np.arange(0,10,0.1)
y = np.arange(0,10,0.1)
X,Y = np.meshgrid(x,y)
u = np.sin(X + Y)
#Create a figure and an axis object for the surface
#(which by the way is not initialized, because I don't know were to)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
#Define a kind-of animation function, imitating what I saw many times
def animate(n):
global u
for n in (1,20):
u = np.sin((X + Y)*n)
return fig,
#I'm missing many commands, I'm just putting what I know
anim = animation.FuncAnimation(fig,animate)
anim.save('A.mp4',fps=10)
我阅读了大量在线文档,包括官方文档,但我找不到表面随时间演变的明确示例。我还发现很难掌握使用 matplotlib 构建绘图背后的逻辑(我阅读了有关图形、关联的对象、轴、其他对象……我感到困惑),但我也在自学它以备考试和我不是一个真正的技术人员,所以也许这就是我遇到这么多麻烦的原因;从根本上说,如果您回答并能多花两分钟更详细地描述您在做什么,您会让我非常高兴。非常感谢您的帮助。
首先,你要设置表面的数学域,它对于每个动画帧都是不变的,所以你可以在开始的时候做:
x = np.arange(0,10,0.1)
y = np.arange(0,10,0.1)
X,Y = np.meshgrid(x,y)
然后就可以初始化图了:
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
这里是动画的东西,你必须定义一个函数来描述一个动画帧和下一帧之间的变化。首先你必须从图中清除你在前一帧中已经绘制的内容,所以你可以使用 ax.cla()
.
然后是数学部分:您必须定义您的函数以及它如何随时间变化。注意 animate
函数有一个参数,在你的例子中是 n
,它在每一帧中增加 1
,你可以用它来描述连续帧之间的变化。例如,如果我写 u = np.sin((X + Y) + n)
那么正交曲面将在每次迭代中增加其相位,因此它将“向前移动”;您可以重新定义此等式,以便通过正确使用 n
参数来实现您的目标。
然后是用 ax.plot_surface(X, Y, u)
绘制表面的时候了。这不是强制性的,但我建议修复轴限制,以改进动画,ax.set_zlim(-2, 2)
。
这样 animate
函数定义为:
def animate(n):
ax.cla()
u = np.sin((X + Y) + n)
ax.plot_surface(X, Y, u)
ax.set_zlim(-2, 2)
return fig,
最后,您必须使用您想要的参数设置 FuncAnimation
对象:
anim = FuncAnimation(fig = fig, func = animate, frames = 10, interval = 1, repeat = False)
完整代码
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.arange(0,10,0.1)
y = np.arange(0,10,0.1)
X,Y = np.meshgrid(x,y)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
def animate(n):
ax.cla()
u = np.sin((X + Y) + n)
ax.plot_surface(X, Y, u)
ax.set_zlim(-2, 2)
return fig,
anim = FuncAnimation(fig = fig, func = animate, frames = 10, interval = 1, repeat = False)
anim.save('A.mp4',fps=10)
另一个改变曲面公式的例子,如果你使用:
u = np.sin(5/2/np.pi*n)*np.sin((X + Y))
在animate
函数中,表面相位保持不变,但正弦表面振幅会发生变化,遵循正弦函数,所以你会得到:
这是另一个例子。我从JavaScript库vis3d的图库借来的,感谢@Zephyr的回答,我把它变成了Python。
from math import pi, cos, sin
import numpy as np
import matplotlib.colors as mcolors
from matplotlib import cm
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x_ = np.linspace(0, 314, 50)
y_ = np.linspace(0, 314, 50)
X, Y = np.meshgrid(x_, y_)
t_ = np.linspace(0, 2*pi, 90)
def f(x, y):
return np.sin(x/50) * np.cos(y/50) * 50 + 50
def g(x, y, t):
return f(x*cos(t) - y*sin(t), x*sin(t) + y*cos(t))
fig = plt.figure()
ax = fig.add_subplot(projection = "3d")
def animate(n):
ax.cla()
Z = g(X, Y, t_[n])
colorfunction = (X**2+Y**2+Z**2)
norm = mcolors.Normalize(colorfunction.min(), colorfunction.max())
ax.plot_surface(
X, Y, Z, rstride = 1, cstride = 1, facecolors=cm.jet(norm(colorfunction))
)
ax.set_zlim(0, 100)
return fig
anim = FuncAnimation(
fig = fig, func = animate, frames = len(t_), interval = 1, repeat = False
)
anim.save("Anim.mp4", fps = 10)
(感谢网站 ezgif.com,我将 mp4 转换为 gif,但是 gif 对于 SO 来说太大了,所以我用 压缩了它gifsicle 质量下降。)
编辑
更好的 gif: