Hi,
I have a figure with 8 subplots, arranged in two rows. I need to generate an automated code adding a centered title above each row, but fail to do so.
A sample code to illustrate the configuration (I also have annotations):
clf;
m = 2;
n = 4;
p = 1;
for i = 1:m*n
s(i) = subplot(m,n,p);
ant(i) = annotation('textbox',s(i).Position,'String',[num2str(i)+")"],...
'linestyle', 'none','Fontsize',14,'FontWeight','bold');
p = p + 1;
end
I want to place the titles without explictly give coordinates, i.e. something like titlehandle.position=[1 2 3 4] is not good, because I sometime use different computers/monitors/OS and the output is not consistent.
Thanks!

 Réponse acceptée

Adam Danz
Adam Danz le 4 Fév 2021
Modifié(e) : Adam Danz le 14 Juin 2024
Create one centered title per row of subplots
Three methods are included
  • Subplot with an odd number of columns
  • Subplot with an even number of columns
  • Tiledlayout (most robust) Preferred method
Subplot with an odd number of columns
Add the title to the middle subplot
Demo:
figure()
subplotLayout = [3,3];
ax = gobjects(fliplr(subplotLayout));
for i = 1:prod(subplotLayout)
ax(i) = subplot(subplotLayout(1),subplotLayout(2),i);
end
ax = ax'; % now axis handles are same shape as subplot layout
% list all titles in order (top to bottom)
titles = {'Row 1 title', 'Row 2 title', 'Row 3 title'};
% Get handles to center subplots
centerSubHandles = ax(:,ceil(subplotLayout(2)/2));
for i = 1:numel(centerSubHandles)
% get center subplot handle
title(centerSubHandles(i), titles{i})
end
Subplot with an even number of columns
Compute the upper position of each row of subplots in normalized units and the center position across the first row of subplots (assuming the center position is the same for all rows of subplots). Then use annotation to set the title position.
Demo:
figure()
subplotLayout = [3,4];
ax = gobjects(fliplr(subplotLayout));
for i = 1:prod(subplotLayout)
ax(i) = subplot(subplotLayout(1),subplotLayout(2),i);
end
set(ax,'Units','Normalize') % this is typically the default
ax = ax'; % now axis handles are same shape as subplot layout
% Reduce vertical space of axes just a bit to make room for "titles"
axPos = cell2mat(get(ax, 'Position'));
axPos(:,4) = axPos(:,4).*.96; % reduces vert space to 96% of height
set(ax, {'Position'}, mat2cell(axPos, ones(numel(ax),1), 4))
% Get upper position of each row of axes, normalized coordinates
axPos = cell2mat(get(ax(:,1), 'Position'));
axUpperPos = sum(axPos(:,[2,4]),2); %upper pos.
% Get center position for 1st row (assumes all rows have same center)
axPos = cell2mat(get(ax(1,[1,end]),'Position'));
axCenterPos = mean([axPos(1,1), sum(axPos(2,[1,3]))]);
% list all titles in order (top to bottom)
titles = {'Row 1 title', 'Row 2 title', 'Row 3 title'};
% Set annotation for each row of subplots
titleHandles = gobjects(numel(titles),1);
for i = 1:numel(titles)
titleHandles = annotation('textbox','String',titles{i}, ...
'Position', [axCenterPos, axUpperPos(i), 0, 0], ...
'HorizontalAlignment', 'center','VerticalAlignment','bottom',...
'LineStyle','none','FitBoxToText','on', ...
'FontWeight',ax(1).Title.FontWeight, ... % matches title property
'FontSize', ax(1).Title.FontSize, ... % matches title property
'FontName', ax(1).Title.FontName, ... % matches title property
'Color', ax(1).Title.Color); % matches title property
end
Tiledlayout (most robust, preferred method)
Added 24-April-2023
tiledlayout creates a TiledChartLayout object which can contain an array of axes, similar to subplot. But TiledChartLayout objects can also host a global title centered above the array of subplots.
Nest a TiledChartLayout for each row of axes and then assign a title to each row. This way you're actually using a title object rather than text.
axgrid = [3,4]; % [#rows, #cols]
titles = {'Row 1 title', 'Row 2 title', 'Row 3 title'};
figure()
tclMain = tiledlayout(axgrid(1),1);
tcl = gobjects(1,axgrid(1));
ax = gobjects(axgrid);
for j = 1:numel(tcl)
tcl(j) = tiledlayout(tclMain,1,axgrid(2));
tcl(j).Layout.Tile = j;
for i = 1:axgrid(2)
ax(j,i) = nexttile(tcl(j));
end
title(tcl(j),titles{j})
end
Create one global title per column
If the inidividual tiles do not have titles, the easiest approach would be to assign a title to the axes in the top row (assuming you're using a fixed layout).
If your axes do have titles and you want to add global titles for each column, you can use a nested tiledlayout approach demonstrated below.
axgrid = [3,4]; % [#rows, #cols]
titles = {'Col 1 title', 'Col 2 title', 'Col 3 title', 'Col 4 title'};
figure()
tclMain = tiledlayout(1,axgrid(2));
tcl = gobjects(1,axgrid(2));
ax = gobjects(axgrid);
for j = 1:numel(tcl)
tcl(j) = tiledlayout(tclMain,axgrid(1),1);
tcl(j).Layout.Tile = j;
for i = 1:axgrid(1)
ax(j,i) = nexttile(tcl(j));
title(sprintf('Tile %d',ax(j,i).Layout.Tile))
end
title(tcl(j),titles{j})
end

15 commentaires

yonatan s
yonatan s le 4 Fév 2021
I need above each row
Adam Danz
Adam Danz le 4 Fév 2021
Do you mean you want 1 title per row, centered in the row?
yonatan s
yonatan s le 4 Fév 2021
exactly.
Adam Danz
Adam Danz le 4 Fév 2021
I've updated my answer.
yonatan s
yonatan s le 5 Fév 2021
Very nice! Thanks for the code and the clearness.
Edward Meixner
Edward Meixner le 1 Fév 2023
How do you adjust the Fontsize?
Adam Danz
Adam Danz le 2 Fév 2023
title(__,'fontsize',18)
Edward Meixner
Edward Meixner le 2 Fév 2023
For this code?
Edward Meixner
Edward Meixner le 2 Fév 2023
I'm not familiar with how this portion works:
'FontSize', ax(1).Title.FontSize, ... % matches title property
Adam Danz
Adam Danz le 2 Fév 2023
The titles that go above each row of subplots are created by an annotation object. The annotation object has a fontsize property. I'm setting the value of the annotation fontsize to the same value of the axes title fontsizes.
To explore, ax(1).Title.FontSize returns a scalar value.
David Gonzalez
David Gonzalez le 11 Juin 2024
@Adam Danz how would you do it for colums?
Adam Danz
Adam Danz le 12 Juin 2024
@David Gonzalez I would assign a title to each axes in the top row, assuming you're not used a flow arrangement where the grid size changes according to figure size.
David Gonzalez
David Gonzalez le 13 Juin 2024
Each of my subplots have a title. But they are organized in a way that each colum belongs to a group. Therefore, I'd like a "column title" appart from each subplot title. I am usign the text function, but it is kind of tedious, plus if I change the size of my subplot (m,n) it becomes messy.
Adam Danz
Adam Danz le 14 Juin 2024
@David Gonzalez, I've updated my answer to add the demo "Create one global title per column". It's similar to "Tiledlayout (most robust, preferred method)".
David Gonzalez
David Gonzalez le 26 Juin 2024
Thanks @Adam Danz!

Connectez-vous pour commenter.

Plus de réponses (0)

Produits

Version

R2020b

Community Treasure Hunt

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

Start Hunting!

Translated by