Changing the marker shape or aspect ratio in a legend

Consider the following example code, and the plot legend it creates:
% Example data
means = [10 40 50 60; ...3 groups, each with 4 conditions (measures)
20 50 60 70; ...
30 60 80 90];
SEMs = [1 4 8 6; ...
2 5 9 12; ...
3 6 10 13];
nGroups = size(means, 1);
nConditionsPerGroup = size(means, 2);
figure('Position', [71 433 560 420])
b = bar(means, 'grouped');
hold on
clear x
% Get the x coordinate of the bars
for i = 1:nConditionsPerGroup
x(i,:) = b(i).XEndPoints;
b(i).BarWidth = 1;
end
% Plot the errorbars
errorbar(x',means,SEMs,'k','linestyle','none');
hold off
set(gca, 'XTickLabel', {'Low' 'Middle' 'High'}, 'FontSize', 12);
xlabel('Socio-economic status', 'FontSize', 18)
[leg,att] = legend('A', 'B', 'C', 'D', 'Orientation','horizontal', 'FontSize', 15);
title(leg,'Measures')
leg.Title.Visible = 'off';
box off
ax = gca;
ax.YGrid = 'on';
I'd like to change the aspect ratio of the legend markers to make them square instead of rectangular. Alternatively, to change their shape altogether and make them e.g. round.
However, I found no property inside the legend handle to manipulate aspect ratio or shape of the markers, only their size (`MarkerSize`). Changing the overall size (width/height) of the legend leaves aspect ratio unchanged.
Thanks for any help!

 Réponse acceptée

DGM
DGM le 20 Juin 2023
Modifié(e) : DGM le 20 Juin 2023
Here's one way. You might also want to adjust the text object positions as well.
% Example data
means = [10 40 50 60; ...3 groups, each with 4 conditions (measures)
20 50 60 70; ...
30 60 80 90];
SEMs = [1 4 8 6; ...
2 5 9 12; ...
3 6 10 13];
nGroups = size(means, 1);
nConditionsPerGroup = size(means, 2);
%figure('Position', [71 433 560 420])
b = bar(means, 'grouped');
hold on
clear x
% Get the x coordinate of the bars
for i = 1:nConditionsPerGroup
x(i,:) = b(i).XEndPoints;
b(i).BarWidth = 1;
end
% Plot the errorbars
errorbar(x',means,SEMs,'k','linestyle','none');
hold off
set(gca, 'XTickLabel', {'Low' 'Middle' 'High'}, 'FontSize', 12);
xlabel('Socio-economic status', 'FontSize', 18)
[leg,att] = legend('A', 'B', 'C', 'D', 'Orientation','horizontal', 'FontSize', 15);
title(leg,'Measures')
leg.Title.Visible = 'off';
box off
ax = gca;
ax.YGrid = 'on';
% adjust each patch object in the legend
% patch vertex data is normalized WRT the legend box
textoffset = att(1).Position(1) - att(5).Children.Vertices(3,1);
leg.Units = 'pixels';
lp = leg.Position;
for k = 1:4
V = att(k+4).Children.Vertices;
xcent = mean(V(2:3,1))*lp(3);
halfw = diff(V(1:2,2))/2*lp(4);
V(:,1) = (xcent + halfw*[-1 -1 1 1 -1].')/lp(3);
att(k+4).Children.Vertices = V;
att(k).Position(1) = V(3,1) + textoffset;
end
Since the objects are just patches, I don't see why you couldn't make them into any polygonal shape you want.
Alternatively, you can also do other workarounds using dummy objects:

3 commentaires

z8080
z8080 le 21 Juin 2023
Modifié(e) : z8080 le 21 Juin 2023
thank you! would making markers round be possible too, given that circles are not polygons?
As far as anyone will be able to tell, an appropriate polygon might as well be a circle.
% Example data
means = [10 40 50 60; ...3 groups, each with 4 conditions (measures)
20 50 60 70; ...
30 60 80 90];
SEMs = [1 4 8 6; ...
2 5 9 12; ...
3 6 10 13];
nGroups = size(means, 1);
nConditionsPerGroup = size(means, 2);
%figure('Position', [71 433 560 420])
b = bar(means, 'grouped');
hold on
clear x
% Get the x coordinate of the bars
for i = 1:nConditionsPerGroup
x(i,:) = b(i).XEndPoints;
b(i).BarWidth = 1;
end
% Plot the errorbars
errorbar(x',means,SEMs,'k','linestyle','none');
hold off
set(gca, 'XTickLabel', {'Low' 'Middle' 'High'}, 'FontSize', 12);
xlabel('Socio-economic status', 'FontSize', 18)
[leg,att] = legend('A', 'B', 'C', 'D', 'Orientation','horizontal', 'FontSize', 15);
title(leg,'Measures')
leg.Title.Visible = 'off';
box off
ax = gca;
ax.YGrid = 'on';
% adjust each patch object in the legend
% patch vertex data is normalized WRT the legend box
nsides = 100; % pick any regular polygon
theta = (0:360/nsides:360) + 360/nsides/2;
textoffset = att(1).Position(1) - att(5).Children.Vertices(3,1);
leg.Units = 'pixels';
lp = leg.Position;
for k = 1:4
% replace patch object with a regular polygon
V = att(k+4).Children.Vertices;
patchcent = [mean(V(2:3,1)) mean(V(1:2,2))].*lp(3:4);
radius = diff(V(1:2,2))/2*lp(4);
V = patchcent + radius*[cosd(theta.') sind(theta.')];
V = V./lp(3:4);
att(k+4).Children.Vertices = V;
att(k+4).Children.Faces = 1:numel(theta);
% move text label
att(k).Position(1) = V(3,1) + textoffset;
end
beautiful work!!

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Data Distribution Plots dans Centre d'aide et File Exchange

Produits

Version

R2023a

Tags

Question posée :

le 20 Juin 2023

Commenté :

le 22 Juin 2023

Community Treasure Hunt

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

Start Hunting!

Translated by