1.4 視覺化工具箱:建立 linalg_viz.py#
本節目標#
- 建立貫穿全書的視覺化模組
linalg_viz.py - 寫出三個核心函數:
plot_vectors()、plot_transformation()、plot_unit_circle_transformed() - 學會在之後的章節 import 使用
為什麼需要工具箱#
之後每一章都會反覆做同樣的事:畫向量、畫變換前後的圖形。 與其在每章複製貼上程式碼,不如寫一個小模組。這也是真實軟體的工作方式。
完整程式碼:linalg_viz.py#
請在與各章 notebook 同一個資料夾建立 linalg_viz.py,內容如下:
# linalg_viz.py —— 本書共用的視覺化工具箱
import numpy as np
import matplotlib.pyplot as plt
def plot_vectors(vectors, colors=None, labels=None, xlim=(-5, 5),
ylim=(-5, 5), title="", ax=None, show=True):
"""從原點畫出多個向量。
參數
----
vectors : list of array-like,每個元素是 [x, y](或 [x, y, z])
colors : list,顏色字串或名稱;None 時自動配色
labels : list of str,圖例文字
xlim, ylim : 座標範圍
title : 標題
ax : 傳入 matplotlib axes 則畫在上面(不另開圖)
show : 是否立即 plt.show()
"""
vectors = [np.asarray(v, dtype=float) for v in vectors]
n = len(vectors)
if colors is None:
colors = [f"C{i}" for i in range(n)]
if labels is None:
labels = [f"v{i}" for i in range(n)]
own_fig = ax is None
if own_fig:
fig, ax = plt.subplots(figsize=(5, 5))
for v, c, lab in zip(vectors, colors, labels):
ax.quiver(0, 0, v[0], v[1], angles='xy', scale_units='xy',
scale=1, color=c, label=lab, width=0.006)
ax.set_xlim(*xlim); ax.set_ylim(*ylim)
ax.grid(alpha=0.4)
ax.axhline(0, color='gray', lw=0.8)
ax.axvline(0, color='gray', lw=0.8)
ax.set_aspect('equal')
ax.legend()
if title:
ax.set_title(title)
if own_fig and show:
plt.show()
return ax
def plot_transformation(A, xlim=(-3, 3), ylim=(-3, 3), title="矩陣變換"):
"""畫出單位方形與網格經矩陣 A 變換前後的樣子。
參數
----
A : 2x2 矩陣(ndarray 或 list)
"""
A = np.asarray(A, dtype=float)
# 單位方形的四個角
square = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]])
transformed = square @ A.T # 每一點都乘上 A
# 背景網格線
fig, axes = plt.subplots(1, 2, figsize=(11, 5))
for grid_n in range(-3, 4):
line_h = np.array([[x, grid_n] for x in np.linspace(-3, 3, 2)])
line_v = np.array([[grid_n, y] for y in np.linspace(-3, 3, 2)])
for ax, pts in [(axes[0], line_h), (axes[0], line_v)]:
ax.plot(pts[:, 0], pts[:, 1], color='lightgray', lw=0.7)
for ax, pts in [(axes[1], line_h @ A.T), (axes[1], line_v @ A.T)]:
ax.plot(pts[:, 0], pts[:, 1], color='lightblue', lw=0.7)
axes[0].plot(square[:, 0], square[:, 1], 'b-o', label='變換前')
axes[1].plot(transformed[:, 0], transformed[:, 1], 'r-o', label='變換後')
for ax in axes:
ax.set_xlim(*xlim); ax.set_ylim(*ylim)
ax.set_aspect('equal'); ax.grid(alpha=0.3); ax.legend()
axes[0].set_title('變換前')
axes[1].set_title(f'變換後 A = {A.tolist()}')
fig.suptitle(title)
plt.show()
def plot_unit_circle_transformed(A, n_points=100):
"""畫單位圓經矩陣 A 變換後的形狀(通常是橢圓)。"""
A = np.asarray(A, dtype=float)
theta = np.linspace(0, 2 * np.pi, n_points)
circle = np.column_stack([np.cos(theta), np.sin(theta)])
transformed = circle @ A.T # (n, 2)
fig, ax = plt.subplots(figsize=(6, 6))
ax.plot(circle[:, 0], circle[:, 1], 'b--', label='單位圓(變換前)')
ax.plot(transformed[:, 0], transformed[:, 1], 'r-', label='變換後')
ax.set_aspect('equal'); ax.grid(alpha=0.4); ax.legend()
ax.set_title(f'單位圓經 A = {A.tolist()} 變換')
plt.show()
擴充函式(第 2 章起會用到)#
第 2 章開始需要「變換前後網格疊在同一張圖」的畫法與自訂座標軸, 請把下列三個函式 加到 linalg_viz.py 尾端(之後章節一樣 import):
# ---- 以下加入 linalg_viz.py ----
def setup_axes(ax, xlim=(-5, 5), ylim=(-5, 5)):
"""準備一個等比例、帶格線與座標軸的畫面。"""
ax.set_xlim(*xlim); ax.set_ylim(*ylim)
ax.set_aspect('equal')
ax.grid(alpha=0.3)
ax.axhline(0, color='gray', lw=0.8)
ax.axvline(0, color='gray', lw=0.8)
def draw_grid_transform(ax, A, xlim=(-5, 5), ylim=(-5, 5), n=6,
show_before=True):
"""在同一張圖上畫出單位方格網經 A 變換前(淡)後(深)的樣子。
A : 2x2 矩陣;n : 網格範圍 ±n
"""
A = np.asarray(A, dtype=float)
xs = np.linspace(-n, n, 2)
if show_before: # 變換前的原始網格
for g in range(-n, n + 1):
ax.plot([-n, n], [g, g], color='lightgray', lw=0.6)
ax.plot([g, g], [-n, n], color='lightgray', lw=0.6)
# 變換後的網格:水平線與垂直線各畫一組
for g in range(-n, n + 1):
h = np.column_stack([xs * 0 + g, xs]) # y = g 的水平線
v = np.column_stack([xs, xs * 0 + g]) # x = g 的垂直線
for pts in (h, v):
t = pts @ A.T # 變換!
ax.plot(t[:, 0], t[:, 1], color='steelblue', lw=1.0)
# 追蹤基向量 e1, e2 的像
for e, c in [(np.array([1., 0.]), 'tab:red'),
(np.array([0., 1.]), 'tab:green')]:
w = A @ e
ax.quiver(0, 0, w[0], w[1], angles='xy', scale_units='xy',
scale=1, color=c, width=0.006)
ax.set_xlim(*xlim); ax.set_ylim(*ylim)
ax.set_aspect('equal')
ax.axhline(0, color='gray', lw=0.8)
ax.axvline(0, color='gray', lw=0.8)
def draw_vectors(ax, vec_map):
"""在既有 axes 上疊畫多個向量(箭頭)。
vec_map : {標籤: 向量} 的字典;標籤含 'T(' 的畫實線,其餘畫虛線
"""
for i, (lab, v) in enumerate(vec_map.items()):
v = np.asarray(v, dtype=float)
style = '-' if 'T(' in lab else '--'
ax.arrow(0, 0, v[0], v[1], head_width=0.12,
length_includes_head=True, color=f'C{i}',
linestyle=style, label=lab)
ax.legend()
return ax
示範(2.1 節會重複用到):
import numpy as np
import matplotlib.pyplot as plt
from linalg_viz import setup_axes, draw_grid_transform, draw_vectors
A = np.array([[1., 1.], [0., 1.]]) # 剪切
fig, ax = plt.subplots(figsize=(6, 6))
setup_axes(ax, xlim=(-1, 4), ylim=(-1, 4))
draw_grid_transform(ax, A, xlim=(-1, 4), ylim=(-1, 4))
plt.show()
輸出描述:淡灰色原始方格網 + 深藍色被剪歪的網格,紅、綠箭頭是 \(\mathbf{e_1}, \mathbf{e_2}\) 變換後的行向量像。
函式選擇速查:
| 函式 | 用途 | 使用章節 |
|---|---|---|
plot_vectors | 畫多支箭頭 | 全書 |
plot_transformation | 單位方形變換前後(兩張圖) | 2.x |
plot_unit_circle_transformed | 單位圓 → 橢圓 | 5、7 |
setup_axes | 自訂等比例軸 | 2 起 |
draw_grid_transform | 網格變換前後疊圖 | 2 全章 |
draw_vectors | 疊畫向量(含虛線原向量) | 2.x |
參數說明與示範#
plot_vectors()#
vectors:向量列表,內部先轉成 float ndarraycolors / labels:自動配C0, C1, ...與v0, v1, ...ax:傳入既有 axes 可疊圖(第 3 章會用到)
示範:
from linalg_viz import plot_vectors
plot_vectors([[2, 1], [1, 3], [3, 4]],
labels=['u', 'v', 'u+v'],
title='向量相加')
輸出描述:座標平面上三支箭頭,紅色 u+v 是藍、橘兩箭頭張出的平行四邊形對角線, 圖例與等比例座標網格一應俱全。
plot_transformation()#
示範:用一個「剪變」矩陣:
from linalg_viz import plot_transformation
A = np.array([[1, 1],
[0, 1]]) # 往右推的剪變
plot_transformation(A, title='剪變換')
輸出描述:左圖是淡灰方格網與藍色單位方形;右圖整個網格被往右推歪、 越上面推越多,單位方形變成斜的平行四邊形——這就是矩陣 \(A\) 對空間做的事。
plot_unit_circle_transformed()#
示範:
from linalg_viz import plot_unit_circle_transformed
A = np.array([[2, 0],
[0, 1]]) # x 方向拉長 2 倍
plot_unit_circle_transformed(A)
輸出描述:藍色虛線單位圓變成紅色橢圓,長軸在 x 方向、半徑 2。 第 8 章你會知道:橢圓的長短軸方向就是 \(A\) 的特徵向量方向。
之後的章節如何使用#
只要 linalg_viz.py 與 notebook 在同一資料夾(或已加入 sys.path):
from linalg_viz import plot_vectors, plot_transformation, plot_unit_circle_transformed
之後章節的使用場景:
| 章節 | 用哪個函數 |
|---|---|
| 第 2 章 矩陣乘法 | plot_transformation() 拆解複合變換 |
| 第 3 章 線性變換 | plot_vectors() 觀察基向量去哪了 |
| 第 5 章 行列式 | plot_transformation() 看面積縮放 |
| 第 8 章 特徵值 | plot_unit_circle_transformed() 找不變方向 |
存檔與執行環境提示#
- 檔案位置:
linalg_viz.py放在 notebook 同目錄;否則用sys.path.append('/你的資料夾路徑')。 - 執行環境:建議 Jupyter Notebook / JupyterLab(圖會內嵌顯示)。 若用純 Python 腳本執行,圖會開在獨立視窗,記得
plt.show()。 - 安裝:
pip install numpy matplotlib(或用conda install)。 - 驗證安裝:
python -c "import numpy, matplotlib; print('OK')"。 - 若在 Colab 執行,把
linalg_viz.py用左側檔案面板上傳,或from google.colab import files; files.upload()。
小結與練習#
本節重點 1. linalg_viz.py 是全書的視覺化基礎設施,三個函數各司其職。 2. plot_transformation 左右對照圖是理解「矩陣 = 變換」的最強工具。 3. 修改網格線的 @ A.T 是 broadcasting + 矩陣乘法的綜合應用。
練習 1. 用 plot_transformation 測試旋轉矩陣 \(\begin{bmatrix} 0 & -1 \\ 1 & 0 \end{bmatrix}\) ,方形轉了幾度? 2. 測試 \(\begin{bmatrix} 0 & 0 \\ 0 & 1 \end{bmatrix}\) ,觀察網格發生什麼?(這是「投影」,空間被壓扁,行列式 = 0 的預告) 3. 幫 plot_vectors 加上 alpha 參數控制透明度。 4. 寫一個 plot_points_combination(u, v, alphas, betas) 函數,畫出 1.3 節的線性組合網格。