← 返回Book 2目录
第10章

等高线、网格、三角剖分

Contour, Grid & Triangulation · 二维函数的可视化艺术

从基础网格到高级剖分,掌握7种二维可视化技法

🗺️ 章节概览

等高线(Contour)是二维函数可视化的经典方法,通过连接函数值相等的点形成曲线, 直观展示函数的"地形"。本章系统讲解网格生成、等高线绘制、决策边界可视化、 几何变换,以及三角剖分(Triangulation)等7种技法, 广泛应用于地理学、气象学、机器学习等领域。

🌐
网格与等高线
meshgrid、contour
🎯
决策边界
分类模型可视化
🔄
几何变换
线性与非线性
🔺
三角剖分
Delaunay、网格细化
10.1

网格数据

numpy.meshgrid()生成二维和三维网格坐标

🌐 numpy.meshgrid()函数

  • • 图1:numpy.meshgrid()生成二维网格数据(将两个一维数组转换为多维坐标矩阵)
  • • 图2:三维空间看二维网格状坐标
  • • 用途:网格状坐标用于绘制网格曲面、等高线等(图3)

🎛️ 颗粒度

  • • 图4:颗粒度低(网格稀疏,可视化效果不理想)
  • • 图5:颗粒度过高(计算量大,本书将分别从等高线、网格曲面等几个角度继续颗粒度)

🎭 使用面具(mask)

  • • 图6:对于网格数据可以使用面具(mask),显示不同于满足条件的部分网格数据

🔺 三维网格与三角剖分

  • • 图7:三维网格(除了方正正方网格,本系列从还会介绍极坐标网格、三角网格)
  • • 图8:极坐标网格(先后首先从极坐标标转化为平面直角坐标网格,最后再转换为平面直角坐标标网格坐标,从numpy.linspace()生成极数、极轴的数组,然后用numpy.meshgrid()生成极坐标网格坐标)
  • • 图9:Delaunay三角剖分(matplotlib.tri提供了多种方便的工具和函数,使用户尸可以方便地进行可视化和分析)
  • • 图10:三角网格(matplotlib.tri可以创建三角网格,可以使用Triangulation类从定义的点集中创建一个三角网格,也可以使用其他函数生成各种类型的网格,如Delaunay三角剖分等)
10.2

等高线

平面等高线、三维等高线的绘制和应用

📏 等高线原理

  • • 等高线图是一种展示三维数据的方式,其中相同数值的数据点被连接成曲线,形成轮廓线
  • • 图11:二元函数相当于一座山峰,在平行于x₁x₂平面在特定高度切一刀,得到的轮廓线就是一条等高线
  • • 一系列轮廓线的高度一般不同高度(图12、13)

🏷️ 给等高线做注释

  • • 图14:给等高线做注释
  • • 图15:单色等高线

🎨 填充等高线

  • • matplotlib.pyplot.contourf():函数contourf是Matplotlib库中用于绘制等高线填充图的函数
  • • 图16:填充等高线原理(其原理是通过将数据转换为等高线线段的集合,然后根据某中每个等高线所在的区域填充,将具有根据指定的colormap进行选择)
  • • 图17:平面填充等高线
  • • 参数控制:levels参数来控制填充等级数量和大小,alpha参数来控制填充颜色的透明度,extend参数来控制在levels范围之外的值应如何处理

🤖 机器学习应用:决策边界

  • • 图23:在机器学习中,填充等高线常被用来绘制决策边界(分类尾花数据集、朴素贝叶斯两方法分类鸢尾花数据集的决策边界)

📊 颗粒度

  • • 前文提过,绘制连续等高线基于网格数据的颗粒度是否平滑,也就是关于网格数据提的颗粒度是否平滑细腻
  • • 图18:绘制等高线采用的网格提据颗粒度然过于粗糙,这导致不管是二维等高线,还是平面等高线都非常粗糙

🗺️ 等高线实验室(Contour Lab)

通过调整参数,理解等高线如何展示函数的"地形"

抛物面: z = x² + y²

🔍 等高线洞察

🔵 抛物面:同心圆等高线
📈 梯度方向:径向向外
等高线间距均匀 → 梯度恒定
✅ 等高线数量适中

🧪 探索建议

  • • 调整等高线层数,观察细节变化
  • • 开启填充,看颜色编码函数值
  • • 开启梯度箭头,理解梯度方向
  • • 切换函数类型,比较不同地形

🎭 函数类型

10
粗糙(3)精细(30)
50×50

📊 函数值范围

最小值 (z_min):0.007
最大值 (z_max):18.000
范围:17.993

📚 等高线理论

等高线定义
对于函数 z = f(x, y),等高线是满足 f(x, y) = c(常数)的点的集合。
contour: f(x, y) = c₁, c₂, ..., cₙ
梯度与等高线
  • • 梯度 ∇f 垂直于等高线
  • • 梯度方向:函数增长最快方向
  • • 梯度大小:等高线密集程度
  • • 等高线密集 → 梯度大 → 陡峭
等高线性质
  • • 等高线永不相交(除非奇点)
  • • 闭合曲线表示局部极值
  • • 间距反映梯度大小
  • • 鞍点处等高线呈"X"形
应用场景
  • • 地理:地形图海拔线
  • • 气象:等压线、等温线
  • • 优化:损失函数景观
  • • 物理:电势、磁场分布
🎯 学习目标:通过动手调整参数,理解等高线如何将三维函数压缩到二维平面。 观察不同函数的"地形"特征,建立等高线密度与梯度大小的关联。
📚 Python绘图代码(基于Ch10原文)
# ===== 示例1:等高线原理 =====
import numpy as np
import matplotlib.pyplot as plt
from sympy import lambdify, exp
from sympy.abc import x, y

# 定义peaks函数(MATLAB经典函数)
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)

# 生成网格
xx, yy = np.meshgrid(
    np.linspace(-3, 3, 121),
    np.linspace(-3, 3, 121)
)
ff = f_xy_fcn(xx, yy)

# 三维等高线
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# 绘制曲面网格
ax.plot_wireframe(xx, yy, ff,
                  color=[0.6, 0.6, 0.6],
                  rstride=5, cstride=5,
                  linewidth=0.25)

# 绘制等高线(在z=2的平面)
ax.contour(xx, yy, ff,
          levels=[2],
          colors='b',
          linewidths=1)

ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
ax.set_zlabel('$f(x_1, x_2)$')
ax.view_init(azim=-120, elev=30)
plt.show()


# ===== 示例2:平面等高线(不同颗粒度) =====
# 低颗粒度(粗糙)
xx_coarse, yy_coarse = np.meshgrid(
    np.linspace(-3, 3, 7),
    np.linspace(-3, 3, 7)
)
ff_coarse = f_xy_fcn(xx_coarse, yy_coarse)

fig, ax = plt.subplots()
ax.scatter(xx_coarse, yy_coarse, marker='.', color='k')
CS = ax.contour(xx_coarse, yy_coarse, ff_coarse,
               levels=np.linspace(-8, 9, 18),
               cmap='RdYlBu_r',
               linewidths=1)
ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
plt.show()

# 高颗粒度(精细)
xx_fine, yy_fine = np.meshgrid(
    np.linspace(-3, 3, 101),
    np.linspace(-3, 3, 101)
)
ff_fine = f_xy_fcn(xx_fine, yy_fine)

fig, ax = plt.subplots()
CS = ax.contour(xx_fine, yy_fine, ff_fine,
               levels=np.linspace(-8, 9, 18),
               cmap='RdYlBu_r',
               linewidths=1)
ax.clabel(CS, inline=True, fontsize=8)
plt.show()


# ===== 示例3:填充等高线(contourf) =====
fig, ax = plt.subplots()
CS = ax.contourf(xx_fine, yy_fine, ff_fine,
                levels=np.linspace(-8, 8, 17),
                cmap='RdYlBu_r')
fig.colorbar(CS)
ax.set_xlabel('$x_1$')
ax.set_ylabel('$x_2$')
plt.show()


# 💡 关键学习点:
# 1. meshgrid()生成二维网格:点数越多,等高线越平滑
# 2. contour()绘制等高线:levels参数控制等高线数量
# 3. contourf()绘制填充等高线:展示数值分布
# 4. clabel()添加等高线标签:显示具体数值
# 5. 颗粒度影响:网格太粗会导致等高线失真

🎯 决策边界动画器(Decision Boundary Animator)

观察分类器决策边界的逐步形成过程

线性分类器类别 A类别 B
0%
速度1x

🔍 观察要点

  • • 注意决策边界如何分隔两类数据
  • • 观察不同分类器的边界形状
  • • 线性边界:直线或超平面
  • • 非线性边界:曲线或复杂形状

🤖 分类器类型

📊 分类特性

✓ 简单高效,可解释性强
✓ 适合线性可分数据
⚠️ 无法处理非线性问题

📐 数学原理

线性分类器:
f(x) = w·x + b
决策边界:f(x) = 0

🎯 应用场景

  • • 图像分类:猫vs狗
  • • 垃圾邮件检测
  • • 医疗诊断辅助
  • • 信用评分

📚 决策边界理论

📏
线性可分
两类数据可用直线(2D)或超平面(高维)完全分开
🌀
非线性可分
需要曲线边界,通过核技巧或神经网络实现
⚖️
复杂度权衡
简单模型欠拟合,复杂模型过拟合,需要平衡
🎓 核心概念
• 支持向量机(SVM):最大化边界间隔
• 核技巧:映射到高维空间
• 正则化:防止过拟合
• 软间隔:容忍少量误分类
📚 Python绘图代码(基于Ch10原文)
# ===== 决策边界可视化 =====
import numpy as np
from matplotlib import pyplot as plt
from sklearn import neighbors, datasets
from matplotlib.colors import ListedColormap
from sklearn.naive_bayes import GaussianNB
from sklearn.tree import DecisionTreeClassifier

# 创建色谱(3类分类问题)
cmap_light = ListedColormap(['#FFAAAA', '#AAFFAA', '#AAAAFF'])
cmap_bold = ListedColormap(['#FF0000', '#00FF00', '#0000FF'])

# 加载鸢尾花数据
iris = datasets.load_iris()
X = iris.data[:, :2]  # 只取前两个特征(花萼长度、宽度)
y = iris.target

# 定义绘图网格范围
x_min, x_max = 4, 8
y_min, y_max = 2, 5
xx, yy = np.meshgrid(
    np.linspace(x_min, x_max, 1000),
    np.linspace(y_min, y_max, 100)
)


# ===== 示例1:决策树分类器 =====
clf_tree = DecisionTreeClassifier(max_depth=5)
clf_tree.fit(X, y)

# 预测网格点的类别
Z = clf_tree.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

# 绘制决策边界(填充等高线)
fig, ax = plt.subplots(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=cmap_light)

# 绘制训练样本点
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold)
plt.xlabel('Sepal length (cm)')
plt.ylabel('Sepal width (cm)')
plt.title('Decision Tree Classifier')
plt.axis('tight')
plt.show()


# ===== 示例2:朴素贝叶斯分类器 =====
clf_nb = GaussianNB()
clf_nb.fit(X, y)

Z = clf_nb.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

fig, ax = plt.subplots(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=cmap_light)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold)
plt.xlabel('Sepal length (cm)')
plt.ylabel('Sepal width (cm)')
plt.title('Gaussian Naive Bayes')
plt.axis('tight')
plt.show()


# ===== 示例3:KNN分类器 =====
clf_knn = neighbors.KNeighborsClassifier(n_neighbors=15)
clf_knn.fit(X, y)

Z = clf_knn.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)

fig, ax = plt.subplots(figsize=(8, 6))
plt.contourf(xx, yy, Z, cmap=cmap_light)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap_bold, edgecolors='k')
plt.xlabel('Sepal length (cm)')
plt.ylabel('Sepal width (cm)')
plt.title('KNN (k=15) Classifier')
plt.axis('tight')
plt.show()


# 💡 关键学习点:
# 1. contourf()绘制决策边界:展示分类器的决策区域
# 2. meshgrid()生成密集网格:覆盖整个特征空间
# 3. predict()预测每个网格点:确定决策边界
# 4. ListedColormap自定义色谱:区分不同类别
# 5. 决策边界形状反映分类器特性:
#    - 决策树:矩形分割
#    - 朴素贝叶斯:平滑曲线
#    - KNN:局部敏感的边界
10.3

三角剖分

Delaunay三角剖分与等高线可视化

🔺 Delaunay三角剖分

  • • 定义:Delaunay triangulation是计算几何中的一个重要概念,用于将给定的几何形状剖分为一组不重叠的三角形,它的名字来源于它的发明者Boris Delaunay
  • • 详细说明:三角剖分的目标是将一个多边形或多边形的集合分割成一组互不相交的三角形,使得这些三角形的顶点恰好是原始几何形状的顶点,并且任意两个三角形之间的交集只能是共享一个边或顶点
  • • Delaunay三角剖分:计算机图形学、计算几何和计算机视觉中常用的技术之一,它在三维重建、图像处理、自然语言处理、机器学习等领域都有广泛的应用

📦 matplotlib.tri模块

  • • matplotlib.tri:Matplotlib中的一个模块,提供了三角剖分的绘图功能
  • • scipy.spatial:中的Delaunay类可以帮助我们生成一个点集的Delaunay三角剖分,它可以用于构建三角形网格、寻找最近邻等等

🎨 三角网格可视化

  • • 图21(a):网格可以手动设定,也可以自动生成。自动生成的三角网格采用Delaunay三角剖分。三角网格可以帮助我们绘制各种类型的三角形网格,例如等高线图、三角形色块图和三角形曲面图等
  • • 图21(b):三角网格等高线图

🎛️ 颗粒度

  • • 图22:三角网格颗粒度(small triangles = 4, 16, 64)
  • • 细化次数:三角网格可以通过多次细化提高颗粒度。前后细化五次就得到三角网格(图21b),颗粒度越高,三角网格也越密集,对基本计算矩阵
  • • matplotlib.tri.Triangulation():简称tri.Triangulation(),根据给定的边和顶点生成的三角形,corners中有三个点
  • • matplotlib.tri.UniformTriRefiner():简称tri.UniformTriRefiner(),将三角形网格均匀细化若干次
  • • refiner.refine_triangulation():参数subdiv控制三角形网格的细化次数,我们可以看到每细化一次就会得到更密的三角网格
  • • matplotlib.pyplot.subplot():简称plt.subplot(),创建1行4列子图,并在第idx小开始绘制子图序
  • • matplotlib.pyplot.triplot():简称plt.triplot(),绘制三角剖分线条图

🤖 决策边界应用

  • • 图23:利用contourf()绘制决策边界等高线(两种不同的决策边界可视化)

🔄 线性与非线性变换

  • • 图24:线性、非线性变换,利用contour绘制,第1组(6种不同的网格变换模式)
  • • 图25:线性、非线性变换,利用contour绘制,第2组(6种不同的网格变换模式)

📚 章节总结

网格与等高线

  • ✓ meshgrid:生成坐标网格
  • ✓ contour:等高线
  • ✓ contourf:填充等高线
  • ✓ 颗粒度:控制层数和平滑度

决策边界与变换

  • ✓ 决策边界:分类器可视化
  • ✓ 线性变换:旋转、缩放
  • ✓ 非线性变换:极坐标、对数
  • ✓ 应用:机器学习模型理解

三角剖分

  • ✓ Delaunay:最优三角剖分
  • ✓ Voronoi图:对偶结构
  • ✓ 网格细化:颗粒度控制
  • ✓ 应用:有限元、地形建模

💡 核心洞察: 等高线将三维信息压缩到二维平面,通过"等值线"直观展示函数的变化趋势。 在地理学中,等高线表示海拔;在气象学中,等压线、等温线描述气象场; 在机器学习中,决策边界可视化模型的分类逻辑。三角剖分则为不规则数据提供了 结构化网格,是有限元分析、计算几何的基础。

🎓核心概念解析

等高线(Contour)

• 定义:函数 z = f(x, y) 值相等的点连成的曲线
• 数学:f(x, y) = c(c为常数)
• 特性:等高线永不相交
• 密集程度反映梯度大小

网格生成

x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
生成规则网格用于函数计算

决策边界

• 分类器输出概率 P(y=1|x) = 0.5 的边界
• 线性分类器:直线或超平面
• 非线性:SVM、神经网络的复杂边界

三角剖分原理

• Delaunay三角剖分:最大化最小角
• 性质:任何三角形外接圆内不包含其他点
• 对偶:Voronoi图(每个点的影响区域)
• 应用:地形建模、有限元网格

几何变换

• 线性变换:矩阵乘法
[x', y'] = A · [x, y]
• 非线性变换:极坐标、对数
r = √(x²+y²), θ = atan2(y,x)

颗粒度控制

• 等高线:levels参数控制层数
• 网格:meshgrid点数影响平滑度
• 三角剖分:细化次数控制精度

💻关键函数速查表

网格生成

np.meshgrid(x, y)
np.mgrid[x1:x2:step, y1:y2:step]
np.ogrid[x1:x2:step, y1:y2:step]

等高线绘制

plt.contour(X, Y, Z, levels=10)
plt.contourf(X, Y, Z, levels=10, cmap='viridis')
plt.clabel(CS, inline=True, fontsize=10)

三角剖分

from scipy.spatial import Delaunay
tri = Delaunay(points)
plt.triplot(x, y, tri.simplices)

🌍应用场景

🗺️
地理与地形
等高线地图展示海拔变化,地形起伏一目了然。 三角剖分用于数字地形模型(DTM)建模。
🌡️
气象学
等压线、等温线描述气象场分布, 帮助气象学家分析天气系统和预测趋势。
🤖
机器学习
决策边界可视化分类器的分类逻辑, 理解模型如何划分不同类别的样本。
⚙️
工程仿真
有限元分析(FEA)使用三角网格, 计算结构应力、热传导等物理场。
🎨
图形学与CAD
三角剖分用于曲面建模、网格简化、 纹理映射等计算机图形学应用。
📊
数据可视化
不规则散点数据插值后用等高线展示, 揭示数据的空间分布模式。

📖 延伸阅读

理论基础

  • • 多元函数微积分:梯度、方向导数
  • • 计算几何:Delaunay三角剖分、Voronoi图
  • • 数值分析:插值方法、网格细化
  • • 拓扑学:网格连接性、边界检测

高级主题

  • • 有限元方法(FEM):结构分析、流体仿真
  • • 地理信息系统(GIS):空间数据可视化
  • • 计算流体力学(CFD):流场可视化
  • • 3D重建:点云三角化、曲面拟合