Skip to content

How to mask the upper triangle of a correlation heatmap in Seaborn (with Code)

The Short Answer (TL;DR)

Pass a Boolean upper-triangle mask to sns.heatmap; cells whose mask is True are hidden. Use a fixed scale from -1 to 1 for a correlation matrix so the remaining cells share a meaningful color scale.

import numpy as np, seaborn as sns
corr = np.corrcoef([[1, 4, 2], [2, 1, 5], [4, 3, 1], [5, 2, 4]], rowvar=False)
sns.heatmap(corr, mask=np.triu(np.ones_like(corr, dtype=bool)), vmin=-1, vmax=1, cmap="vlag")

Detailed Implementation

This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.

python -m pip install numpy==2.5.4 pandas==3.0.6 matplotlib==3.11.2 seaborn==0.13.2
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# Synthetic measurements; no dataset download is required.
rng = np.random.default_rng(7)
x = rng.normal(size=24)
data = pd.DataFrame({
    "input": x,
    "response": 0.7 * x + rng.normal(scale=0.5, size=x.size),
    "noise": rng.normal(size=x.size),
})
corr = data.corr(numeric_only=True)
# k=0 hides the diagonal too. Use k=1 to keep the diagonal visible.
mask = np.triu(np.ones_like(corr, dtype=bool), k=0)
fig, ax = plt.subplots(figsize=(5.4, 4.6), layout="constrained")
sns.heatmap(corr, mask=mask, annot=True, fmt=".2f",
            vmin=-1, vmax=1, center=0, cmap="vlag", square=True,
            cbar_kws={"label": "Pearson correlation"}, ax=ax)
ax.set_title("Pairwise Pearson correlations")
fig.savefig("masked-correlation.png", dpi=160)
plt.show()

The saved chart contains three annotated correlation cells below the diagonal and a colorbar spanning -1 to 1.

What does the mask change?

The mask changes which cells are drawn; it does not change the correlation coefficients or remove observations. A symmetric 3 by 3 matrix has three distinct off-diagonal pairs, so showing one triangle avoids repeating those pairs.

When should the diagonal remain visible?

Set k=1 in np.triu to hide only cells above the diagonal. Set k=0 to hide the diagonal and the upper triangle. The Boolean mask must have the same shape as the plotted matrix.

Which data need extra care?

Constant columns have undefined Pearson correlation and can produce missing cells. Pandas computes correlations using available pairs when data are missing; different cells can therefore use different sample sizes. Report missingness and inspect the data before interpreting a pattern.

Mathematical Context

For variables x and y, Pearson correlation is r = Σ[(xᵢ − x̄)(yᵢ − ȳ)] / √(Σ(xᵢ − x̄)² Σ(yᵢ − ȳ)²). The matrix satisfies rᵢⱼ = rⱼᵢ when computed on the same pair, which is why one triangle repeats the other. Correlation describes linear association and does not establish causation.

\[ r_{xy}=\frac{\sum_i(x_i-\bar{x})(y_i-\bar{y})}{\sqrt{\sum_i(x_i-\bar{x})^2\sum_i(y_i-\bar{y})^2}} \]

Reproducibility

Executed with Python 3.12.14; numpy 2.5.4, pandas 3.0.6, matplotlib 3.11.2, seaborn 0.13.2. Automated checks confirm the stated output properties.

Primary documentation

Related guides