← 返回Book 2目录
第14章

三维曲面

3D Surface · 可视化连续函数曲面

从三维线图到曲面可视化,掌握6种高级三维技法

🌊 章节概览

三维曲面可视化是理解多元函数的关键工具。本章在Ch13三维散点图的基础上, 系统讲解三维线图、曲面图、投影、参考线、偏导数可视化、火柴梗图等6种高级技法。 通过曲面图,可以直观展示二元函数的形态、梯度、极值等特征。 偏导数可视化揭示了函数在不同方向上的变化率,火柴梗图则提供了独特的三维展示方式。

📈
三维线图
plot3D绘制曲线
🌊
曲面图
plot_surface函数
📐
投影与参考线
辅助理解曲面
∂
偏导数
微分可视化
14.1

三维线图

plot3D 在三维空间中绘制曲线

Python代码:BK_2_Ch14_1.ipynb

🌀 三维螺旋线动画器

参数方程生成的三维螺旋曲线 · 动态展示线图生成过程

进度: 100%

🌊 螺旋类型

旋转圈数24
仰角30°
方位角-135°

📐 参数方程

x = r · sin(θ)
y = r · cos(θ)
z = z(t)
r = z² + 1 (半径随高度平方增长)

💡 学习要点

  • • plot3D()绘制三维曲线
  • • 参数方程生成复杂曲线
  • • θ控制旋转,z控制高度
  • • r控制半径变化规律
📚 Python实现参考
# 螺旋线参数方程
theta = np.linspace(-24 * np.pi, 24 * np.pi, 1000)
z = np.linspace(-2, 2, 1000)
r = z**2 + 1  # 半径变化规律

x = r * np.sin(theta)
y = r * np.cos(theta)

# 绘制三维线图
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(projection='3d')
ax.plot(x, y, z)
ax.set_proj_type('ortho')
plt.show()
14.2

一元高斯分布概率密度

用三维曲面展示正态分布

Python代码:BK_2_Ch14_2.ipynb

📊 一元高斯分布参数动画器

观察正态分布随μ和σ变化的三维展示 · 参数对概率密度曲线的影响

xμf(x)

📐 变化参数

均值 μ0
控制分布的中心位置
仰角15°
方位角-145°

📐 高斯公式

f(x) = (1/(σ√(2π))) × exp(-(x-μ)²/(2σ²))
• μ:均值(峰值位置)
• σ:标准差(宽度)

💡 观察要点

  • • μ增大:曲线向右平移
  • • μ减小:曲线向左平移
  • • 曲线形状保持不变
  • • 峰值高度保持不变
📚 Python实现参考
# 一元高斯分布概率密度函数
def gaussian_1D(x_array, mu, sigma):
    z = (x_array - mu) / sigma
    factor = 1 / sigma / np.sqrt(2 * np.pi)
    PDF_array = factor * np.exp(-z**2 / 2)
    return PDF_array

# 创建数据
x_array = np.linspace(-8, 8, 121)
mu_array = np.arange(-4, 5)  # 均值变化
sigma = 1

# 绘制三维曲线族
fig, ax = plt.subplots(subplot_kw={'projection': '3d'})
colors = cm.rainbow(np.linspace(0, 1, num_lines))

for mu_idx, color_idx in zip(mu_array, colors):
    ax.plot(x_array,
           x_array*0 + mu_idx,
           gaussian_1D(x_array, mu_idx, 1),
           color=color_idx)

ax.view_init(azim=-145, elev=15)
plt.show()
14.3

投影

将三维曲面投影到坐标平面

Python代码:BK_2_Ch14_3.ipynb

🌊 三维曲面实验室(Surface Lab)

探索三维曲面的形态和参数影响

z = exp(-(x²+y²)/(2σ²))

🔍 曲面洞察

🔔 高斯曲面:钟形对称
σ = 1:控制曲面宽度
中心最高,四周平滑下降

🧪 探索建议

  • • 切换函数类型,观察不同曲面形态
  • • 调整视角,从多个角度观察曲面
  • • 改变渲染模式,理解网格结构
  • • 开启投影,看曲面在平面的映射

📊 函数类型

🎨 渲染模式

仰角30°
方位角45°
标准差 σ1.0
振幅1.0
网格密度20

📚 三维曲面理论

网格生成
meshgrid生成X, Y网格坐标,Z = f(X, Y)计算高度。 网格密度决定曲面平滑程度。
曲面形态
• 高斯:中心峰值,对称衰减
• 抛物面:碗状,有全局最小值
• 鞍点:马鞍形,原点既非极大也非极小
渲染方式
• surface:实心曲面,展示连续性
• wireframe:线框,清晰看到网格
• contour:等高线,平面投影
应用场景
✓ 机器学习损失函数可视化
✓ 地形高程图
✓ 概率密度函数
🎯 学习目标:通过调整参数和视角,理解三维曲面的几何特征。 观察不同函数的形态差异,建立函数与曲面的直觉联系。
📚 Python绘图代码(基于Ch14原文)
# ===== 示例1:三维线图(螺旋线) =====
import numpy as np
import matplotlib.pyplot as plt

# 创建参数方程数据
theta = np.linspace(-24 * np.pi, 24 * np.pi, 1000)
z = np.linspace(-2, 2, 1000)
r = z**2 + 1  # 半径随z变化

# 参数方程
x = r * np.sin(theta)
y = r * np.cos(theta)

# 绘制三维线图
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(projection='3d')
ax.plot(x, y, z)

ax.set_proj_type('ortho')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.grid(False)
plt.show()


# ===== 示例2:一元高斯分布概率密度(随μ变化) =====
from matplotlib import cm

def gaussian_1D(x_array, mu, sigma):
    z = (x_array - mu) / sigma
    factor = 1 / sigma / np.sqrt(2 * np.pi)
    PDF_array = factor * np.exp(-z**2 / 2)
    return PDF_array

# 创建数据
x_array = np.linspace(-8, 8, 121)
mu_array = np.arange(-4, 4 + 1)
num_lines = len(mu_array)

fig, ax = plt.subplots(subplot_kw={'projection': '3d'})

colors = cm.rainbow(np.linspace(0, 1, num_lines))

for mu_idx, color_idx in zip(mu_array, colors):
    ax.plot(x_array,                    # x 坐标
           x_array*0 + mu_idx,          # y 坐标
           gaussian_1D(x_array, mu_idx, 1),  # z 坐标
           color=color_idx)

ax.set(xlim=[x_array.min(), x_array.max()],
      ylim=[mu_array.min(), mu_array.max()])
ax.view_init(azim=-145, elev=15)
ax.set_proj_type('ortho')
ax.set_xlabel('$x$')
ax.set_ylabel(r'$\mu$')
ax.set_zlabel('$f_X(x)$')
ax.set_box_aspect((1, 1, 1))
ax.grid(False)
plt.show()


# ===== 示例3:曲面与投影曲线 =====
# 生成网格数据
grid = np.linspace(-3, 3)
xx1, xx2 = np.meshgrid(np.linspace(-3, 3), np.linspace(-3, 3))
ff = np.exp(-xx1**2 - xx2**2)  # 高斯函数

fig, ax = plt.subplots(subplot_kw={'projection': '3d'})

# 绘制曲面
ax.plot_wireframe(xx1, xx2, ff,
                 color=[0.3, 0.3, 0.3],
                 linewidth=0.25)

# 绘制投影曲线
ax.plot(grid,
       np.sqrt(np.pi) * np.exp(-grid**2),
       zs=3, zdir='x')  # x坐标固定为3
ax.plot(grid,
       np.sqrt(np.pi) * np.exp(-grid**2),
       zs=3, zdir='y')  # y坐标固定为3

ax.view_init(azim=-120, elev=30)
ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
ax.set_zlabel('$f(x_1,x_2)$')
ax.set_proj_type('ortho')
ax.set_box_aspect((1, 1, 1))
ax.grid(False)
plt.show()


# 💡 关键学习点:
# 1. plot()绘制三维线图:参数方程生成螺旋线
# 2. zs/zdir参数:控制投影方向('x', 'y', 'z')
# 3. plot_wireframe():绘制网格曲面
# 4. 多条曲线叠加:展示参数变化趋势
# 5. set_proj_type('ortho'):正交投影
14.4

参考线

添加辅助线帮助理解曲面

Python代码:BK_2_Ch14_4.ipynb
14.5

可视化偏导数

展示函数在不同方向的导数

Python代码:BK_2_Ch14_5.ipynb

∂ 偏导数动画器(Partial Derivative Animator)

观察函数在不同方向上的变化率

xz∂f/∂x 方向导数值: 0.00
0/50
速度1x

👀 观察要点

  • • 红点是基准点 (x₀, y₀, f(x₀,y₀))
  • • 蓝点沿x方向移动
  • • 橙色虚线是切线(斜率=偏导数)
  • • 切线斜率反映函数变化率

📐 偏导数方向

📍 基准点

x₀0.0
y₀0.0

📊 偏导数值

∂f/∂x = x/2
在 (0, 0): 0.00
∂f/∂y = y/2
在 (0, 0): 0.00

∇ 梯度向量

∇f = (0.00, 0.00)
梯度指向函数增长最快的方向

📚 偏导数概念

• ∂f/∂x:保持y不变,f对x的变化率
• ∂f/∂y:保持x不变,f对y的变化率
• 切线斜率:等于该点的偏导数值
• 梯度:由两个偏导数组成的向量

🎓 偏导数理论

∂
偏导数定义
偏导数是多元函数在某一方向上的瞬时变化率。 保持其他变量不变,只考虑一个变量的变化。
∇
梯度向量
梯度是由所有偏导数组成的向量,指向函数增长最快的方向。 梯度下降算法的核心。
📈
应用
• 优化算法(梯度下降)
• 神经网络反向传播
• 物理场分析
🎯 学习目标:通过观察点沿不同方向移动,理解偏导数的几何意义。 切线的斜率直观展示了函数在该方向的变化率。
📚 Python绘图代码(基于Ch14原文)
# ===== 示例:可视化偏导数(沿x和y方向切线) =====
import numpy as np
from sympy import lambdify, diff, exp
from sympy.abc import x, y
from matplotlib import pyplot as plt

# 创建网格数据
num = 301
x_array = np.linspace(-3, 3, num)
y_array = np.linspace(-3, 3, num)
xx, yy = np.meshgrid(x_array, y_array)

# 定义二元函数(MATLAB经典peaks函数)
f_xy = 3*(1-x)**2*exp(-(x**2) - (y+1)**2) \
    - 10*(x/5 - x**3 - y**5)*exp(-x**2-y**2) \
    - 1/3*exp(-(x+1)**2 - y**2)

f_xy_fcn = lambdify([x, y], f_xy)
f_xy_zz = f_xy_fcn(xx, yy)

# 计算偏导数(符号计算)
df_dx = f_xy.diff(x)  # 对x求偏导
df_dy = f_xy.diff(y)  # 对y求偏导

df_dx_fcn = lambdify([x, y], df_dx)
df_dy_fcn = lambdify([x, y], df_dy)

# 定义切点网格
x_s = np.linspace(-2.4, 2.4, 9)
y_s = np.linspace(-2.4, 2.4, 9)
xx_s, yy_s = np.meshgrid(x_s, y_s)


# ===== 沿x方向切线 =====
def plot_d_x_tangent(x_t, y_t, df_dx_fcn, f_xy_fcn, color, ax):
    # 计算切线斜率(偏导数)
    k = df_dx_fcn(x_t, y_t)
    # 切点z坐标
    z_t = f_xy_fcn(x_t, y_t)
    # 切线x轴数组
    x_array = np.linspace(x_t-0.6, x_t+0.6, 10)
    # 切线函数:z = k*(x - x_t) + z_t
    z_array = k*(x_array - x_t) + z_t
    
    # 绘制切线
    ax.plot(x_array, x_array*0 + y_t, z_array, 
           color=color, lw=0.2)
    # 绘制切点
    ax.plot(x_t, y_t, z_t, color=color, 
           marker='.', markersize=5)

fig, ax = plt.subplots(subplot_kw={'projection': '3d'})

# 绘制曲面(只显示沿x方向的网格线)
ax.plot_wireframe(xx, yy, f_xy_zz,
                 color=[0.5, 0.5, 0.5],
                 rstride=15, cstride=0,
                 linewidth=0.25)

# 绘制多条沿x方向的切线
colors = plt.cm.rainbow(np.linspace(0, 1, len(xx_s.ravel())))

for i in range(len(xx_s.ravel())):
    x_t = xx_s.ravel()[i]
    y_t = yy_s.ravel()[i]
    color = colors[i, :]
    plot_d_x_tangent(x_t, y_t, df_dx_fcn, f_xy_fcn, color, ax)

ax.set_proj_type('ortho')
ax.view_init(azim=-135, elev=30)
ax.grid(False)
plt.show()


# ===== 沿y方向切线 =====
def plot_d_y_tangent(x_t, y_t, df_dy_fcn, f_xy_fcn, color, ax):
    k = df_dy_fcn(x_t, y_t)
    z_t = f_xy_fcn(x_t, y_t)
    
    y_array = np.linspace(y_t-0.6, y_t+0.6, 10)
    z_array = k*(y_array - y_t) + z_t
    
    ax.plot(y_array*0 + x_t, y_array, z_array, 
           color=color, lw=0.2)
    ax.plot(x_t, y_t, z_t, color=color, 
           marker='.', markersize=5)

fig, ax = plt.subplots(subplot_kw={'projection': '3d'})

# 绘制曲面(只显示沿y方向的网格线)
ax.plot_wireframe(xx, yy, f_xy_zz,
                 color=[0.5, 0.5, 0.5],
                 rstride=0, cstride=15,
                 linewidth=0.25)

colors = plt.cm.rainbow(np.linspace(0, 1, len(yy_s.ravel())))

for i in range(len(yy_s.ravel())):
    x_t = xx_s.ravel()[i]
    y_t = yy_s.ravel()[i]
    color = colors[i, :]
    plot_d_y_tangent(x_t, y_t, df_dy_fcn, f_xy_fcn, color, ax)

ax.set_proj_type('ortho')
ax.view_init(azim=-135, elev=30)
ax.grid(False)
plt.show()


# 💡 关键学习点:
# 1. sympy.diff():符号求导,计算偏导数
# 2. lambdify():将符号表达式转为数值函数
# 3. 偏导数几何意义:曲面沿某方向的切线斜率
# 4. ∂f/∂x:固定y,沿x方向的变化率
# 5. ∂f/∂y:固定x,沿y方向的变化率
14.6

火柴梗图

stem3D 创造独特的三维展示

Python代码:BK_2_Ch14_6.ipynb

🎯 火柴梗图动画器 (Stem3D)

多项式分布的三维火柴梗可视化 · 调整概率参数观察分布变化

x₁x₂
显示 136 个有效样本点
p₁ = 0.15
p₂ = 0.35
p₃ = 0.50

📊 火柴梗方向

概率 p₁0.15
概率 p₂0.35
概率 p₃0.50
自动计算:p₃ = 1 - p₁ - p₂
样本数 n15
x₁ + x₂ + x₃ = 15
仰角30°
方位角30°

📐 多项式分布

PMF(x₁,x₂,x₃) =
(n! / (x₁!x₂!x₃!))
× p₁^x₁ × p₂^x₂ × p₃^x₃

💡 学习要点

  • • stem3D()绘制火柴梗图
  • • 火柴梗高度=概率密度
  • • orientation控制延伸方向
  • • 适合展示离散分布
📚 Python实现参考
from scipy.stats import multinomial

p_array = [0.15, 0.35, 0.50]
num = 15

x1_array = np.arange(num + 1)
x2_array = np.arange(num + 1)
xx1, xx2 = np.meshgrid(x1_array, x2_array)

xx3 = num - xx1 - xx2
xx3 = np.where(xx3 >= 0.0, xx3, np.nan)

PMF_ff = multinomial.pmf(
    x=np.array(([xx1.ravel(), xx2.ravel(), xx3.ravel()])).T,
    n=num, p=p_array
)

fig = plt.figure(figsize=(5, 5))
ax = plt.axes(projection="3d")

# 沿z轴绘制火柴梗
ax.stem(xx1.ravel(), xx2.ravel(), PMF_ff.ravel(), basefmt=" ")

ax.set_proj_type('ortho')
ax.view_init(azim=30, elev=30)
plt.show()

📚 章节总结

三维曲线与曲面

  • ✓ plot3D:三维线图
  • ✓ plot_surface:三维曲面
  • ✓ plot_wireframe:网格曲面
  • ✓ mesh网格:X, Y网格生成

辅助可视化

  • ✓ 投影:曲面到平面的映射
  • ✓ 参考线:等值线、切线
  • ✓ 等高线:contour3D
  • ✓ 火柴梗图:stem3D

数学应用

  • ✓ 概率密度:高斯分布曲面
  • ✓ 偏导数:方向导数可视化
  • ✓ 梯度:函数变化方向
  • ✓ 优化:损失函数曲面

💡 核心洞察: 三维曲面图将抽象的二元函数具象化为可见的几何形态。 通过观察曲面的起伏、凹凸、极值点,可以直观理解函数的性质。 偏导数揭示了函数在不同方向上的变化速率,是理解梯度下降等优化算法的关键。 投影和参考线则帮助我们在三维和二维之间建立联系,降低理解难度。

🎓核心概念解析

网格生成

• np.meshgrid(x, y):生成X, Y网格
• Z = f(X, Y):计算高度值
• 网格点数决定曲面平滑度
• 密集网格→精细曲面

曲面类型

• plot_surface:实心曲面
• plot_wireframe:线框曲面
• contour3D:三维等高线
• stem3D:火柴梗图

投影

• 将三维曲面投影到xy/xz/yz平面
• offset参数控制投影位置
• 帮助理解曲面的平面特征
• 常与等高线结合使用

偏导数

• ∂f/∂x:沿x方向的变化率
• ∂f/∂y:沿y方向的变化率
• 梯度向量:∇f = (∂f/∂x, ∂f/∂y)
• 指向函数增长最快的方向

高斯分布曲面

• f(x) = 1/(σ√(2π)) exp(-(x-μ)²/(2σ²))
• 钟形曲线的三维展示
• 峰值在μ处,宽度由σ控制
• 正态分布的几何直觉

火柴梗图

• 从xy平面垂直向上的线段
• 高度表示函数值
• 离散数据的独特展示
• 适合展示稀疏三维数据

💻关键函数速查表

曲面绘制

ax.plot_surface(X, Y, Z)
ax.plot_wireframe(X, Y, Z)
ax.contour3D(X, Y, Z)
ax.plot3D(x, y, z)

网格与数据

X, Y = np.meshgrid(x, y)
Z = f(X, Y)
np.gradient(Z)

特殊图形

ax.stem3D(x, y, z)
ax.contour(X, Y, Z, offset=z0)

📐 核心数学公式

偏导数
∂f/∂x = lim(h→0) [f(x+h,y) - f(x,y)] / h
∂f/∂y = lim(h→0) [f(x,y+h) - f(x,y)] / h
梯度向量
∇f(x,y) = (∂f/∂x, ∂f/∂y)
指向函数增长最快的方向
方向导数
D_u f = ∇f · u
u为单位方向向量
高斯函数
f(x) = (1/(σ√(2π))) exp(-(x-μ)²/(2σ²))

📂Python代码文件

本章内容对应以下Jupyter Notebook代码文件:

BK_2_Ch14_01.ipynb小节 14.1
BK_2_Ch14_02.ipynb小节 14.2
BK_2_Ch14_03.ipynb小节 14.3
BK_2_Ch14_04.ipynb小节 14.4
BK_2_Ch14_05.ipynb小节 14.5
BK_2_Ch14_06.ipynb小节 14.6
📁 代码位置:books/Book2_Beauty-of-Data-Visualization/Book2_Ch14_Python_Codes/

📖 延伸阅读

数学基础

  • • 多元微积分:偏导数、梯度、方向导数
  • • 向量分析:梯度、散度、旋度
  • • 微分几何:曲面的切平面、法向量
  • • 优化理论:梯度下降、牛顿法

实际应用

  • • 机器学习:损失函数曲面可视化
  • • 地理信息:地形高程图
  • • 物理模拟:势能面、电场分布
  • • 金融分析:期权价格曲面