You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:55:04