Python 画图 向量a在向量b上的投影(Projection of Vector a on Vector b)
flyfish
向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影(Projection of Vector a ⃗ \vec{a} a on Vector b ⃗ \vec{b} b)是指向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 方向上的分量。这个投影可以理解为 a ⃗ \vec{a} a 在 b ⃗ \vec{b} b 方向上“影子”的长度和方向,即下图紫色虚线。
数学定义
向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影向量 proj b ⃗ a ⃗ \text{proj}_{\vec{b}} \vec{a} projba 可以通过以下公式计算:
proj b ⃗ a ⃗ = ( a ⃗ ⋅ b ⃗ b ⃗ ⋅ b ⃗ ) b ⃗ \text{proj}_{\vec{b}} \vec{a} = \left( \frac{\vec{a} \cdot \vec{b}}{\vec{b} \cdot \vec{b}} \right) \vec{b} projba=(b⋅ba⋅b)b
这里:
-
a
⃗
⋅
b
⃗
\vec{a} \cdot \vec{b}
a⋅b 是向量
a
⃗
\vec{a}
a 和向量
b
⃗
\vec{b}
b 的点积(内积),表示为:
a ⃗ ⋅ b ⃗ = a 1 b 1 + a 2 b 2 + ⋯ + a n b n \vec{a} \cdot \vec{b} = a_1 b_1 + a_2 b_2 + \cdots + a_n b_n a⋅b=a1b1+a2b2+⋯+anbn -
b
⃗
⋅
b
⃗
\vec{b} \cdot \vec{b}
b⋅b 是向量
b
⃗
\vec{b}
b 的模的平方,表示为:
b ⃗ ⋅ b ⃗ = ∥ b ⃗ ∥ 2 = b 1 2 + b 2 2 + ⋯ + b n 2 \vec{b} \cdot \vec{b} = \| \vec{b} \|^2 = b_1^2 + b_2^2 + \cdots + b_n^2 b⋅b=∥b∥2=b12+b22+⋯+bn2 - ( a ⃗ ⋅ b ⃗ b ⃗ ⋅ b ⃗ ) \left( \frac{\vec{a} \cdot \vec{b}}{\vec{b} \cdot \vec{b}} \right) (b⋅ba⋅b) 是一个标量,表示 a ⃗ \vec{a} a 在 b ⃗ \vec{b} b 方向上的分量的长度。
- b ⃗ \vec{b} b 是向量 b ⃗ \vec{b} b 本身,用来确定投影的方向。
投影长度
向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影长度(标量形式)可以通过以下公式计算:
∣ proj b ⃗ a ⃗ ∣ = ∣ a ⃗ ⋅ b ⃗ ∣ ∥ b ⃗ ∥ |\text{proj}_{\vec{b}} \vec{a}| = \frac{|\vec{a} \cdot \vec{b}|}{\|\vec{b}\|} ∣projba∣=∥b∥∣a⋅b∣
这里:
- ∣ a ⃗ ⋅ b ⃗ ∣ |\vec{a} \cdot \vec{b}| ∣a⋅b∣ 是向量 a ⃗ \vec{a} a 和向量 b ⃗ \vec{b} b 点积的绝对值。
-
∥
b
⃗
∥
\|\vec{b}\|
∥b∥ 是向量
b
⃗
\vec{b}
b 的模长,表示为:
∥ b ⃗ ∥ = b 1 2 + b 2 2 + ⋯ + b n 2 \|\vec{b}\| = \sqrt{b_1^2 + b_2^2 + \cdots + b_n^2} ∥b∥=b12+b22+⋯+bn2
几何意义
- 方向:投影向量 proj b ⃗ a ⃗ \text{proj}_{\vec{b}} \vec{a} projba 的方向与向量 b ⃗ \vec{b} b 的方向相同(或相反,取决于点积的符号)。
- 长度:投影向量的长度表示 a ⃗ \vec{a} a 在 b ⃗ \vec{b} b 方向上的分量的大小。
示例
假设 a ⃗ = ( 2 3 ) \vec{a} = \begin{pmatrix} 2 \\ 3 \end{pmatrix} a=(23) 和 b ⃗ = ( 4 0 ) \vec{b} = \begin{pmatrix} 4 \\ 0 \end{pmatrix} b=(40),我们来计算 a ⃗ \vec{a} a 在 b ⃗ \vec{b} b 上的投影。
-
计算点积:
a ⃗ ⋅ b ⃗ = 2 ⋅ 4 + 3 ⋅ 0 = 8 \vec{a} \cdot \vec{b} = 2 \cdot 4 + 3 \cdot 0 = 8 a⋅b=2⋅4+3⋅0=8 -
计算 b ⃗ \vec{b} b 的模的平方:
b ⃗ ⋅ b ⃗ = 4 2 + 0 2 = 16 \vec{b} \cdot \vec{b} = 4^2 + 0^2 = 16 b⋅b=42+02=16 -
计算投影向量:
proj b ⃗ a ⃗ = ( 8 16 ) ( 4 0 ) = 1 2 ( 4 0 ) = ( 2 0 ) \text{proj}_{\vec{b}} \vec{a} = \left( \frac{8}{16} \right) \begin{pmatrix} 4 \\ 0 \end{pmatrix} = \frac{1}{2} \begin{pmatrix} 4 \\ 0 \end{pmatrix} = \begin{pmatrix} 2 \\ 0 \end{pmatrix} projba=(168)(40)=21(40)=(20) -
计算投影长度:
∣ proj b ⃗ a ⃗ ∣ = ∣ 8 ∣ 16 = 8 4 = 2 |\text{proj}_{\vec{b}} \vec{a}| = \frac{|8|}{\sqrt{16}} = \frac{8}{4} = 2 ∣projba∣=16∣8∣=48=2
因此,向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影向量是 ( 2 0 ) \begin{pmatrix} 2 \\ 0 \end{pmatrix} (20),投影长度是 2。
import matplotlib.pyplot as plt
import numpy as np
# 设置画布大小和背景颜色
fig, ax = plt.subplots(figsize=(8, 6)) # 创建一个新的图形并设置其大小
ax.set_facecolor('beige') # 设置绘图区域的背景颜色为米色
# 定义向量a和b
vector_a = np.array([2, 3]) # 向量a的坐标
vector_b = np.array([4, 0]) # 向量b的坐标
# 绘制向量a
origin = np.array([0, 0]) # 向量的起点
ax.quiver(*origin, *vector_a, color='blue', scale_units='xy', angles='xy', scale=1, label=r'$\vec{a}$') # 使用quiver函数绘制向量a,颜色为蓝色
# 绘制向量b
ax.quiver(*origin, *vector_b, color='teal', scale_units='xy', angles='xy', scale=1, label=r'$\vec{b}$') # 使用quiver函数绘制向量b,颜色为蓝绿色
# 计算向量a在向量b上的投影长度
proj_length = np.dot(vector_a, vector_b) / np.linalg.norm(vector_b) # 计算向量a在向量b上的投影长度
projection = proj_length * vector_b / np.linalg.norm(vector_b) # 计算投影点的坐标
# 绘制投影线段
ax.plot([0, projection[0]], [0, projection[1]], linestyle='dashed', color='purple', label='Projection') # 绘制从原点到投影点的虚线,颜色为紫色
ax.plot([vector_a[0], projection[0]], [vector_a[1], projection[1]], linestyle='dotted', color='gray', label='A to Projection') # 绘制从点A到投影点的点划线,颜色为灰色
# 添加文本标签
ax.text(-0.3, -0.3, r'$O$', fontsize=14, color='black') # 在原点附近添加文本标签O
ax.text(2.1, 3.1, r'$A$', fontsize=14, color='blue') # 在点A附近添加文本标签A
ax.text(4.0, -0.3, r'$B$', fontsize=14, color='teal') # 在点B附近添加文本标签B
ax.text(0.5, 0.3, r'$\theta$', fontsize=14, color='red') # 在原点附近添加角度θ的标签
ax.text(1.0, -0.5, r'$|a|\cos{\theta}$', fontsize=14, color='purple') # 在投影线段下方添加投影长度的标签
# 添加点标记
ax.scatter(projection[0], projection[1], color='purple', s=100, label='Projection Point') # 标记投影点,颜色为紫色
ax.scatter(vector_b[0], vector_b[1], color='teal', s=100, label=r'End of $\vec{b}$') # 标记向量b的终点,颜色为蓝绿色
ax.scatter(origin[0], origin[1], color='black', s=100, label='Origin') # 标记原点,颜色为黑色
ax.scatter(vector_a[0], vector_a[1], color='blue', s=100, label='Point A') # 标记点A,颜色为蓝色
# 设置坐标轴范围和隐藏坐标轴
ax.set_xlim([-1, 5]) # 设置x轴的显示范围
ax.set_ylim([-1, 4]) # 设置y轴的显示范围
ax.axis('off') # 隐藏坐标轴
# 显示图例
ax.legend(loc='upper right') # 在右上角显示图例
# 显示图形
plt.show() # 显示图形
在Python字符串中,前缀 r
表示一个原始字符串(raw string)。原始字符串中的反斜杠 \
不会被转义,而是作为普通字符处理。这对于包含反斜杠的字符串(如正则表达式或LaTeX公式)非常有用,因为这样可以避免多次转义带来的混乱。
ax.text(1.0, -0.5, r'$|a|\cos{\theta}$', fontsize=14, color='purple')
这里的 r
就是用来告诉Python解析器,这个字符串中的反斜杠 \
是普通字符,而不是转义字符。这样,$\cos{\theta}$
就会被正确地解析为LaTeX数学模式中的余弦函数符号。
如果不使用 r
前缀,字符串中的反斜杠会被转义,例如:
'\n'
会被解析为换行符。'\t'
会被解析为制表符。
使用 r
前缀可以确保LaTeX公式中的反斜杠不会被错误解析,从而正确显示数学符号。
计算向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影长度和投影点的坐标
np.dot(vector_a, vector_b)
:计算向量 a ⃗ \vec{a} a 和 b ⃗ \vec{b} b 的点积。np.linalg.norm(vector_b)
:计算向量 b ⃗ \vec{b} b 的模。proj_length
:计算向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影长度。projection
:计算向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影向量的坐标。
1. 计算向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影长度
proj_length = np.dot(vector_a, vector_b) / np.linalg.norm(vector_b)
解释:
-
np.dot(vector_a, vector_b)
:这是计算向量 a ⃗ \vec{a} a 和向量 b ⃗ \vec{b} b 的点积(内积)。点积的公式是:
a ⃗ ⋅ b ⃗ = a 1 b 1 + a 2 b 2 + ⋯ + a n b n \vec{a} \cdot \vec{b} = a_1 b_1 + a_2 b_2 + \cdots + a_n b_n a⋅b=a1b1+a2b2+⋯+anbn
其中 a i a_i ai 和 b i b_i bi 分别是向量 a ⃗ \vec{a} a 和 b ⃗ \vec{b} b 的对应分量。 -
np.linalg.norm(vector_b)
:这是计算向量 b ⃗ \vec{b} b 的模(长度)。模的公式是:
∥ b ⃗ ∥ = b 1 2 + b 2 2 + ⋯ + b n 2 \|\vec{b}\| = \sqrt{b_1^2 + b_2^2 + \cdots + b_n^2} ∥b∥=b12+b22+⋯+bn2
np.linalg.norm
是 NumPy 库中的一个函数,用于计算向量的范数(默认是2-范数,即欧几里得距离)。 -
proj_length
:这是向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影长度。根据公式:
proj_length = a ⃗ ⋅ b ⃗ ∥ b ⃗ ∥ \text{proj\_length} = \frac{\vec{a} \cdot \vec{b}}{\|\vec{b}\|} proj_length=∥b∥a⋅b
2. 计算投影点的坐标
projection = proj_length * vector_b / np.linalg.norm(vector_b)
解释:
-
proj_length * vector_b
:这一步是将投影长度乘以向量 b ⃗ \vec{b} b。这会得到一个与 b ⃗ \vec{b} b 方向相同的向量,但长度为proj_length
。 -
/ np.linalg.norm(vector_b)
:这一步是将上述结果除以 b ⃗ \vec{b} b 的模。这样做是为了将向量 b ⃗ \vec{b} b 归一化(即变成单位向量),从而确保投影向量的长度为proj_length
。 -
projection
:这是向量 a ⃗ \vec{a} a 在向量 b ⃗ \vec{b} b 上的投影向量的坐标。根据公式:
projection = ( a ⃗ ⋅ b ⃗ ∥ b ⃗ ∥ 2 ) b ⃗ \text{projection} = \left( \frac{\vec{a} \cdot \vec{b}}{\|\vec{b}\|^2} \right) \vec{b} projection=(∥b∥2a⋅b)b
这个公式可以分解为:
projection = ( a ⃗ ⋅ b ⃗ ∥ b ⃗ ∥ ) ( b ⃗ ∥ b ⃗ ∥ ) \text{projection} = \left( \frac{\vec{a} \cdot \vec{b}}{\|\vec{b}\|} \right) \left( \frac{\vec{b}}{\|\vec{b}\|} \right) projection=(∥b∥a⋅b)(∥b∥b)
其中, b ⃗ ∥ b ⃗ ∥ \frac{\vec{b}}{\|\vec{b}\|} ∥b∥b 是 b ⃗ \vec{b} b 的单位向量。