Matplotlib三维图形

Matplotlib的3D功能通过mpl_toolkits.mplot3d模块实现。

1. 基本设置

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

# 创建3D坐标轴
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

2. 三维散点图

# 生成数据
np.random.seed(42)
n = 100
x = np.random.randn(n)
y = np.random.randn(n)
z = np.random.randn(n)

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 绘制散点图
scatter = ax.scatter(x, y, z, c=z, cmap='viridis', s=50, alpha=0.8)

# 添加标签和标题
ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
ax.set_title('三维散点图')

# 添加颜色条
plt.colorbar(scatter, ax=ax, label='Z值')

plt.show()

3. 三维线图

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 生成螺旋线数据
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)

# 绘制线图
ax.plot(x, y, z, 'b-', linewidth=2, label='螺旋线')
ax.scatter(x[::10], y[::10], z[::10], c='red', s=50)

ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
ax.set_title('三维线图 - 螺旋线')
ax.legend()

plt.show()

4. 三维曲面图

fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')

# 生成网格数据
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)

# 定义曲面函数 (Rastrigin函数)
Z = (X**2 - 10 * np.cos(2 * np.pi * X)) + \
    (Y**2 - 10 * np.cos(2 * np.pi * Y)) + 20

# 绘制曲面
surf = ax.plot_surface(X, Y, Z, cmap='coolwarm', 
                      alpha=0.8, antialiased=True)

# 添加等高线投影
ax.contour(X, Y, Z, 10, zdir='z', offset=Z.min(), 
           cmap='coolwarm', alpha=0.5)

ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
ax.set_title('三维曲面图')
plt.colorbar(surf, ax=ax, shrink=0.5, aspect=10)

plt.show()

5. 三维柱状图

fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')

# 生成数据
x = np.arange(5)
y = np.arange(5)
xpos, ypos = np.meshgrid(x, y)
xpos = xpos.flatten()
ypos = ypos.flatten()
zpos = np.zeros_like(xpos)

# 柱子的高度
dx = dy = 0.4 * np.ones_like(zpos)
dz = np.random.rand(25)

# 绘制柱状图
colors = plt.cm.viridis(dz / dz.max())
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=colors, 
         shade=True, alpha=0.8)

ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
ax.set_title('三维柱状图')

plt.show()

6. 三维等高线图

fig = plt.figure(figsize=(14, 6))

# 创建两个子图
ax1 = fig.add_subplot(121, projection='3d')
ax2 = fig.add_subplot(122, projection='3d')

# 生成数据
x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + Y**2)) * np.cos(2*np.pi*X) * np.cos(2*np.pi*Y)

# 子图1:3D等高线
ax1.plot_surface(X, Y, Z, cmap='viridis', alpha=0.6)
ax1.contour(X, Y, Z, 20, zdir='z', offset=Z.min(), 
            cmap='coolwarm', linewidths=1)
ax1.set_title('3D曲面+等高线投影')

# 子图2:3D线框
ax2.plot_wireframe(X, Y, Z, rstride=5, cstride=5, 
                   color='blue', linewidth=0.5)
ax2.contour(X, Y, Z, 15, zdir='z', offset=Z.min(), 
            colors='red', linewidths=1)
ax2.set_title('3D线框+等高线投影')

for ax in [ax1, ax2]:
    ax.set_xlabel('X轴')
    ax.set_ylabel('Y轴')
    ax.set_zlabel('Z轴')

plt.tight_layout()
plt.show()

7. 交互式视图控制

from matplotlib import animation

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

# 生成球形数据
u = np.linspace(0, 2 * np.pi, 50)
v = np.linspace(0, np.pi, 50)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))

# 绘制球体
ax.plot_surface(x, y, z, color='lightblue', alpha=0.6)
ax.set_box_aspect([1,1,1])  # 保持等比例

# 设置初始视角
ax.view_init(elev=20, azim=30)

def rotate(angle):
    ax.view_init(elev=20, azim=angle)
    
# 创建动画
ani = animation.FuncAnimation(fig, rotate, frames=np.arange(0, 360, 2), 
                             interval=50)

ax.set_xlabel('X轴')
ax.set_ylabel('Y轴')
ax.set_zlabel('Z轴')
ax.set_title('可旋转的3D球体')

# 保存动画
# ani.save('3d_rotation.gif', writer='pillow', fps=20)

plt.show()

8. 实用技巧

# 多个子图的3D图形
fig = plt.figure(figsize=(15, 10))

# 创建4个子图
for i in range(4):
    ax = fig.add_subplot(2, 2, i+1, projection='3d')
    
    # 生成不同的函数
    x = np.linspace(-3, 3, 50)
    y = np.linspace(-3, 3, 50)
    X, Y = np.meshgrid(x, y)
    
    if i == 0:
        Z = np.sin(np.sqrt(X**2 + Y**2))
        title = '波纹曲面'
        cmap = 'plasma'
    elif i == 1:
        Z = X**2 - Y**2
        title = '马鞍面'
        cmap = 'coolwarm'
    elif i == 2:
        Z = np.exp(-(X**2 + Y**2))
        title = '高斯曲面'
        cmap = 'viridis'
    else:
        Z = np.cos(X) * np.sin(Y)
        title = '周期曲面'
        cmap = 'RdYlBu'
    
    # 绘制
    surf = ax.plot_surface(X, Y, Z, cmap=cmap, alpha=0.8)
    ax.set_title(title)
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('Z')
    
    # 设置视角
    ax.view_init(elev=30, azim=45*i)

plt.tight_layout()
plt.show()

主要参数说明:

视角控制:

  • ax.view_init(elev=30, azim=45) – 设置仰角和方位角
  • elev – 仰角(上下看的角度)
  • azim – 方位角(左右旋转的角度)

坐标轴设置:

  • ax.set_xlim3d(left, right)
  • ax.set_ylim3d(bottom, top)
  • ax.set_zlim3d(zmin, zmax)
  • ax.set_box_aspect([1,1,1]) – 保持等比例

图形属性:

  • alpha – 透明度
  • rstridecstride – 曲面网格步长
  • linewidth – 线宽
  • antialiased – 抗锯齿

Matplotlib的3D功能适合基本的三维可视化,但对于复杂的三维场景或大数据集,建议考虑:

  • Mayavi – 更强大的3D可视化库
  • Plotly – 交互式3D可视化
  • PyVista – 专业级3D可视化