Matplotlib Animation:创建sin(x/2)绕y轴旋转体及np.arcsin疑问
为什么用np.arcsin无法创建sin(x/2)绕y轴的旋转体?
我正在尝试为函数sin(x/2)在x∈[0, 2π]区间内创建绕y轴的旋转体动画,目前已成功实现该函数绕x轴的旋转体动画(效果如图1),对应的代码如下:
import gif import numpy as np import matplotlib.pyplot as plt import mpl_toolkits.mplot3d.axes3d as axes3d @gif.frame def plot_volume(angle): fig = plt.figure(figsize = (20, 15)) ax2 = fig.add_subplot(1, 1, 1, projection = '3d') angles = np.linspace(0, 360, 20) x = np.linspace(0, 2*np.pi, 60) v = np.linspace(0, 2*angle, 60) U, V = np.meshgrid(x, v) Y1 = np.sin(U/2)*np.cos(V) Z1 = np.sin(U/2)*np.sin(V) X = U ax2.plot_surface(X, Y1, Z1, alpha = 0.2, color = 'blue', rstride = 6, cstride = 6) ax2.set_xlim(-3,3) ax2.set_ylim(-3,3) ax2.set_zlim(-3,3) ax2.view_init(elev = 50, azim = 30*angle) ax2.plot_wireframe(X, Y1, Z1, color = 'black') ax2._axis3don = False frames = [] for i in np.linspace(0, 4*np.pi, 20): frame = plot_volume(i) frames.append(frame) gif.save(frames, '/home/browni/LasthrimProjection/Python/solidofrevolutionxaxis.gif', duration = 500)
但尝试用np.arcsin作为正弦函数的逆函数编写绕y轴旋转的代码时,生成的结果不符合预期(应为半环形,实际效果如图2),现询问:为什么np.arcsin无法用于创建sin(x/2)绕y轴的旋转体?
失败代码如下:
import gif import numpy as np import matplotlib.pyplot as plt import mpl_toolkits.mplot3d.axes3d as axes3d @gif.frame def plot_volume(angle): fig = plt.figure(figsize = (20, 15)) ax2 = fig.add_subplot(1, 1, 1, projection = '3d') angles = np.linspace(0, 360, 20) x = np.linspace(0, 1, 60) v = np.linspace(0, 2*angle, 60) U, V = np.meshgrid(x, v) Y1 = 2*np.arcsin(U)*np.cos(V) Z1 = 2*np.arcsin(U)*np.sin(V) X = U ax2.plot_surface(X, Y1, Z1, alpha = 0.2, color = 'blue', rstride = 6, cstride = 6) ax2.set_xlim(-3,3) ax2.set_ylim(-3,3) ax2.set_zlim(-3,3) ax2.view_init(elev = 50, azim = 30*angle) ax2.plot_wireframe(X, Y1, Z1, color = 'black') ax2._axis3don = False frames = [] for i in np.linspace(0, 4*np.pi, 20): frame = plot_volume(i) frames.append(frame) gif.save(frames, '/home/browni/LasthrimProjection/Python/solidofrevolutionyaxis.gif', duration = 500)
核心原因:原函数非单调,np.arcsin只能取到一半的解
函数y = sin(x/2)在x∈[0, 2π]区间内并非单调函数:
- 当
x∈[0, π]时,x/2∈[0, π/2],y从0递增到1; - 当
x∈[π, 2π]时,x/2∈[π/2, π],y从1递减回0。
也就是说,对于每个y∈(0,1),存在两个不同的x值对应:x₁=2arcsin(y)(对应左半支)和x₂=2π-2arcsin(y)(对应右半支)。
而np.arcsin的取值范围是[-π/2, π/2],因此2np.arcsin(y)的范围是[-π, π],当y∈[0,1]时,它只能得到x∈[0, π]的左半支,完全丢失了x∈[π, 2π]的右半支。这就是你生成的旋转体形状错误的原因——只旋转了原函数的一半曲线,自然得不到完整的半环形。
正确的绕y轴旋转实现思路
绕y轴旋转时,无需反解函数,直接基于原函数的参数x构建旋转体的3D坐标即可:
原函数上的任意点为(x, y)=(x, sin(x/2)),绕y轴旋转时,该点会形成一个以y轴为中心、半径为x的圆,对应的3D参数方程为:
X = x * cos(v)(旋转后的x坐标,v为旋转角度)Z = x * sin(v)(旋转后的z坐标)Y = sin(x/2)(y坐标保持不变)
基于此修改的代码如下:
import gif import numpy as np import matplotlib.pyplot as plt import mpl_toolkits.mplot3d.axes3d as axes3d @gif.frame def plot_volume(angle): fig = plt.figure(figsize=(20, 15)) ax2 = fig.add_subplot(1, 1, 1, projection='3d') x = np.linspace(0, 2*np.pi, 60) # 控制当前旋转的角度范围,从0到angle v = np.linspace(0, angle, 60) U, V = np.meshgrid(x, v) # 绕y轴旋转的坐标计算 X = U * np.cos(V) Z = U * np.sin(V) Y = np.sin(U/2) ax2.plot_surface(X, Y, Z, alpha=0.2, color='blue', rstride=6, cstride=6) ax2.plot_wireframe(X, Y, Z, color='black') ax2.set_xlim(-7,7) ax2.set_ylim(-1,1) ax2.set_zlim(-7,7) ax2.view_init(elev=50, azim=30*(angle/(2*np.pi))) ax2._axis3don = False frames = [] # 旋转一周,角度从0到2π for i in np.linspace(0, 2*np.pi, 20): frame = plot_volume(i) frames.append(frame) gif.save(frames, '/home/browni/LasthrimProjection/Python/solidofrevolutionyaxis.gif', duration=500)
这段代码直接遍历原函数的x参数,通过旋转角度v生成完整的旋转曲面,能得到你预期的半环形旋转体动画。
内容的提问来源于stack exchange,提问作者Freya the Goddess
相关产品推荐
相关产品推荐

