文章/Matplotlib/第 20 章
矩阵可视化
Matplotlib · 第 20 / 43 章
358 字约 1 分钟
matshow() —— 矩阵可视化
matshow() 是 imshow() 的一行封装,专门用来「看矩阵」:它把 aspect 强制成 'equal',并把刻度移到顶部(这是线性代数的书写习惯——矩阵的行列标号在上下方,不在下方)。
Python1 行
Axes.matshow(self, Z, **kwargs)matshow 自己只有 Z 一个参数,其余 **kwargs 全部原样透传给 imshow。所以 cmap、vmin、vmax、alpha、interpolation、origin 都能用。
与 imshow 的差别 |
imshow |
matshow |
|---|---|---|
aspect |
'equal'(但可传 'auto' 覆盖) |
强制 'equal' |
| 刻度位置 | 底部 / 左侧 | 顶部 / 左侧 |
| 参数 | 几十个 | 只有 Z + 透传 |
三栏对比:aspect 才是真正的差别
Python5 行
mat = rng.random((5, 30)) # 非方阵:差别最明显
ax.imshow(mat) # 默认 'equal' → 压成一条扁带
ax.matshow(mat) # 同样 'equal',但刻度跑到顶部
ax.matshow(mat, aspect="auto") # 覆盖掉强制值,铺满
注意第三栏:matshow 的 'equal' 是默认值而不是硬编码——aspect="auto" 依然能覆盖它。所以「matshow 强制等比例」这句话更准确的说法是「matshow 把默认值从 auto 改成了 equal」。
返回对象
Python13 行
im = ax.matshow(Z) # 和 imshow 同一个类
print(type(im).__name__)
# 输出: AxesImage
fig.colorbar(im, ax=ax)
im.set_clim(0, 1)
im.set_cmap("magma")
print(ax.get_aspect()) # 数值形式,1.0 就是 'equal'
# 输出: 1.0
ax.set_aspect("auto") # 事后覆盖
plt.show()matshow 返回的也是 AxesImage,用法和 imshow 完全一致。ax.get_aspect() 返回数值(1.0)而不是字符串('equal')——两者等价,但判断时注意别拿字符串去比。
注意事项
matshow把刻度放在顶部,想让它们在底部得手动ax.xaxis.set_ticks_position("bottom")。aspect='equal'让非方阵矩阵极扁;要看清格子必须显式传aspect="auto"。- 除了
Z,所有参数都是透传给imshow的,imshow的坑它全有(origin、vmin等)。 - 只是「看一个矩阵」时
matshow更省事;要做热力图排版(带 label、colorbar、多子图)还是用imshow更可控。
综合示例:矩阵 + 刻度贴顶 + 色块数值
Python41 行
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False
A = np.array([[4, -2, 1, 0],
[-2, 4, -2, 1],
[1, -2, 4, -2],
[0, 1, -2, 4]], float)
labels = ["x₁", "x₂", "x₃", "x₄"]
fig, axes = plt.subplots(1, 2, figsize=(11, 4.4))
# ---- (a) 默认 matshow:刻度在顶部,格子正方 ----
im = axes[0].matshow(A, cmap="PuOr_r", vmin=-4, vmax=4)
axes[0].set_xticks(range(4), labels)
axes[0].set_yticks(range(4), labels)
for i in range(4):
for j in range(4):
axes[0].text(j, i, A[i, j], ha="center", va="center", fontsize=10)
fig.colorbar(im, ax=axes[0], shrink=0.85)
axes[0].set_title("(a) matshow 默认(刻度在上)")
# ---- (b) 转成热力图排版:刻度回到底部 + 白线分格 ----
im2 = axes[1].matshow(A, cmap="PuOr_r", vmin=-4, vmax=4, aspect="auto")
axes[1].xaxis.set_ticks_position("bottom")
axes[1].set_xticks(range(4), labels)
axes[1].set_yticks(range(4), labels)
for i in range(4):
for j in range(4):
axes[1].text(j, i, A[i, j], ha="center", va="center", fontsize=10)
axes[1].set_xticks(np.arange(-0.5, 4, 1), minor=True)
axes[1].set_yticks(np.arange(-0.5, 4, 1), minor=True)
axes[1].grid(which="minor", color="white", linewidth=1.5)
axes[1].tick_params(which="minor", length=0)
fig.colorbar(im2, ax=axes[1], shrink=0.85)
axes[1].set_title("(b) 刻度移到底部 + 白线分格")
plt.tight_layout()
plt.show()(b) 那个「次刻度打在白线位置 + 只画网格」的套路,是把 matshow 改造成标准热力图排版的通用做法。