Numbers on the middle of colorbar in MATLAB
3 views (last 30 days)
Show older comments
How to create a colorbar in MATLAB like this in which the numebrs comes exactly on the colorbar cell.
0 Comments
Answers (3)
Ayush
on 30 Sep 2024
I understand you need to create a “colorbar” in MATLAB with text inside the “colorbar” cell.
This can be achieved using “annotation” objects (for example textbox)
Here’s the code for the same:
figure
hcb = colorbar;
hcb.Position(3)=0.1;
hcb.Position(4)=0.5;
hcb.TickLabels = [];
tix = reshape([hcb.Ticks; repmat(" ", 1, numel(hcb.Ticks))],[],1);
pos = hcb.Position;
t=annotation('textbox',pos,'String',flip(tix), 'LineStyle','none', 'FontWeight','bold')
t.HorizontalAlignment="right";
t.VerticalAlignment = "middle";
size(hcb.TickLabels);
sz=size(tix);
You can read more about “annotation” function and its properties here: https://www.mathworks.com/help/matlab/ref/annotation.html
You can read about “textbox” properties here: https://www.mathworks.com/help/matlab/ref/matlab.graphics.shape.textbox-properties.html
Hope this helps!
4 Comments
Ayush
on 1 Oct 2024
Edited: Ayush
on 1 Oct 2024
you can use callback function to track the "resize" operation on the colorbar and adjust the position of labels accordingly.
Here's a script using this approach:
matrix = magic(3);
imagesc(matrix)
% Define levels and number of ticks (customizable)
levels = 9; % Change this to adjust the number of ticks
tick_vals = linspace(min(matrix(:)), max(matrix(:)), levels);
% Setting up the figure and color settings
current_figure = gcf;
colormap_tones = jet(numel(tick_vals)); % Using jet colormap for a different approach
colormap(colormap_tones)
color_scale = colorbar('Ticks', tick_vals);
% Adjusting the color axis limits based on the range of ticks
color_limits = [min(tick_vals)-0.5, max(tick_vals)+0.5];
caxis(color_limits);
% Convert the tick positions to figure space
colorbar_pos = color_scale.Position;
tick_positions = rescale_range(tick_vals, color_limits, colorbar_pos(2) + [0 colorbar_pos(4)]);
% Generating custom tick labels
for i = 1:numel(tick_vals)
gray_intensity = double(rgb2gray(1 - colormap_tones(i,:)) > 0.5);
annotation('textbox', [colorbar_pos(1), tick_positions(i), 0.05, 0.05], ...
'String', num2str(round(tick_vals(i),2)), 'VerticalAlignment', 'middle', ...
'Color', gray_intensity, 'LineStyle', 'none', 'FontWeight', 'bold');
end
% Hide default tick labels on the colorbar
color_scale.TickLabels = [];
% Adding dynamic resizing behavior for figure
set(current_figure, 'ResizeFcn', @(~,~) adjust_on_resize(color_scale, tick_vals));
% Rescaling the function to update tick positions during figure resize
function adjust_on_resize(color_scale, tick_vals)
colorbar_pos = color_scale.Position;
new_tick_positions = rescale_range(tick_vals, [min(tick_vals)-0.5, max(tick_vals)+0.5], colorbar_pos(2) + [0 colorbar_pos(4)]);
for i = 1:numel(tick_vals)
annotation('textbox', [colorbar_pos(1), new_tick_positions(i), 0.05, 0.05], ...
'String', num2str(round(tick_vals(i),2)), 'LineStyle', 'none');
end
end
% Helper function to rescale values to a new range
function output_vals = rescale_range(input_vals, input_range, output_range)
output_vals = rescale(input_vals, output_range(1), output_range(2), 'InputMin', input_range(1), 'InputMax', input_range(2));
end
Note:I
f the labels extend beyond the boundaries of the colorbar, consider defining custom positions for the labels by adjusting their placement according to the required width of the colorbar.
Hope this helps!
DGM
on 30 Sep 2024
Edited: DGM
on 1 Oct 2024
Assuming a discrete colorbar,
% the setup
z = magic(3);
imagesc(z)
% the values associated with each discrete level
ticks = 1:9;
% set the colormap and colorbar
nticks = numel(ticks);
CT = parula(nticks);
colormap(CT)
hcb = colorbar;
hcb.Ticks = ticks;
% set clim so that our ticks are centered on their respective subinterval
% if your ticks are not uniformly-spaced integers, then this needs adjusting
cbrange = imrange(ticks) + [-0.5 0.5];
clim(cbrange);
% rescale tick position from data space to figure space
pos = hcb.Position;
tposy = pos(2) + [0 pos(4)];
tposy = rescalefix(ticks,cbrange,tposy);
% create new ticks
for k = 1:nticks
thislabel = sprintf('%d',ticks(k));
thispos = [pos(1)+pos(3)/2 tposy(k) 0 0];
thiscolor = double(rgb2gray(1-CT(k,:))>0.5);
annotation('textbox',thispos,'string',thislabel, ...
'horizontalalignment','center','verticalalignment','middle', ...
'color',thiscolor,'linestyle','none', 'fontweight','bold');
end
% hide the old ticks once you're sure the new ones are okay
hcb.TickLabels = [];
EDIT: That should help make the labels more readable.
3 Comments
DGM
on 1 Oct 2024
Edited: DGM
on 1 Oct 2024
It looks like you're resizing the figure. If you do that, the relative positions change. You need to update the annotation positions.
% the setup
z = magic(3);
imagesc(z)
% the values associated with each discrete level
ticks = 1:9;
% we need the figure handle later
hfig = gcf;
% set the colormap and colorbar
nticks = numel(ticks);
CT = parula(nticks);
colormap(CT)
hcb = colorbar;
hcb.Ticks = ticks;
% set clim so that our ticks are centered on their respective subinterval
% if your ticks are not uniformly-spaced integers, then this needs adjusting
cbrange = imrange(ticks) + [-0.5 0.5];
clim(cbrange);
% rescale tick position from data space to figure space
pos = hcb.Position;
tposy = pos(2) + [0 pos(4)];
tposy = rescalefix(ticks,cbrange,tposy);
% create new ticks
han = gobjects(nticks,1);
for k = 1:nticks
thislabel = sprintf('%d',ticks(k));
thispos = [pos(1)+pos(3)/2 tposy(k) 0 0];
thiscolor = double(rgb2gray(1-CT(k,:))>0.5);
han(k) = annotation('textbox',thispos,'string',thislabel, ...
'horizontalalignment','center','verticalalignment','middle', ...
'color',thiscolor,'linestyle','none', 'fontweight','bold');
end
% hide the old ticks once you're sure the new ones are okay
hcb.TickLabels = [];
% set up a callback that fires when the figure is resized
hfig = gcf; % or use whatever the relevant figure handle is
set(hfig,'resizefcn',{@onresize,ticks,cbrange,hcb,han})
% function to do the size update
function onresize(~,~,ticks,cbrange,hcb,han)
% rescale tick position from data space to figure space
pos = hcb.Position;
tposy = pos(2) + [0 pos(4)];
tposy = rescalefix(ticks,cbrange,tposy);
% adjust ticks
for k = 1:numel(ticks)
thispos = [pos(1)+pos(3)/2 tposy(k) 0 0];
han(k).Position = thispos;
end
end
DGM
on 1 Oct 2024
I don't know what the motivation for this layout actually is, but it should be clear that managing annotations and trying to do direct manipulation of the colorbar costs extra effort and complexity for whatever benefit it has.
On the downside, I think it reduces the readability of both the color patches and the tick labels.
Also note that moving the tick labels into the colorbar doesn't save any space. We never moved the colorbar (and axes) to take advantage of the empty space left by removing the original labels. Doing that would take yet more work to complicate the layout.
Likewise, larger ticklabels would require the colorbar (and the axes) to be resized and repositioned so that the colorbar can be wide enough to accomodate the labels.
Star Strider
on 30 Sep 2024
It can be done using annotation objects (specifically textbox) however it is definitely a challenge.
Try something like this —
figure
surf(peaks)
hcb = colorbar;
% get(hcb)
hcb.TickLabels = [];
tix = reshape([hcb.Ticks; repmat(" ", 1, numel(hcb.Ticks))],[],1);
pos = hcb.Position;
annotation('textbox',pos,'String',flip(tix), 'LineStyle','none', 'FontWeight','bold')
.
6 Comments
See Also
Categories
Find more on Colormaps in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!