使用Python 3(可能是matplotlib)绘制旋转体图形

5

问候问题:

R是xy平面上由抛物线y=x^2+1和直线y=x+3所限定的区域。通过将R绕x轴旋转形成一个旋转固体。我需要在2D中绘制抛物线和直线,在3D中绘制旋转固体,如何实现? 我已经安装了Anaconda。


看起来你想让我们为你编写一些代码。虽然很多用户愿意帮助有困难的程序员编写代码,但他们通常只会在发帖者已经尝试过自己解决问题时才提供帮助。展示这种努力的好方法是包括你已经编写的代码、示例输入(如果有的话)、期望输出以及实际得到的输出(控制台输出、跟踪等)。提供的细节越多,你可能会收到更多的答案。请查看[FAQ]和[ask]。 - idjaw
2个回答

7

您可以使用plot_surface

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as axes3d

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection='3d')

u = np.linspace(-1, 2, 60)
v = np.linspace(0, 2*np.pi, 60)
U, V = np.meshgrid(u, v)

X = U
Y1 = (U**2 + 1)*np.cos(V)
Z1 = (U**2 + 1)*np.sin(V)

Y2 = (U + 3)*np.cos(V)
Z2 = (U + 3)*np.sin(V)

ax.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
ax.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
plt.show()

enter image description here

要使用plot_surface绘制表面,您需要确定两个一维参数uv

u = np.linspace(-1, 2, 60)
v = np.linspace(0, 2*np.pi, 60)

假设 x, y, z 是参数 uv 的函数:

x = x(u, v)
y = y(u, v)
z = z(u, v)

注意关于ax.plot_surface的一件事是它的前三个参数必须是2D数组。因此,我们使用np.meshgrid将坐标向量(uv)创建为坐标矩阵(UV),并定义2D数组XYZ作为UV的函数:
X = U
Y1 = (U**2 + 1)*np.cos(V)
Z1 = (U**2 + 1)*np.sin(V)

对于坐标矩阵 UV 上的每个位置,都有相应的 XYZ 值。这创建了一个从二维 uv 空间到三维 xyz 空间的映射。对于 uv 空间中的每个矩形,在 xyz 空间中都有一个表面。由 plot_surface 绘制的曲面由这些平面组成。

你的答案是关于x轴的。你能帮我找到关于y轴的旋转固体吗? - haccks
@haccks:使用上述代码,只需将 ax.plot_surface(X, Y1, Z1,...) 更改为 ax.plot_surface(Y1, X, Z1,...),并对第二个 ax.plot_surface 调用进行类似操作。哇,旋转曲面现在将围绕 y 轴。当然,X 现在扮演 "y" 的角色,而 Y1Y2 现在是 "x" 值,因此为了清晰起见,您还需要更改变量名称。但是,通过简单地 "交换" XY 变量即可实现结果。 - unutbu
你是指逆函数吗? - haccks
是的。找到将 x 表示为 y 的反函数。然后用 U 替换 y。在 X = (...)*np.cos(V) 中使用它来代替 (...) - unutbu
是的。对于像 y = x**2y = 3*x + 5 这样的函数是可行的。但是对于像 y = x**3 + x**2 这样的函数就不行了。你无法找到这个多项式的反函数(据我所知)。 - haccks
显示剩余6条评论

0
借鉴以上内容,你可以使用组件或 GIF 使之动态化。
制作 GIF:使用 GIF 包:
import gif

@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(-1, 2, 60)
    v = np.linspace(0, 2*angle, 60)

    U, V = np.meshgrid(x, v)
    Y1 = (U**2 + 1)*np.cos(V)
    Z1 = (U**2 + 1)*np.sin(V)
    Y2 = (U + 3)*np.cos(V)
    Z2 = (U + 3)*np.sin(V)
    X = U
    ax2.plot_surface(X, Y1, Z1, alpha = 0.2, color = 'blue', rstride = 6, cstride = 6)
    ax2.plot_surface(X, Y2, Z2, alpha = 0.2, color = 'red', rstride = 6, cstride = 6)
    ax2.set_xlim(-3,3)
    ax2.set_ylim(-5,5)
    ax2.set_zlim(-5,5)
    ax2.view_init(elev = 50, azim = 30*angle)
    ax2.plot_wireframe(X, Y2, Z2)
    ax2.plot_wireframe(X, Y1, Z1, color = 'black')
    ax2._axis3don = False

frames = []
for i in np.linspace(0, 2*np.pi, 20):
    frame = plot_volume(i)
    frames.append(frame)

gif.save(frames, 'images/vol1.gif', duration = 500)

from IPython.display import Image

Image('images/vol1.gif')

交互式编程: 使用 ipywidgets。

def three_d_plotter(angle, rotate, turn):
    fig = plt.figure(figsize = (13, 6))
    ax = fig.add_subplot(1, 1, 1, projection='3d')

    u = np.linspace(-1, 2, 60)
    v = np.linspace(0, angle, 60)
    U, V = np.meshgrid(u, v)

    X = U
    Y1 = (U**2 + 1)*np.cos(V)
    Z1 = (U**2 + 1)*np.sin(V)

    Y2 = (U + 3)*np.cos(V)
    Z2 = (U + 3)*np.sin(V)

    ax.plot_surface(X, Y1, Z1, alpha=0.3, color='red', rstride=6, cstride=12)
    ax.plot_surface(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
    ax.plot_wireframe(X, Y2, Z2, alpha=0.3, color='blue', rstride=6, cstride=12)
    ax._axis3don = False
    ax.view_init(elev = rotate, azim = turn)

    plt.show()

from ipywidgets import interact
import ipywidgets as widgets

interact(three_d_plotter, angle = widgets.FloatSlider(0, min = 0, max = 2*np.pi, step = np.pi/10),
        rotate = widgets.FloatSlider(0, min = 0, max = 360, step = 5),
         turn = widgets.FloatSlider(0, min = 0, max = 500, step = 5))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接