Heatmap log colour scale: caxis() doesn't map values correctly?

12 views (last 30 days)
Duncan Ingram on 1 Dec 2021
Commented: Duncan Ingram on 1 Dec 2021
I have a 2D array with logarithmically distributed values from [1e-5, 1e5]. For various reasons, I want to change the colourbar with limits beyond this range. I do this using caxis, e.g. caxis([a,b]), where a and b are the desired exponents. However the resulting colourbar does not map correctly.
Example problem, starting with log-distributed values and desired limits of [1e-5, 1e5]:
% Create log values and generate heatmap
dim = 10;
x = logspace(-5,5,dim);
values = repmat(x,[dim,1]);
hm = heatmap(values);
% Make visually clearer
hm.GridVisible = 'off';
colormap default
ax1 = gca;
ax1.XDisplayLabels = nan(length(ax1.XDisplayData),1);
ax1.YDisplayLabels = nan(length(ax1.YDisplayData),1);
% Colour bar scaling - PROBLEM
set(gca,'ColorScaling','log') % Log scale
caxis([-5,5]) % Lower/Upper limits (exponents) (to change!)
ax2 = struct(gca);
cb = ax2.Colorbar;
cb.Ticks = [1e0,1e1,1e2,1e3,1e4,1e5]; % Example ticks to show problem...
After the limits are specified, the colour mapping becomes skewed. If you pause the code after the 'set' line, the caxis values give [-11.5, 11.5], not [-5, 5]. Therefore, if I desire a fixed colour range such as [1e-7, 1e7], I apparently need to fudge the values. What's going on? Does caxis() not define exponents in the way that it should?

DGM on 1 Dec 2021
Edited: DGM on 1 Dec 2021
You're expecting that caxis expects log10(limits). It's actually expecting the natural log.
% Create log values and generate heatmap
dim = 11; % just so the data labels show up
x = logspace(-5,5,dim);
values = repmat(x,[dim,1]);
hm = heatmap(values);
% Make visually clearer
hm.GridVisible = 'off';
colormap default
ax1 = gca;
ax1.XDisplayLabels = nan(length(ax1.XDisplayData),1);
ax1.YDisplayLabels = nan(length(ax1.YDisplayData),1);
% Colour bar scaling
set(gca,'ColorScaling','log') % Log scale
caxis(log([x(1) x(end)])); Now you should be able to set arbitrary caxis limits.
% caxis(log([1E-7 1E7]));
Duncan Ingram on 1 Dec 2021
Ahh thank you so much! Natural log vs. log10 went through my head at some point, but for some reason I never took it further. The log([a b]) conversion is so simple yet explains all my 'scaling issues' perfectly.

Mathieu NOE on 1 Dec 2021
hello
no mre problem my friend ! % Create log values and generate heatmap
dim = 10;
x = logspace(-5,5,dim);
values = repmat(x,[dim,1]);
hm = heatmap(values);
% Make visually clearer
hm.GridVisible = 'off';
ax1 = gca;
ax1.XDisplayLabels = nan(length(ax1.XDisplayData),1);
ax1.YDisplayLabels = nan(length(ax1.YDisplayData),1);
% Colour bar scaling
N = 256; % colorbar discrete values
cmap = colormap(jet(N)) ; %Create Colormap
set(gca,'ColorScaling','log') % Log scale
ax2 = struct(gca);
cbh = ax2.Colorbar;
tmp = logspace(min(log10(values),[],'all'), max(log10(values),[],'all'), dim+1);
cbh.Ticks = tmp ; %Create N ticks from min to max of Z array
cbh.TickLabels = num2cell(tmp) ; %Replace the labels of these N ticks with the numbers defined in "tmp"
Duncan Ingram on 1 Dec 2021
Thanks for this example, however it doesn't solve my general problem of specifying a general range for the colourbar. E.g. how would I create an equivalent heatmap with a colourbar from [1e-7, 1e7] (with the same data!).
Also, I can achieve the same result as your example by simply stopping my code after the 'set' line.

R2020b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!