表面动画并使用 matplotlib 保存

Rob*_*Tan 3 python math animation matplotlib matplotlib-animation

我尝试做一个非常简单的动画并用 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)
Run Code Online (Sandbox Code Playgroud)

我阅读了大量在线文档,包括官方文档,但我找不到表面随时间演变的清晰示例。我还发现很难掌握用 matplotlib 构建绘图背后的逻辑(我读到了有关图形、关联对象、轴、其他对象的内容......我很困惑),但我也在自学它以备考试和我并不是一个真正的技术人员,所以也许这就是我遇到这么多麻烦的原因;从根本上来说,如果你回答并且能再花两分钟更详细地描述你在做什么,你会让我非常高兴。非常感谢您的帮助。

Zep*_*hyr 6

首先,您必须设置表面的数学域,该数学域对于每个动画帧都是恒定的,因此您可以在开始时执行此操作:

x = np.arange(0,10,0.1)
y = np.arange(0,10,0.1)
X,Y = np.meshgrid(x,y)
Run Code Online (Sandbox Code Playgroud)

然后你可以初始化该图:

fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
Run Code Online (Sandbox Code Playgroud)

动画部分来了,您必须定义一个函数来描述一个动画帧和下一帧之间的变化。首先,您必须从图中清除上一帧中已经绘制的内容,以便您可以使用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,
Run Code Online (Sandbox Code Playgroud)

FuncAnimation最后,您必须使用所需的参数设置对象:

anim = FuncAnimation(fig = fig, func = animate, frames = 10, interval = 1, repeat = False)
Run Code Online (Sandbox Code Playgroud)

完整代码

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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


另一个更改表面公式的示例,如果您使用:

u = np.sin(5/2/np.pi*n)*np.sin((X + Y))
Run Code Online (Sandbox Code Playgroud)

在函数内animate,则表面相位将保持恒定,但滑曲线表面振幅将发生变化,遵循滑曲线函数本身,因此您将得到:

在此输入图像描述


Sté*_*ent 6

这是另一个例子。我从 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)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

(感谢网站ezgif.com,我将 mp4 转换为 gif ,但 gif 太大了,所以我用gifsicle压缩它,但质量有所损失。)


编辑

更好的动图:

在此输入图像描述