# Overlay a contour over a heatmap

**URL:** <https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586>\
**Category:** Visualization\
**Created:** [January 19, 2021, 6:58am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586 "2021-01-19T06:58:33Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![fkguo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fkguo/32/16866_2.png) [@fkguo](https://discourse.julialang.org/u/fkguo)\
**Post date:** [January 19, 2021, 6:58am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/1 "2021-01-19T06:58:33Z")

</div>

Hello,

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

```julia
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

 ![图片](https://global.discourse-cdn.com/julialang/original/3X/a/7/a7955cc7e9f29a67ff9897ec332a429946f1550f.jpeg)

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?

---

<div class="post-metadata">

**Author:** ![lazarusA](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lazarusa/32/6571_2.png) [@lazarusA](https://discourse.julialang.org/u/lazarusA)\
**Post date:** [January 19, 2021, 9:09am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/2 "2021-01-19T09:09:02Z")

</div>

A solution with Makie [sorry is not with Plots]

```julia
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

```

 ![FigMixHeatContour](https://global.discourse-cdn.com/julialang/original/3X/1/c/1c58d7f5fbdc65fd6e39f6e8dbd436c7487a9860.png)

---

<div class="post-metadata">

**Author:** ![fkguo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fkguo/32/16866_2.png) [@fkguo](https://discourse.julialang.org/u/fkguo)\
**Post date:** [January 20, 2021, 3:42am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/3 "2021-01-20T03:42:29Z")

</div>

Thank you for your suggestion!  
This indeed works. Is there a solution with Plots?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 20, 2021, 4:28pm UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/4 "2021-01-20T16:28:15Z")

</div>

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`

```julia
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")
p1_rgb, p2_rgb = load("p1.png"), load("p2.png")
plot(0.5*p1_rgb + 0.5*p2_rgb, ticks=nothing, border=:none, size=(700,700),dpi=300)

```

 ![plot_images_merged](https://global.discourse-cdn.com/julialang/original/3X/0/2/025d765827d3dbb080e6bcc77ccb7803f81f449a.png)

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

---

<div class="post-metadata">

**Author:** ![briochemc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/briochemc/32/4209_2.png) [@briochemc](https://discourse.julialang.org/u/briochemc)\
**Post date:** [January 20, 2021, 10:45pm UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/5 "2021-01-20T22:45:34Z")

</div>

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.,

```julia
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

```

 ![Screen Shot 2021-01-21 at 9.42.09 am](https://global.discourse-cdn.com/julialang/original/3X/7/4/74f949e856691f95450df1c5f16eeadfed4779aa.jpeg)

---

<div class="post-metadata">

**Author:** ![fkguo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fkguo/32/16866_2.png) [@fkguo](https://discourse.julialang.org/u/fkguo)\
**Post date:** [January 21, 2021, 8:08am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/6 "2021-01-21T08:08:05Z")

</div>

Thank you for your solution!

---

<div class="post-metadata">

**Author:** ![briochemc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/briochemc/32/4209_2.png) [@briochemc](https://discourse.julialang.org/u/briochemc)\
**Post date:** [January 21, 2021, 8:32am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/7 "2021-01-21T08:32:30Z")

</div>

No worries! My pleasure 😃

PS: I’m also happy you asked, because we also got a Makie solution 🙂

---

<div class="post-metadata">

**Author:** ![lazarusA](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lazarusa/32/6571_2.png) [@lazarusA](https://discourse.julialang.org/u/lazarusA)\
**Post date:** [January 21, 2021, 8:46am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/8 "2021-01-21T08:46:48Z")

</div>

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.

```julia
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

```

 ![FigMixHeatContour](https://global.discourse-cdn.com/julialang/original/3X/4/c/4c68e73e611b90c405155a5ef2c38b688d5201ac.png)

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 21, 2021, 11:06am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/9 "2021-01-21T11:06:43Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![lazarusA](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lazarusa/32/6571_2.png) [@lazarusA](https://discourse.julialang.org/u/lazarusA)\
**Post date:** [January 21, 2021, 11:16am UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/10 "2021-01-21T11:16:08Z")

</div>

ahh. 😄 yes, ok then everything is fine.

---

<div class="post-metadata">

**Author:** ![fkguo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fkguo/32/16866_2.png) [@fkguo](https://discourse.julialang.org/u/fkguo)\
**Post date:** [January 21, 2021, 1:59pm UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/11 "2021-01-21T13:59:59Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 21, 2021, 2:08pm UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/12 "2021-01-21T14:08:07Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![fkguo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fkguo/32/16866_2.png) [@fkguo](https://discourse.julialang.org/u/fkguo)\
**Post date:** [January 21, 2021, 2:29pm UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/13 "2021-01-21T14:29:48Z")

</div>

> [@rafael.guerra](#):
>
> @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.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [January 23, 2021, 12:02pm UTC](https://discourse.julialang.org/t/overlay-a-contour-over-a-heatmap/53586/14 "2021-01-23T12:02:11Z")

</div>

@fkguo, it is clear, thank you.
