Discriminate between NaN and Inf in plots

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?

f_mu_pi_atar

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)

heatmap_inf_nan

2 Likes

This is a very creative solution, thank you very much : )

1 Like

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)

2 Likes

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))
5 Likes

what is the syntax?

The code has been posted below the plot.

This is brilliant, thanks for the pointer!

1 Like