PatrickT
PatrickT

Reputation: 10510

Julia: Heatmap with color gradient centered at 0

In a heatmap, how could I create a three-color gradient, with blue for negative values, red for positive values and white for zero, such that with many zero values, much of the heatmap would be white (and not light red as with the default gradient).

A = [5 0 -3 -2 7; 0 5 0 0 0; -2 0 -1 0 0; -4 0 0 -10 0; 0 0 0 0 9]
using Plots
heatmap(Array(A),
    c = cgrad([:blue,:white,:red]),
    yflip = true,
    xlabel = "row", ylabel = "col",
    title = "Nonzeros, Positives, Negatives, in Matrix")

enter image description here

Here the gradient is automatically centered at the midpoint, a sensible default.

Related: here.

Post-Scriptum

As BallPointBen suggests, it would seem that computing the range of values is the recommended approach. Here is some benchmarking. The best approach, suggested by BallPointBen, is max = maximum(abs, A)

julia> using BenchmarkTools
julia> A = rand(10_000, 10_100)

julia> @btime max = maximum(abs.(A))
  432.837 ms (6 allocations: 770.57 MiB)
0.999999999929502

julia> @btime max = maximum(abs.(extrema(A)))
  339.597 ms (5 allocations: 144 bytes)
0.999999999929502

julia> @btime max = maximum(abs, A)
  60.690 ms (1 allocation: 16 bytes)
0.9999999985609005

Upvotes: 1

Views: 1434

Answers (1)

BallpointBen
BallpointBen

Reputation: 13750

You can compute the maximum absolute value in your array, then use it to set the clims argument. c.f. http://docs.juliaplots.org/latest/generated/attributes_subplot/

julia> max_val = maximum(abs, A)
10

julia> heatmap(Array(A),
           c = cgrad([:blue,:white,:red]),
           yflip = true,
           xlabel = "row", ylabel = "col",
           title = "Nonzeros, Positives, Negatives, in Matrix",
           clims=(-max_val, max_val))

enter image description here

Upvotes: 2

Related Questions