Legend Placement in Nested Tile Layout

18 次查看(过去 30 天)
Here is the figure my code currently creates:
I want to produce exaclty this same figure, but with the legend in the bottom middle, rather than the bottom. As I understand it, the problem is that legend takes in the axes for the second tile in the nested layout as its position argument. I think I need to use a nested tiled layout in order to get a title for each column (currently "test1" and test2").
My code is paasted below. I really appreciate any help/suggestions!
figure('Position', [0, 0, 1200, 600]); % Adjust the size as needed
T=tiledlayout(1, length(cdfs_in)); %
for i=1:length(cdfs_in)
t=tiledlayout(T,2,1);
title(t, titles(i));
t.Layout.Tile = i;
t.Layout.TileSpan = [1 1];
t.TileSpacing = 'compact';
nexttile(t);
plot(soph, utils_sinc(:,1,i))
hold on
plot(soph, utils_sinc(:,2,i))
hold on
plot(soph, utils_sinc(:,3,i))
hold off
ylabel("Mean Utility", 'FontSize', 12);
xlabel("Fraction of Students who are Sophisticated (P_{soph})", 'FontSize', 12);
title("Sincere Students", 'FontWeight', 'normal');
nexttile(t)
plot(soph, utils_tot(:,1,i))
hold on
plot(soph, utils_tot(:,2,i))
hold on
plot(soph, utils_tot(:,3,i))
hold off
title("All Students", 'FontWeight', 'normal');
xlabel("Fraction of Students who are Sophisticated (P_{soph})", 'FontSize', 12);
ylabel("Mean Utility", 'FontSize', 12);
end
lgd = legend('Optimal Taiwan Mechanism', 'Boston Mechanism', 'Deferred Acceptance', 'location', 'Best');
lgd.Layout.Tile = 'south';

采纳的回答

Harsha Vardhan
Harsha Vardhan 2023-12-28
Hi,
I understand that you want the legend to be displayed at the bottom middle rather than at the bottom.
Based on your description, the issue arises because the legend is currently aligned with the axes of the second tile in your nested layout. Let's address this to achieve the desired placement.
I recreated your figure using dummy data and viewed the figure in Property Inspector as below.
We can notice that the legend, by default, is linked as a child to the most recently active tiled layout. In your case, it's the inner layout, hence the legend aligning to the bottom of the second tile. Your current approach using
lgd.Layout.Tile = 'south';
is south-aligning the legend as a child to this inner layout created in the line ‘
t=tiledlayout(T,2,1);
To overcome this, we need to redirect the legend's association as a child from the inner tiled layout to the outer one. However, directly changing the parent of the legend using
lgd.Parent = T;
leads to an error as below due to the legend's linked axes belonging to the inner layout.
'A legend and its associated axes must have the same parent'
This is because the axes associated with the legend is the most recently created axes and is a child of the inner tiled layout. This is the axes created in the second execution of
nexttile(t).
The solution is to create an auxiliary, invisible axis associated with the outer layout. This axis will act as a placeholder for the legend without altering your current figure structure. Here's how we can do it:
  1. Generate a dummy axis in the outer layout.
  2. Plot invisible or NaN data on this axis, ensuring it doesn't disrupt your existing plot.
  3. Assign the legend to this dummy axis and position it at the bottom middle, achieving the layout you desire.
This approach maintains the structural integrity of your nested layout while allowing the flexibility to position the legend as needed.
Please check the modified code that implements this solution.
%Generating Dummy data for the purpose of this solution
% Assuming cdfs_in represents some groups or conditions
cdfs_in = 1:2; % For example, we have 2 conditions
% Define titles for the tiled plots
titles = {'test 1', 'test 2'};
% 'soph' can be a linear space vector, representing a fraction of sophisticated students
soph = linspace(0.3, 0.7, 100); % 100 points between 0.3 and 0.7
% 'utils_tot' is a 3D matrix for utility values with dimensions corresponding to:
% - number of 'soph' points (100)
% - number of strategies/mechanisms (3)
% - number of conditions in 'cdfs_in' (length of cdfs_in)
utils_sinc = rand(100, 3, length(cdfs_in)) * 0.5 + 1; % Random data for sincere students
utils_tot = rand(100, 3, length(cdfs_in)) * 0.5 + 1; % Random data for all students
figure('Position', [0, 0, 1200, 600]); % Adjust the size as needed
T=tiledlayout(1, length(cdfs_in));
for i=1:length(cdfs_in)
t=tiledlayout(T,2,1);
title(t, titles(i));
t.Layout.Tile = i;
t.Layout.TileSpan = [1 1];
t.TileSpacing = 'compact';
nexttile(t);
plot(soph, utils_sinc(:,1,i))
hold on
plot(soph, utils_sinc(:,2,i))
hold on
plot(soph, utils_sinc(:,3,i))
hold off
ylabel("Mean Utility", 'FontSize', 12);
xlabel("Fraction of Students who are Sophisticated (P_{soph})", 'FontSize', 12);
title("Sincere Students", 'FontWeight', 'normal');
nexttile(t)
plot(soph, utils_tot(:,1,i))
hold on
plot(soph, utils_tot(:,2,i))
hold on
plot(soph, utils_tot(:,3,i))
hold off
title("All Students", 'FontWeight', 'normal');
xlabel("Fraction of Students who are Sophisticated (P_{soph})", 'FontSize', 12);
ylabel("Mean Utility", 'FontSize', 12);
end
% Create a dummy axes for placing the legend at the bottom
ax = axes(T, 'Visible', 'off');
% Plot dummy lines with the same properties as your actual data plots
hold(ax, 'on'); % Hold the dummy axes for multiple plots
hOptimal = plot(ax, NaN, NaN, 'DisplayName', 'Optimal Taiwan Mechanism', 'Color', 'b');
hBoston = plot(ax, NaN, NaN, 'DisplayName', 'Boston Mechanism', 'Color', 'r');
hDeferred = plot(ax, NaN, NaN, 'DisplayName', 'Deferred Acceptance', 'Color', 'y');
hold(ax, 'off'); % Release the hold
% Create the legend using the dummy lines
lgd = legend([hOptimal, hBoston, hDeferred]);
lgd.Layout.Tile = 'south';
Please check the resulting figure below.
Hope this helps in resolving your query!

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Graphics 的更多信息

产品


版本

R2022a

Community Treasure Hunt

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

Start Hunting!

Translated by