# Plotting matrix (heatmap/pcolor/imshow) with log scales

**URL:** https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685
**Category:** Visualization
**Created:** [July 23, 2019, 1:32pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685 "2019-07-23T13:32:49Z")
**Posts on this page:** 12
**Page:** 1

<div class="post-metadata">

### Author: ![dapz](https://avatars.discourse-cdn.com/v4/letter/d/a4c791/32.png) [@dapz](https://discourse.julialang.org/u/dapz)
#### Post date: [July 23, 2019, 1:32pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/1 "2019-07-23T13:32:49Z")

</div>

Hi, I’m struggling with plotting a simple matrix with log-scales for x, y and/or color-axis.  
Consider e.g. a random 5\*5 matrix `a`, with associated values for `x` and `y` axis (these values are always regularly spaced, either in linear or log space).

```julia
a = 10 .^(3*randn(5,5))
x = 10 .^(1:5)
y = 1:5

```

So given these values, it makes sense to use logarithmic x- and color-scales.  
I tried with Plots.jl, first with GR backend:

```julia
heatmap(10 .^(1:5), 1:5, a, xscale=:log10)

```

which produces:  
 ![gr_xscalelog](https://global.discourse-cdn.com/julialang/original/3X/a/5/a5a037889532c1346b588c592c10595bd3f21fb8.png)  
here the xticks are perfect, but not the rendering of the matrix…  
Without the `xscale=:log10` option, the xticks are wrong… but the cells sizes well rendered:  
 ![gr_lincolor](https://global.discourse-cdn.com/julialang/original/3X/6/e/6e362b00abb810acb3f0b49719f4508e614efe0d.png)  
Now, independently from this xticks behavior, let’s check the colors (these are probably two different problems, but I need to find a solution fixing the two together).  
The `zscale=:log10` seems to be ineffective, so I tried to play with the color gradient to yield a good color rendering:

```julia
heatmap(10 .^(1:5), 1:5, a, cgrad=(scale=:log10))

```

![gr_logcolor](https://global.discourse-cdn.com/julialang/original/3X/1/7/1791d6fc019b19f9054fd0b444f090cd76afc869.png)  
I don’t quite understand how the transformation is computed, but it looks worse than before, so I also tried:

```julia
heatmap(10 .^(1:5), 1:5, a, cgrad=(scale=:exp))

```

which is better, but still not what I expect:  
 ![gr_expcolor](https://global.discourse-cdn.com/julialang/original/3X/c/2/c24b765930bb242771fbe05c6679619fa535d9ac.png)  
This should be compared to the range of colors you get when manually computing the log:

```julia
heatmap(10 .^(1:5), 1:5, log10.(a))

```

which produces:  
 ![gr_manuallog](https://global.discourse-cdn.com/julialang/original/3X/4/4/4406582f739391249e548d204458a21f6549dc33.png)  
The colors are much better, but the colorbar is now useless.

Now I also tried with PyPlot backend and `xscale=:log10`:

 ![plots_pyplot_xscalelog](https://global.discourse-cdn.com/julialang/original/3X/7/b/7b6f3d20b50ed4d785eae3f6c88c782e8db5bd54.png)  
The matrix display is great, but same problem with the colors.

Then I tried to use directly PyPlot, without Plots. I used the keyword argument `norm=matplotlib[:colors][:LogNorm]` which solves the color problem, but I can’t get the ticks to render correcly.  
First with `imshow`, I have trouble with the xaxis, even when using `xscale("log")`:

```julia
PyPlot.imshow(a, cmap=:RdBu, norm=matplotlib[:colors][:LogNorm](),extent=[1, 10^5, 1, 5])

```

 ![pyplot_imshow_extent](https://global.discourse-cdn.com/julialang/original/3X/9/3/93ea4e55cbc468230343f2aa7f4d4c0e528c158e.png)  
Then with `pcolor`, I have a bug with the first column, and also the ticks are now aligned to the begin/end of the axis, but they should be aligned with the centers of the bins. With a lin-scale I could use that and play manually with xticks, but with a log-scale it us much more annoying.

```julia
PyPlot.pcolor(10 .^(1:6),1:6, a, cmap=:RdBu, norm=matplotlib[:colors][:LogNorm]())

```

 ![pyplot_pcolor](https://global.discourse-cdn.com/julialang/original/3X/0/4/0409f0be65b11c21947b12e8e5546e993e2a23e4.png)

So none of these options works properly to me, does anyone know how to get that working?

I’m using julia 1.1.0, Plots 0.25.3, PyPlot 2.8.1.

---

<div class="post-metadata">

### Author: ![jheinen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jheinen/32/2787_2.png) [@jheinen](https://discourse.julialang.org/u/jheinen)
#### Post date: [July 23, 2019, 3:08pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/2 "2019-07-23T15:08:15Z")

</div>

log scaling seems to work fine in plain GR, so it can probably easily be fixed in Plots, too. Will check this later.

```julia
using GR
heatmap(randn(5,4), xlog=true)

```

---

<div class="post-metadata">

### Author: ![dapz](https://avatars.discourse-cdn.com/v4/letter/d/a4c791/32.png) [@dapz](https://discourse.julialang.org/u/dapz)
#### Post date: [July 24, 2019, 6:56am UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/3 "2019-07-24T06:56:55Z")

</div>

Thanks. With plain GR, how would you specify the values on the x axis ? because your code does indeed produces a logscale for x and does aligns the xticks properly, but on the values 1:5, and as a consequence the bins have different sizes. But the GR heatmap function does not take `x` and `y` arguments like Plots does. Also, is there a way to solve the colormap problem in plain GR? I had a quick look at the doc, but no success so far.

---

<div class="post-metadata">

### Author: ![dapz](https://avatars.discourse-cdn.com/v4/letter/d/a4c791/32.png) [@dapz](https://discourse.julialang.org/u/dapz)
#### Post date: [July 24, 2019, 10:58am UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/4 "2019-07-24T10:58:22Z")

</div>

OK, below is the workaround I came with using PyPlot, and the output. I had trouble with my first toy example where the range for z was too high and the ticks not displaying, but it was actually unrelated to the log-scale, it works when `norm=…` is passed to `pcolor`. Regarding x- and y- ticks, I do manually compute them.

If someone knows if it is possible to achieve this behavior with Plots, I would be grateful.

Also, after thinking a bit more, the `scale=:log10` option of `cgrad` cannot possibly solve the problem as we need to use the range of z when creating the gradient. So there should be another `zscale` option to use here, I probably didn’t understand correctly how to use that, or maybe it is a limitation of Plots?

```julia
a = 10 .^(1*randn(5,5));
custom_heatmap(10 .^(1:5), 1:5, a, xscale=:log10, zscale=:log10)

```

![good](https://global.discourse-cdn.com/julialang/original/3X/9/1/91d71b5ff55ed3e78d1ab7b674b2719796056d4f.png)

```julia
# ===== Manually extending ticks values for pcolor =====

# For n values (ticks) corresponding to the centers of n equally-spaced bins,
# returns n+1 ticks corresponding to the borders before/between/after the bins.
function extend_lin(x)
	n = length(x)
	m, M = minimum(x), maximum(x)
	halfbin = (M - m )/(2(n-1))
	return range(m - halfbin, M + halfbin, length = n+1)
end
extend_log10(x) = 10 .^(extend_lin(log10.(x)))

function extend_from_spacing(x, sp)
	if sp == :lin
		extend_lin(x)
	elseif sp == :log10
		extend_log10(x)
	else error("Unsupported spacing '$sp'.") end
end

# ===== Detecting lin- or log-spaced data =====

lindiff(x) = [x[i+1] - x[i] for i in 1:(length(x)-1)]
logdiff(x) = [x[i+1]/x[i] for i in 1:(length(x)-1)]
function findspacing(x)
	@assert length(x)>2
	lgd = unique(logdiff(x)) # TODO catch zeros
	if all(lgd[1] .≈ lgd)
		if lgd[1] ≈ 10
			return :log10
		elseif lgd[1] ≈ exp(1)
			return :log
		end
	end
	lid = unique(lindiff(x))
	if all(lid[1] .≈ lid)
		return :lin
	end
	@warn "Could not detect lin/log regular spacing. Using lin without any guarantees."
	:lin
end

# ===== Plotting =====

function custom_heatmap(x, y, z; 
			  clear = true, 
			  xscale = :lin, 
			  yscale = :lin, 
			  zscale = :lin, 
			  kwargs...)

	clear && clf()	# Don't know how to avoid multiple colorbars otherwise when replotting
	@assert all([s in [:lin, :log10] for s in [xscale, yscale, zscale]])
	xsp = findspacing(x)
	ysp = findspacing(y)
	nx = extend_from_spacing(x, xsp)
	ny = extend_from_spacing(y, ysp)
	xscale == :log10 && PyPlot.xscale("log")
	yscale == :log10 && PyPlot.yscale("log")
	extra_args = Dict{Symbol, Any}()
	if zscale == :log10
		extra_args[:norm] = matplotlib[:colors][:LogNorm]()
	end
	p = PyPlot.pcolor(nx, ny, z; merge(extra_args, kwargs)...)
	c = colorbar(p)
	return p
end

```

---

<div class="post-metadata">

### Author: ![jheinen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jheinen/32/2787_2.png) [@jheinen](https://discourse.julialang.org/u/jheinen)
#### Post date: [July 24, 2019, 12:36pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/5 "2019-07-24T12:36:21Z")

</div>

In GR, the above plot can only be created using low-level functions, not with a single call. You will have to set scales, draw axes and the histogram separately - probably not what you want.

May be, Plots ha a recipe for this - I don’t know.

---

<div class="post-metadata">

### Author: ![henry2004y](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henry2004y/32/9284_2.png) [@henry2004y](https://discourse.julialang.org/u/henry2004y)
#### Post date: [May 7, 2021, 10:14am UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/6 "2021-05-07T10:14:51Z")

</div>

This might be an relatively “old” post, but I am still suffering from getting a working log color scale heatmap:

```julia
using Plots
gr()
x = LinRange(-2, 2, 40)
y = LinRange(0, pi, 20)
z = abs.(50 .* sin.(x') .+ cos.(y))
heatmap(z, cgrad=(scale=:log10))

```

![test](https://global.discourse-cdn.com/julialang/original/3X/5/8/58de701faf97ac0ffbcaeff028f0e38755a4a467.png)

Besides, I haven’t found any related documenation in either GR.jl or GRUtils.jl.

---

<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: [May 7, 2021, 2:55pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/7 "2021-05-07T14:55:59Z")

</div>

It does not seem to work in gr() but one can always heatmap log10 of the data:  
`heatmap(log10.(z))`  
 ![log10_heatmap2](https://global.discourse-cdn.com/julialang/original/3X/4/7/475e26e7c1b2e9a83da2596fea4eee80cd90ff4d.png)

---

<div class="post-metadata">

### Author: ![henry2004y](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henry2004y/32/9284_2.png) [@henry2004y](https://discourse.julialang.org/u/henry2004y)
#### Post date: [May 7, 2021, 3:38pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/8 "2021-05-07T15:38:20Z")

</div>

Yes, but I am wondering why the `scale` keyword in `cgrad` doesn’t do anything, even though it exists. Perhaps it would be clearer to look at the source code then, but that takes more time and effort.

---

<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: [May 7, 2021, 4:15pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/9 "2021-05-07T16:15:43Z")

</div>

Ok, I know this is not done with Plots, but if your are up to try [Gnuplot.jl](https://github.com/gcalderone/Gnuplot.jl) then the following works pretty well in every dimension, colors, x and y.

```julia
using Gnuplot
@gp exp10.(2*rand(100,100)) "w image pixels not" "set logscale cb"
@gp :- "set auto fix" "set size square" palette(:plasma)
@gp :- "set logscale x" "set logscale y" xrange = (1,100) yrange = (1,100)
save(term="pngcairo size 640,600", output="FigHeatmap_logscales.png")

```

 ![FigHeatmap_logscales](https://global.discourse-cdn.com/julialang/original/3X/8/0/80b5709bae61a7f03ccbc2dadc46cbdb660cf296.png)

---

<div class="post-metadata">

### Author: ![zhiyuanzhai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zhiyuanzhai/32/9519_2.png) [@zhiyuanzhai](https://discourse.julialang.org/u/zhiyuanzhai)
#### Post date: [May 9, 2021, 12:46pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/10 "2021-05-09T12:46:29Z")

</div>

Well… I guess this might be a bug.

---

<div class="post-metadata">

### Author: ![Si\_Chen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/si_chen/32/37487_2.png) [@Si\_Chen](https://discourse.julialang.org/u/Si_Chen)
#### Post date: [June 27, 2022, 9:29pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/11 "2022-06-27T21:29:27Z")

</div>

Hi all,  
I have to refresh this post and really need your insights as I still have a problem plotting heatmap with log colorbar even with Gnuplot.jl. I currently use the following code

```julia
@gp P_save "w image notit" "set logscale cb" 

```

which generates the following figure

 ![test](https://global.discourse-cdn.com/julialang/original/3X/e/1/e1a6fac70499ca08727d10a44819d3e95c4a763f.png)

The problem is I need to replace y axis with its real value (using another vector called `Depth` )rather than using index from 0 to 150. And `Depth` has Non-uniform grid.  
Do the same for x axis too.

P\_save is 150×731 Matrix{Float64}:

I am very new to both Gnuplot.jl and gnuplot.

Thank you so much!

---

<div class="post-metadata">

### Author: ![jcbritobr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jcbritobr/32/219275_2.png) [@jcbritobr](https://discourse.julialang.org/u/jcbritobr)
#### Post date: [July 3, 2022, 5:32pm UTC](https://discourse.julialang.org/t/plotting-matrix-heatmap-pcolor-imshow-with-log-scales/26685/12 "2022-07-03T17:32:59Z")

</div>

If I understood well, with heatmap from plots.jl you can change the colums with a string array

> [@Heatmap Plots.jl](https://discourse.julialang.org/t/heatmap-plots-jl/39406):
>
> Good afternoon! I can not get the heatmap plot in the Plots.jl package to do what I would like. If I do: using Plots backend(:plotly) p = heatmap([1,2,3,1,2,3,1,2,3],[1,1,1,2,2,2,3,3,3],[1,1,1,1,1,1,1,1,1]) gui(p) I get the result: [newplot] while I expect some kind of plot homogeneously filled with ones. (maybe from 0,5 to 3,5 in x and y?) What am I missing?
