I'm trying to plot 3D bar chart in MATLAB with colormap. The colormap wasn't showing up. Then I found a work around to apply colormap on bar3:
b = [...] % my data
b = bar3(Z, 1);
for k = 1:length(b)
zdata = b(k).ZData;
b(k).CData = zdata;
b(k).FaceColor = 'interp';
end
colormap('jet')
I'm also applying log scale in Z axis. But it was messing up my plot showing only the top surfaces of the bars. I found a work around for this also.
% Z log fix
llim = .1;
h = get(gca,'Children');
for i = 1:length(h)
ZData = get(h(i), 'ZData');
ZData(ZData==0) = llim;
set(h(i), 'ZData', ZData);
end
set(gca,'ZScale','log')
But I'm getting the following result after the log fix where the bars don't have same color at the same Z value (height).
I'm trying to get results like the following plot.
My MATLAB version is R2022a.
Anyone know the solution?
The default CDataMapping
is "scaled", by using "direct" mapping you can avoid problems which seem to be arising from dodgy indexing of your colour map in combination with the log scale.
From the surface property docs:
'direct' — Interpret the values as indices into the current colormap. Values with a decimal portion are fixed to the nearest lower integer. [...]
'scaled' — Scale the values to range between the minimum and maximum color limits. The CLim property of the axes contains the color limits.
The scale you want is 255 * log10(zdata) ./ mx
, because
I suspect, without proof, that the automatic scaling isn't taking the log of zdata when you expect it to, so the indexing is all wrong.
A full example, including your face colouring and log(0) fixes from your question, would look something like this:
% Create some random data
rng(0);
z = 10.^(rand(1,20)*3 + [20,16,10,5,1,0,0].');
% Make the bar plot
figure(1); clf;
b = bar3( z, 1 );
llim = .1; % Min value to avoid log(0) issues
mx = log10(max(z(:),[],'omitnan')); % log of max value in data
% Loop over all bars to recolour
for k = 1:length(b)
% Fix log(0) issue which breaks surfaces
ZData = get(b(k), 'ZData');
ZData(ZData==0) = llim;
set(b(k), 'ZData', ZData);
% Set new CData according to direct scaling between 0 and 255
b(k).CData = 255 * log10(b(k).ZData) ./ mx;
b(k).CDataMapping = 'direct';
% Interp over face for gradient
b(k).FaceColor = 'interp';
end
colormap('jet'); % Set colourmap
set(gca,'ZScale','log'); % Set log scale
Output: