# Overlay a contour over a heatmap

Hello,

I have difficulty overlaying a contour plot over a heatmap. Here is an example

``````let
f(x,y) = (x + 2y^2) * abs(sin(y) + cos(x))
p1 = heatmap(1:0.5:20, 1:0.5:20, f, alpha=0.3)
p2 = Plots.contourf(1:0.5:20, 1:0.5:20, (x,y)->10f(x,y),
c=:black, levels=[100,101], colorbar=false)
p3 = heatmap(1:0.5:20, 1:0.5:20, f, alpha=0.3)
Plots.contour!(1:0.5:20, 1:0.5:20, (x,y)->10f(x,y),
c=:black, levels=[100,101], colorbar=false)
plot(p1, p2, p3, layout =(1,3), size=(1000,350))
end
``````

The outcome is

That is I tried to overlay the second plot over the first one, but with `contour!` I got the third one, where the color distribution in the `heatmap` is almost invisible. Is there a way to get a proper overlaid plot in this case?

A solution with Makie [sorry is not with Plots]

``````using CairoMakie
f(x,y) = (x + 2y^2) * abs(sin(y) + cos(x))
x = y = 1:0.5:20
z = [f(x,y) for x in x, y in y]
fig = Figure(resolution=(750,300), fontsize = 14)
ax1 = Axis(fig, aspect = 1, xlabel = "x", ylabel = "y")
ax2 = Axis(fig, aspect = 1,  xlabel = "x")
ax3 = Axis(fig, aspect = 1,  xlabel = "x")
p1 = heatmap!(ax1, x, y, z, colormap = :Spectral)
contour!(ax2, x, y, z, color = :black, levels = 100:1:101) # contourf! also works... but with colormap
heatmap!(ax3, x, y, z, colormap = (:Spectral, 0.3))
contour!(ax3, x, y, z, color = :black, levels = 100:1:101)
cbar = Colorbar(fig, p1, width = 10, hight = Relative(0.8), ticklabelsize = 10)
limits!(ax2, 0,20,0,20)
hideydecorations!(ax2, grid = false)
hideydecorations!(ax3, grid = false)
fig[1,1] = ax1
fig[1,2] = cbar
fig[1,3] = ax2
fig[1,4] = ax3
save("./results/FigMixHeatContour.png", fig, px_per_unit = 2)
fig
``````

8 Likes

This indeed works. Is there a solution with Plots?

A different solution using `Plots` and `Images`, that someone more knowledgeable may be able to refine further.
PS: set `dpi=300` and displayed `f `in both `heatmap` and `contour`

``````using Images, Plots; gr()
f(x,y) = (x + 2y^2) * abs(sin(y) + cos(x))
x = y = 1:0.2:20
p1 = heatmap(x, y, f, size=(700,700), xlims=(1,20), ylims=(1,20), colorbar=false, dpi=300)
savefig("p1.png")
p2 = contour(x,y,(x,y)->f(x,y), c=:black,levels=[100,101],size=(700,700),xlims=(1,20),ylims=(1,20),colorbar=false, dpi=300)
savefig("p2.png")
plot(0.5*p1_rgb + 0.5*p2_rgb, ticks=nothing, border=:none, size=(700,700),dpi=300)
``````

I would be interested in knowing how to obtain the RGB image array directly from Plots, without saving/loading images to disk.

The issue was that `10f`, plotted with `contour`, silently changed the `clim` (of `f` plotted with `heatmap`). I think you can fix that with the `clim` kwarg, e.g.,

``````using Plots
f(x,y) = (x + 2y^2) * abs(sin(y) + cos(x))
x, y = 1:0.5:20, 1:0.5:20
p1 = heatmap(x, y, f, size=(700,700), α=0.5)
contour!(p1, x, y, (x,y)->10f(x,y), c=:black, levels=100:100, clim=(0,1500)) # note the clim kwarg
``````

3 Likes

No worries! My pleasure PS: I’m also happy you asked, because we also got a Makie solution Although, I’m afraid one of them is wrong. The contour lines are different. For me it makes sense to have lines around the big jumps, because the values are lower. I’m not sure what’s happening in the Plots solution. Increasing the grid points it’s more clear.

``````using CairoMakie
f(x,y) = (x + 2y^2) * abs(sin(y) + cos(x))
x = y = 1:0.2:20
z = [f(x,y) for x in x, y in y]
fig = Figure(resolution=(750,300), fontsize = 14)
ax1 = Axis(fig, aspect = 1, xlabel = "x", ylabel = "y")
ax2 = Axis(fig, aspect = 1,  xlabel = "x")
ax3 = Axis(fig, aspect = 1,  xlabel = "x")
p1 = heatmap!(ax1, x, y, z, colormap = :plasma)
contour!(ax2, x, y, z, color = :black, levels = 100:1:101) # contourf! also works... but with colormap
heatmap!(ax3, x, y, z, colormap = (:plasma, 0.5))
contour!(ax3, x, y, z, color = :white, levels = 100:1:101)
cbar = Colorbar(fig, p1, width = 10, hight = Relative(0.8), ticklabelsize = 10, tickalign = 1)
limits!(ax2, 1,20,1,20)
hideydecorations!(ax2, grid = false)
hideydecorations!(ax3, grid = false)
fig[1,1] = ax1
fig[1,2] = cbar
fig[1,3] = ax2
fig[1,4] = ax3
#save("./results/FigMixHeatContour.png", fig, px_per_unit = 2)
fig
`````` 2 Likes

@lazarusA, the problem is that original post heatmaps `f` but contours `10*f`, if we fix this to display `f` only, results are similar.

ahh. yes, ok then everything is fine.

Yes, I put this factor of `10` in purpose to expose the issue.

@fkguo, because it was not exposed enough without it?

sorry for the confusion. I meant to expose the issue that the color in the heatmap would be destroyed by the `contour!` if the values of the contoured function are much larger.
As pointed out in the Plots solution, the large values of the contoured function change `clim` so that the pattern in heatmap becomes invisible.

@fkguo, it is clear, thank you.