在 Python 3 中绘制旋转实体(可能是 matplotlib)

Ploting solid of revolution in Python 3 (matplotlib maybe)

问候问题:

R 是 xy 平面中由抛物线 y=x^2+1 和线 y=x+3 界定的区域。通过绕 x 轴旋转 R 形成旋转体。我需要在 2D 和 solid revolution 3D 中绘制抛物线和直线,怎么做? 我安装了anaconda。

您可以使用 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()

要使用 plot_surface 绘制曲面,您首先要确定两个一维参数,uv:

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

使得 xyz 是参数 uv:

的函数
x = x(u, v)
y = y(u, v)
z = z(u, v)

关于 ax.plot_surface 需要注意的是它的前三个参数 必须是二维数组。所以我们使用 np.meshgrid 从坐标向量(uv)创建坐标矩阵(UV),并定义二维数组 X, Y, ZUV:

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

对于坐标矩阵UV上的每个位置,XYZ都有对应的值。这将创建一个从 2 维 uv-space 到 3 维 xyz-space 的映射。对于 uv-space 中的每个矩形,我们在 xyz-space 中的表面上都有一张脸。 plot_surface画出的曲面就是由这些平面构成的

借助上面的内容,您可以使用小部件或 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))