How can I plot a scatter plot over a heatmap with a different color gradient?

I want to overlay a scatter plot onto a heatmap, where the points in the scatter plot are colored based on values at those points. If the values of the scatter points are in the same range as the heatmap’s values, this is pretty easy. However, if the scatter points have a different range/scale than the heatmap, then the plot with the smaller range of variables gets washed out.

For example, in the following code, the heatmap values in Grid_mat fall in [0,1] and Y~N(0,5), which results in a significantly larger range than the Grid_mat values. So, the heatmap becomes less informative, because the color limits are linked between the two plots. I even tried specifying different clims for the two plots, but that didn’t fix the problem.

using Plots, Distributions
using Plots.PlotMeasures

# Example data
x = 1:10
y = 1:10
Grid_mat = rand(1, 100)
ngridpoints = 10
n=50
locs = [rand(Uniform(1, 10), n) rand(Uniform(1, 10), n)]
Y = rand(Normal(0, 5), n)

# Create the heatmap with the first color scale
heatmap(x, y, reshape(Grid_mat[1, :], ngridpoints, ngridpoints),
    color = :viridis, title = "", xlabel = "", ylabel = "",
    clim = (minimum(Grid_mat[1, :]), maximum(Grid_mat[1, :])), alpha = 0.5, legend = false)
scatter!(locs[:, 1], locs[:, 2], marker_z = Y,
    clim = (minimum(Y), maximum(Y)), color = :viridis, msw = 0.25, c = :viridis, legend = false, colorbar = true)

How can I plot the heatmap such that the color limits are for the heatmap values and overlay a scatter plot with color limits that are only for the scatter point values? Note that I do not want to rescale Grid_mat nor Y.

Using Plots.jl and pgfplotsx() you can get something like this:

Plots.jl dual colorbar code
using Distributions, Measures, Plots, pgfplotsx()

# Example data
x = y = 1:10
Grid_mat = rand(100)
ngridpoints, n = 10, 50
locs = [rand(Uniform(1, 10), n) rand(Uniform(1, 10), n)]
Y = rand(Normal(0, 5), n)

# Create the heatmap with the first color scale
heatmap(x, y, reshape(Grid_mat, ngridpoints, ngridpoints),
    color=:grays, title="", label="", widen=false,
    clim=extrema(Grid_mat), alpha=0.5, legend=false, colorbar=:left,
    xlims=extrema(x), ylims=extrema(y)

)

scatter!(twinx(), eachcol(locs)..., marker_z=Y, xmirror=true, widen=false,
    clim=extrema(Y), color=:viridis, msw=0.25, legend=false, colorbar=:right,
    xlims=extrema(x), ylims=extrema(y)
)
1 Like

Unfortunately this isn’t possible in general with Plots.jl as far as I understand it:

That looks great! What is the code that you used to generate this graphic?

Is there a different plotting library in Julia that would work? I’m not tied to the Plots package.

I’m not sure if I understand the problem, but Makie should work fine:

using Distributions, GLMakie

# Example data
x = 1:10
y = 1:10
Grid_mat = rand(1, 100)
ngridpoints = 10
n = 50
locs = [rand(Uniform(1, 10), n) rand(Uniform(1, 10), n)]
Y = rand(Normal(0, 5), n)

# Create the heatmap with the first color scale
f, ax, pl = heatmap(x, y, reshape(Grid_mat[1, :], ngridpoints, ngridpoints),
    colormap=:viridis, 
    colorrange=(minimum(Grid_mat[1, :]), maximum(Grid_mat[1, :])), alpha=0.5)

scatter!(ax, locs[:, 1], locs[:, 2], color=Y, colorrange=(minimum(Y), maximum(Y)), colormap=:viridis, )
f

1 Like

In Plots/GR you can set the colorscale of the markers by hand, like:

julia> using Plots

julia> m = [ sin(x * y) for x in x, y in y ];

julia> heatmap(m)

julia> scatter!(1:10, 1:10; markercolor = [Plots.cgrad(:viridis)[i*20] for i in 10:-1:1])

1 Like

Please find below the image above the Plots.jl code used to generate a dual colorbar scatterplot on top of a heatmap.

1 Like

Another option

using GMT

G = peaks(N=128);

# Interpolate the grid on scattered locations
xy = [(rand(50)*6 .- 3) (rand(50)*6 .- 3)];
Dxyz = grdtrack(G, xy);

# Colormaps for the image and the scatter
cmap1 = makecpt(G, C=:gray);
cmap2 = makecpt(G, C=:turbo);

grdimage(G, cmap=cmap1, colorbar=true)
scatter!(Dxyz, marker=:circ, color=cmap2, zcolor=Dxyz[:,3], colorbar=(position=(outside=true,anchor=:MR, offset=(2,0)), frame=:auto), show=1)

2 Likes