I have a plot where some values originate from devision by 0 and some originate from 0/0, I would like to add new colours to the heatmap to descriminate between them.
Does anyone have an idea on how to do this in plots.jl?
I don’t know if one can specify custom colors for Inf
and NaN
directly, but a possible workaround would be to manually plot something in the place of the infinities/NaNs with scatter!
.
Here’s an example (note that I transposed the data for the heatmap, otherwise the definitions of the x and y axes will be flipped for heatmap
and scatter!
):
using Plots
N = 50
rawData = rand(N, N)
nanPointCoordinates = rand(CartesianIndices((1:N, 1:N)), 500)
infPointCoordinates = rand(CartesianIndices((1:N, 1:N)), 500)
rawData[nanPointCoordinates] .= NaN
rawData[infPointCoordinates] .= Inf
p = heatmap(transpose(rawData); c=:viridis)
scatter!(p, Tuple.(findall(isnan, rawData)); label="NaNs", markers=:square, markerstrokewidth=0, markercolor=:red, markersize=3)
scatter!(p, Tuple.(findall(isinf, rawData)); label="Infs", markers=:square, markerstrokewidth=0, markercolor=:black, markersize=3)
This will produce something like this (you would have to play around with the shapes/sizes/colors of the markers of course – also how to find the right x/y coordinates in your case, I just used the indices)
This is a very creative solution, thank you very much : )
An alternative with grids and playing with the colormap
using GMT
N = 50;
rawData = rand(N, N);
nanPointCoordinates = rand(CartesianIndices((1:N, 1:N)), 500);
infPointCoordinates = rand(CartesianIndices((1:N, 1:N)), 500);
rawData[nanPointCoordinates] .= NaN;
rawData[infPointCoordinates] .= Inf;
# Convert data into a GMT grid
G = mat2grid(Float32.(rawData));
# Make a colormap with NaNs in gray and Infs in white
C = makecpt(range=(0,1), overrule_bg=true, conf=(COLOR_FOREGROUND=:white, COLOR_NAN=:gray));
viz(G, cmap=C, colorbar=true)
Fyi, it is also possible to get this using Plots’ heatmap():
Plots' heatmap code
# (continued from code above)
using Colors, ColorSchemes, Plots; gr()
theme(:dark)
c0, c3 = colorant"white", colorant"red" # NaN's are labelled white, Inf's red
m = 16
cscheme1 = palette(ColorScheme([c0; ColorSchemes.viridis.colors; c3]), m+2)
z1, z2 = extrema(x for x in rawData if isfinite(x))
dz = (z2 - z1)/m
Z0 = replace(rawData, NaN => z1 - dz, Inf => z2 + dz)
heatmap(Z0, c=cscheme1, lims=(0.5, N+0.5), ratio=1, dpi=600)
annotate!(N+8, N+0.5, text("Inf", :red, 9))
annotate!(N+8, 1, text("NaN", :white, 9))
what is the syntax?
The code has been posted below the plot.
This is brilliant, thanks for the pointer!