How to plot only the upper (or lower) triangle matrix in a heatmap?

Hello, folks

I’m using a combination of functions plot() and heatmap() to visualize a correlation matrix. Correlation matrices, by definition, are symmetric, i.e., a_{i,j} = a_{j,i} for all i \neq j. The diagonal, where i = j, always has correlation 1 since it’s the correlation of a column with itself.

The diagonal and half of the plot is redundant or informative. For this reason, I wanted to plot only the upper (or the lower) portions of the heatmap. How can I do that?

Here’s an example of a simple heatmap. Thanks for the help.

using Distributions
using Random
using Statistics
using Plots

# Create fake data --------------------------
x = Array{Float64}(undef, 500,50);

for i in 1:50 
    if i == 1
        x[:,i] = 10 .+ rand((Normal(0, 1)),500);
        x[:,i] = x[:,i-1] .+ rand((Normal(0, i/2)), 500)
correl = cor(x);

# Call heatmap -------------------------------
ht = heatmap(correl, c = cgrad([:blue,:red]));

# Plot correlation heatmap -------------------
plot(ht, yflip = true) # How to plot only the upper or lower matrix ?

Maybe fill the other triangle with NaN values, since that typically suppresses plotting?

1 Like

function ut2ci(idx)
    j = Int(ceil(sqrt(2 * idx + 0.25) - 0.5))+1
    i = Int(idx - (j-2) * (j-1) / 2)

ht = heatmap(correl, c = cgrad([:blue,:red]));
plot(ht, yflip = true) 

no diagonal

function ut2ci(idx)
    j = Int(ceil(sqrt(2 * idx + 0.25) - 0.5))
    i = Int(idx - (j-1) * (j) / 2)
    CartesianIndex(i,j)    #  cartesianindex(j,i) to get the other half


1 Like

Easier to do:

correl[triu(trues(size(correl)), 1)] .= NaN # upper triangle, no diagonal
1 Like

Another simple way:

cmap1 = cgrad([:blue,:red])
CI = CartesianIndices(correl)
ht = heatmap([(ci[1] > ci[2] ? correl[ci] : NaN) for ci in CI], c=cmap1, yflip=true)

I’m curious to see the implementation of the triu() function.
Using the @edit macro it sends me to the generic.jl module but I can’t find the function code

1 Like

Can you also explain to me why the @edit macro sends me to genric.jl and not to dense.jl?
or how to get to dense.jl starting from generic.jl?

I’m voting this one as solution because it was the easiest solution to implement and the one that relied on the most basic Julian features. All it took was the implementation of a simple for loop to assign NaN to all values I didn’t want to have in the plot.