[英]Animate 3D surface over an initial 3D plot with matplotlib
I am trying to animate a 3D surface over an initial 3D plot. But am struggling with keeping the initial 3D plot on the animation. I have to call the cla
function to be able to plot the new surface and this will delete my initial state. I am trying to animate a 3D surface over an initial 3D plot. But am struggling with keeping the initial 3D plot on the animation. I have to call the cla
function to be able to plot the new surface and this will delete my initial state.
As an example, I have the animation of a surface while keeping the x,y,z axis.例如,我有一个表面的 animation,同时保持 x、y、z 轴。 The end goal would be to plot the initial state once, and animate the surface.最终目标是 plot 初始 state 一次,并为表面设置动画。
Is it possible to create plot layers?是否可以创建 plot 层? Send the initial state to one layer and the animation to another?将初始 state 发送到一层,将 animation 发送到另一层?
import matplotlib.pyplot as plt import numpy as np from matplotlib.animation import FuncAnimation从 matplotlib.animation 导入 matplotlib.pyplot 作为 plt 导入 numpy 作为 np 导入 FuncAnimation
fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111, projection='3d')
def initialState(ax):
s=1.15
x_axis = np.array([s*5, 0, 0])
y_axis = np.array([0, s*5, 0])
z_axis = np.array([0, 0, s*5])
ax.quiver(0,0,0,*x_axis,color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*x_axis),'x',fontsize=10)
ax.quiver(0,0,0,*y_axis, color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*y_axis),'y',fontsize=10)
ax.quiver(0,0,0,*z_axis,color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*z_axis),'z',fontsize=10)
ax.set_xlim3d(-10, 10)
ax.set_ylim3d(-5, 5)
ax.set_zlim3d(-5, 5)
def plot(i):
X = np.arange(-5+i, 5+i, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
return [X,Y,Z]
def anime(i, ax, stepFactor):
ax.cla()
points = plot(i*stepFactor)
ax.plot_surface(*points, alpha=0.5)
ax.set_xlim3d(-10, 10)
ax.set_ylim3d(-5, 5)
ax.set_zlim3d(-5, 5)
animation = FuncAnimation(
fig,
anime,
init_func=initialState(ax),
frames=range(100),
fargs=(ax, 0.1)
)
Thanks for the help!谢谢您的帮助!
This is how I would do it: add two identical surfaces (at t=0) at the end of the init method.这就是我的做法:在 init 方法的末尾添加两个相同的表面(在 t=0 处)。 This will add two Poly3DCollection
in the last two positions of ax.collections
.这将在Poly3DCollection
的最后两个位置添加两个ax.collections
。 Then, ax.collections[-2]
represents the surface at t=0, and ax.collections[-1]
will be removed and readded in the animation function: it will represent the surface at t=i.然后, ax.collections[-2]
表示 t=0 处的表面, ax.collections[-1]
将被删除并重新添加到 animation function 中:它将表示 t=i 处的表面。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111, projection='3d')
def initialState(ax):
s=1.15
x_axis = np.array([s*5, 0, 0])
y_axis = np.array([0, s*5, 0])
z_axis = np.array([0, 0, s*5])
ax.quiver(0,0,0,*x_axis,color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*x_axis),'x',fontsize=10)
ax.quiver(0,0,0,*y_axis, color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*y_axis),'y',fontsize=10)
ax.quiver(0,0,0,*z_axis,color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*z_axis),'z',fontsize=10)
# add the initial surface
surf0 = ax.plot_surface(*plot(0), color="tab:blue")
# add another copy of the initial surface: this will be removed (and later
# added again) by the anim function.
surf1 = ax.plot_surface(*plot(0), color="tab:blue")
ax.set_xlim3d(-10, 10)
ax.set_ylim3d(-5, 5)
ax.set_zlim3d(-5, 5)
def plot(i):
X = np.arange(-5+i, 5+i, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
return [X,Y,Z]
def anime(i, stepFactor):
points = plot(i*stepFactor)
# remove the last surface added in the previous iteration
# (or in the init function)
ax.collections[-1].remove()
anim_surf = ax.plot_surface(*points, color="tab:blue", alpha=0.5)
animation = FuncAnimation(
fig,
anime,
init_func=initialState(ax),
frames=range(100),
fargs=(0.1, )
)
plt.show()
EDIT: Second solution to accommodate comment: you can also add the surface in the global namespace, like i did below with surf_to_update
.编辑:容纳评论的第二个解决方案:您还可以在全局命名空间中添加表面,就像我在下面使用surf_to_update
所做的那样。 Then, inside anime
you would have to use global surf_to_update
.然后,在anime
中你必须使用global surf_to_update
。 It is not the nicest solution, but it is definitely easier than keeping track of all the things you are adding/updating.这不是最好的解决方案,但它绝对比跟踪您正在添加/更新的所有内容更容易。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(111, projection='3d')
surf_to_update = ax.plot_surface(*plot(0), color="tab:blue")
def initialState(ax):
s=1.15
x_axis = np.array([s*5, 0, 0])
y_axis = np.array([0, s*5, 0])
z_axis = np.array([0, 0, s*5])
ax.quiver(0,0,0,*x_axis,color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*x_axis),'x',fontsize=10)
ax.quiver(0,0,0,*y_axis, color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*y_axis),'y',fontsize=10)
ax.quiver(0,0,0,*z_axis,color = 'k', alpha =1, arrow_length_ratio=0.05)
ax.text(*(s*z_axis),'z',fontsize=10)
# add the initial surface
surf0 = ax.plot_surface(*plot(0), color="tab:blue")
ax.set_xlim3d(-10, 10)
ax.set_ylim3d(-5, 5)
ax.set_zlim3d(-5, 5)
def plot(i):
X = np.arange(-5+i, 5+i, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
return [X,Y,Z]
def anime(i, stepFactor):
global surf_to_update
points = plot(i*stepFactor)
# remove the last surface added in the previous iteration
# (or in the init function)
surf_to_update.remove()
surf_to_update = ax.plot_surface(*points, color="tab:blue", alpha=0.5)
animation = FuncAnimation(
fig,
anime,
init_func=initialState(ax),
frames=range(100),
fargs=(0.1, )
)
plt.show()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.