目录4

文章绘图第 16 章

CORRELOGRAM

绘图 · 第 16 / 36 章

基础相关图

chart_057

基础相关图
Python51 行
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap

BG = "#F7F3EC"
CMAP = LinearSegmentedColormap.from_list(
    "theme", ["#35666E", "#F7F3EC", "#A8552E"], N=256
)

np.random.seed(42)
n = 300
# 构造 5 个有相关结构的变量
X = np.random.normal(0, 1, (n, 5))
X[:, 1] = X[:, 0] * 0.85 + np.random.normal(0, 0.5, n)
X[:, 2] = -X[:, 0] * 0.6 + np.random.normal(0, 0.7, n)
X[:, 3] = X[:, 1] * 0.5 + np.random.normal(0, 0.8, n)
# X[:, 4] 独立

labels = ["V1", "V2", "V3", "V4", "V5"]
corr = np.corrcoef(X.T)

fig, ax = plt.subplots(figsize=(7.5, 6.5))

im = ax.imshow(corr, cmap=CMAP, vmin=-1, vmax=1)

# 数字标注
for i in range(len(labels)):
    for j in range(len(labels)):
        val = corr[i, j]
        # 深色背景用白字,浅色背景用深棕字
        color = "white" if abs(val) > 0.6 else "#3F2E18"
        ax.text(j, i, f"{val:.2f}",
                ha="center", va="center",
                fontsize=10, color=color,
                fontweight="bold" if i == j else "normal")

ax.set_xticks(range(len(labels)))
ax.set_yticks(range(len(labels)))
ax.set_xticklabels(labels)
ax.set_yticklabels(labels)
ax.tick_params(axis="both", colors="#3F2E18")

ax.set_title("Correlogram", fontsize=15, color="#3F2E18", pad=12)

cbar = fig.colorbar(im, ax=ax, shrink=0.85, pad=0.02)
cbar.set_label("Correlation", fontsize=11, color="#3F2E18")
cbar.ax.tick_params(colors="#3F2E18")
cbar.outline.set_edgecolor("#3F2E18")

plt.tight_layout()
plt.show()

下三角相关图

chart_058

下三角相关图
Python54 行
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap

BG = "#FFFFFF"
CMAP = LinearSegmentedColormap.from_list(
    "theme", ["#35666E", "#F7F3EC", "#A8552E"], N=256
)

np.random.seed(0)
n = 400
X = np.random.normal(0, 1, (n, 6))
X[:, 1] = X[:, 0] * 0.8 + np.random.normal(0, 0.5, n)
X[:, 2] = -X[:, 1] * 0.5 + np.random.normal(0, 0.7, n)
X[:, 3] = X[:, 0] * 0.4 + np.random.normal(0, 0.9, n)
X[:, 4] = X[:, 2] * 0.6 + np.random.normal(0, 0.6, n)
labels = ["V1", "V2", "V3", "V4", "V5", "V6"]
corr = np.corrcoef(X.T)

# 掩码上三角(含对角线)
mask = np.triu(np.ones_like(corr, dtype=bool))
corr_masked = np.ma.masked_where(mask, corr)

fig, ax = plt.subplots(figsize=(7.5, 6.5))

cmap = CMAP.copy()
cmap.set_bad(BG)   # 掩码区域用背景色

im = ax.imshow(corr_masked, cmap=cmap, vmin=-1, vmax=1)

# 只标注下三角
for i in range(len(labels)):
    for j in range(i):
        val = corr[i, j]
        color = "white" if abs(val) > 0.6 else "#3F2E18"
        ax.text(j, i, f"{val:.2f}", ha="center", va="center",
                fontsize=10, color=color)

ax.set_xticks(range(len(labels)))
ax.set_yticks(range(len(labels)))
ax.set_xticklabels(labels)
ax.set_yticklabels(labels)
ax.tick_params(axis="both", colors="#3F2E18")

ax.set_title("Lower Triangle Correlogram",
             fontsize=15, color="#3F2E18", pad=12)

cbar = fig.colorbar(im, ax=ax, shrink=0.85, pad=0.02)
cbar.set_label("Correlation", fontsize=11, color="#3F2E18")
cbar.ax.tick_params(colors="#3F2E18")
cbar.outline.set_edgecolor("#3F2E18")

plt.tight_layout()
plt.show()

气泡相关图

chart_059

气泡相关图
Python59 行
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap

BG = "#F7F3EC"
CMAP = LinearSegmentedColormap.from_list(
    "theme", ["#35666E", "#F7F3EC", "#A8552E"], N=256
)

np.random.seed(1)
n = 300
X = np.random.normal(0, 1, (n, 6))
X[:, 1] = X[:, 0] * 0.8 + np.random.normal(0, 0.5, n)
X[:, 2] = -X[:, 1] * 0.5 + np.random.normal(0, 0.7, n)
X[:, 3] = X[:, 0] * 0.4 + np.random.normal(0, 0.9, n)
X[:, 4] = X[:, 2] * 0.6 + np.random.normal(0, 0.6, n)
labels = ["V1", "V2", "V3", "V4", "V5", "V6"]
corr = np.corrcoef(X.T)

fig, ax = plt.subplots(figsize=(8, 7))

# 只画下三角
for i in range(len(labels)):
    for j in range(i + 1):
        r = corr[i, j]
        size = abs(r) * 1200 + 50
        color = CMAP((r + 1) / 2)   # -1~1 → 0~1
        ax.scatter(j, i, s=size, color=color,
                   edgecolor="white", linewidth=1.0,
                   alpha=0.9, zorder=3)
        if i != j:   # 对角线不标数字
            ax.text(j, i, f"{r:.2f}", ha="center", va="center",
                    fontsize=9, color="#3F2E18",
                    zorder=4, fontweight="bold")

# 对角线画变量名
for i, lab in enumerate(labels):
    ax.text(i, i, lab, ha="center", va="center",
            fontsize=11, color="#3F2E18",
            fontweight="bold", zorder=4)

ax.set_xlim(-0.7, len(labels) - 0.3)
ax.set_ylim(len(labels) - 0.3, -0.7)
ax.set_xticks([])
ax.set_yticks([])

ax.set_title("Bubble Correlogram",
             fontsize=15, color="#3F2E18", pad=12)

# 加参考网格线
for k in np.arange(-0.5, len(labels), 1):
    ax.axhline(k, color="#3F2E18", linewidth=0.3, alpha=0.2)
    ax.axvline(k, color="#3F2E18", linewidth=0.3, alpha=0.2)

for s in ("top", "right", "left", "bottom"):
    ax.spines[s].set_visible(False)

plt.tight_layout()
plt.show()

聚类排序的相关图

chart_060

聚类排序的相关图
Python60 行
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from matplotlib.colors import LinearSegmentedColormap
from scipy.cluster.hierarchy import linkage, leaves_list
from scipy.spatial.distance import squareform

BG = "#F7F3EC"
CMAP = LinearSegmentedColormap.from_list(
    "theme", ["#35666E", "#F7F3EC", "#A8552E"], N=256
)

np.random.seed(2)
n = 400
X = np.random.normal(0, 1, (n, 8))
# 构造两个相关簇
X[:, 1] = X[:, 0] * 0.85 + np.random.normal(0, 0.4, n)
X[:, 2] = X[:, 0] * 0.75 + np.random.normal(0, 0.5, n)
X[:, 4] = -X[:, 3] * 0.8 + np.random.normal(0, 0.5, n)
X[:, 5] = -X[:, 3] * 0.7 + np.random.normal(0, 0.6, n)
X[:, 6] = X[:, 3] * 0.5 + np.random.normal(0, 0.8, n)
labels = [f"V{i+1}" for i in range(8)]
corr = np.corrcoef(X.T)

# 层次聚类重排
dist = 1 - np.abs(corr)
np.fill_diagonal(dist, 0)
Z = linkage(squareform(dist, checks=False), method="average")
order = leaves_list(Z)

corr_ordered = corr[np.ix_(order, order)]
labels_ordered = [labels[i] for i in order]

fig, ax = plt.subplots(figsize=(8.5, 7.5))

im = ax.imshow(corr_ordered, cmap=CMAP, vmin=-1, vmax=1)

for i in range(len(labels_ordered)):
    for j in range(len(labels_ordered)):
        val = corr_ordered[i, j]
        color = "white" if abs(val) > 0.6 else "#3F2E18"
        ax.text(j, i, f"{val:.2f}", ha="center", va="center",
                fontsize=9, color=color)

ax.set_xticks(range(len(labels_ordered)))
ax.set_yticks(range(len(labels_ordered)))
ax.set_xticklabels(labels_ordered, rotation=45, ha="right")
ax.set_yticklabels(labels_ordered)
ax.tick_params(axis="both", colors="#3F2E18")

ax.set_title("Clustered Correlogram",
             fontsize=15, color="#3F2E18", pad=12)

cbar = fig.colorbar(im, ax=ax, shrink=0.85, pad=0.02)
cbar.set_label("Correlation", fontsize=11, color="#3F2E18")
cbar.ax.tick_params(colors="#3F2E18")
cbar.outline.set_edgecolor("#3F2E18")

plt.tight_layout()
plt.show()