![Figure_1]()
import numpy as np
import matplotlib.pyplot as plt
# 全局中文设置
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 生成基础网格
x = np.linspace(-1, 2, 10)
y = np.linspace(-1, 2, 10)
X, Y = np.meshgrid(x, y)
pts = np.vstack([X.ravel(), Y.ravel()])
# 5类线性变换,优化反射变换
transform_list = [
{
"name": "1. 轴向缩放变换\n两个正交特征方向,仅拉伸压缩",
"mat": np.array([[2, 0], [0, 0.5]]),
"color": "#dd3333"
},
{
"name": "2. 旋转变换\n无实特征向量,实数域不可对角化",
"mat": np.array([[np.cos(np.pi/6), -np.sin(np.pi/6)],
[np.sin(np.pi/6), np.cos(np.pi/6)]]),
"color": "#3366dd"
},
{
"name": "3. 反射变换(沿x轴镜像)\nx轴方向不变,y轴方向反向翻转",
"mat": np.array([[1, 0], [0, -1]]),
"color": "#9933dd",
"draw_sym": True # 绘制对称轴
},
{
"name": "4. 斜向拉伸(可对角化)\n表观剪切,换基可消除斜向形变",
"mat": np.array([[2, 1], [1, 2]]),
"color": "#ff7722"
},
{
"name": "5. 原生剪切变换\n仅1个实特征方向,无法对角化",
"mat": np.array([[1, 1.2], [0, 1]]),
"color": "#ddaa00"
}
]
# 布局:2行3列,隐藏最后一张空白子图
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
axes = axes.flatten()
axes[5].axis('off')
for idx, info in enumerate(transform_list):
ax = axes[idx]
A = info["mat"]
color = info["color"]
title = info["name"]
draw_sym = info.get("draw_sym", False)
# 原始网格
ax.plot(X, Y, c="gray", lw=0.6, alpha=0.4)
ax.plot(X.T, Y.T, c="gray", lw=0.6, alpha=0.4)
ax.scatter(pts[0], pts[1], s=14, c="gray", alpha=0.6, label="原始点")
# 矩阵变换
pts_trans = A @ pts
Xt = pts_trans[0].reshape(X.shape)
Yt = pts_trans[1].reshape(Y.shape)
# 变换后网格+带黑边散点
ax.plot(Xt, Yt, c=color, lw=0.7, alpha=0.5)
ax.plot(Xt.T, Yt.T, c=color, lw=0.7, alpha=0.5)
ax.scatter(pts_trans[0], pts_trans[1], s=16, c=color, alpha=0.8,
edgecolors="black", linewidth=0.2, label="变换后点")
# 反射变换绘制对称轴
if draw_sym:
ax.axhline(y=0, color='red', linestyle='--', lw=2, alpha=0.7, label='镜像对称轴(x轴)')
# 绘制实特征向量
eigvals, eigvecs = np.linalg.eig(A)
for i in range(2):
val = eigvals[i]
vec = eigvecs[:, i]
if np.isreal(val):
ax.arrow(0, 0, vec[0]*3, vec[1]*3, head_width=0.08, lw=2, color="blue", alpha=0.7)
ax.set_title(title, fontsize=11)
ax.set_aspect("equal")
ax.grid(alpha=0.3)
ax.legend(fontsize=8)
plt.tight_layout()
plt.show()
# 输出特征值
for info in transform_list:
vals = np.linalg.eigvals(info["mat"])
print(f"{info['name'].splitlines()[0]} 特征值:{vals.round(3)}")