Adding legend for subplot when none of the subplots include all legend entries

155 ビュー (過去 30 日間)
Catriona
Catriona 2020 年 9 月 29 日
コメント済み: LIU 2022 年 3 月 21 日
Hi folks, I am trying to create a subplot where the points are coloured by year, and the years have the same colour in each subplot. Through careful control of the colours I have been able to achieve this, but I only want one legend for the figure, and none of the subplots contain all the years. I cannot figure out (excuse the pun!) how to create just one legend that has all the years (2011-2016). I can easily position one legend at the bottom of the subplot, that's not the problem. Here is the code to make the figure with individual legends (which I don't want in the end) to show you what I mean, along with the code. Thank you!
st_colours=[0, 0.4470, 0.7410;0.8500, 0.3250, 0.0980; 0.9290, 0.6940, 0.1250; 0.4940, 0.1840, 0.5560; 0.4660, 0.6740, 0.1880; 0.3010, 0.7450, 0.9330; 0.6350, 0.0780, 0.1840];
figure15 = figure();
for m=1:12
subplot(4,3,m)
if m==1 || m==2 || m==3 || m==4 || m==5 || m==6 || m==8 || m==11 || m==12 %Month
for r=1:5 %The row this time
sc(m,r)=scatter(QQG_Amm3M_T_split(m).months.NOAA_ONI(r),QQG_Amm3M_T_split(m).months.mean_Tmelt(r),25,'filled');hold on;
end
end
if m==7 || m==9 || m==10
for r=1:4 %The row this time
sc(m,r)=scatter(QQG_Amm3M_T_split(m).months.NOAA_ONI(r),QQG_Amm3M_T_split(m).months.mean_Tmelt(r),25,'filled');hold on;
end
end
if m==11 || m==12
for r=1:5 %The row this time
sc(m,r).MarkerFaceColor=st_colours(r,:);
end
elseif m==1 || m==2 || m==3 || m==4 || m==5 || m==6 || m==8
for r=1:5 %The row this time
sc(m,r).MarkerFaceColor=st_colours(r+1,:);
end
else
for r=1:4 %The row this time
sc(m,r).MarkerFaceColor=st_colours(r+1,:);
end
end
legend(string(QQG_Amm3M_T_split(m).months.mean_Year));
title(Month_labels(m));
xlim([-2 2.5]);
ylim([0 1]);
end
  2 件のコメント
Adam Danz
Adam Danz 2020 年 9 月 29 日
You can simplify the if m==1 || m==2 || m==3 || m.... conditions by using ismember instead.
if ismember(m, [1,2,3, . . .])
Catriona
Catriona 2020 年 9 月 30 日
That's handy, thanks Adam!!

サインインしてコメントする。

採用された回答

Adam Danz
Adam Danz 2020 年 9 月 29 日
編集済み: Adam Danz 2020 年 9 月 29 日
All you need are the handles to each object you want to include in the legend and the handles can come from different subplots within the same figure. But the legend is a child of only one subplot and can be repositioned relative to that subplot.
% DEMO
figure()
colors = [winter(3);summer(3);autumn(3);copper(3)];
subPlotNames = 'ABCD';
h = gobjects(3,4);
for i = 1:4
ax = subplot(1,5,i);
h(:,i) = plot([0,1],[.66;.5;.33].*[1,1],'LineWidth',4);
text([.1,.1,.1],[.66;.5;.33],{'1' '2' '3'},'VerticalAlignment', 'Bottom')
set(h(:,i), {'DisplayName'}, compose('%s %d',subPlotNames(i),1:3)')
title(subPlotNames(i))
end
set(h(:), {'Color'}, mat2cell(colors,ones(12,1),3))
lg = legend(h(:));
lg.Position(1:2) = [.8 .3];
This method also works with TiledLayout but requries r2020b for the last line which repositions the legend.
Another method I've used a lot is to use the DisplayName property of line objects to assign the legend string to all line objects within a figure even if the legend string & line line properties associations are redundant (e.g. more than 1 orange marker named "2012"). Then use legendUnq() from the file exchange to eliminate the objects with redundant legend strings. After applying DisplayName, you just need to call this after assigning all objects to the plot,
legend(legendUnq())
  3 件のコメント
Catriona
Catriona 2020 年 9 月 30 日
編集済み: Catriona 2020 年 9 月 30 日
Just to say that after a bit of tweaking I was able to use Adam's idea to get one legend with all the entries I needed. The key is to set the display property for every object you create (in my case this was for every month and row of data). Then from the matrix of object properties, I could choose those I wanted in my legend. In my case it was important to set the display year correctly as the sequence of years differed by month, but I understand a lot more about using handles now! Thanks to everyone for all their ideas, I really wasn't sure if this was solveable!!
Here's the code and graph in the end:
%Subplots
st_colours=[0, 0.4470, 0.7410;0.8500, 0.3250, 0.0980; 0.9290, 0.6940, 0.1250; 0.4940, 0.1840, 0.5560; 0.4660, 0.6740, 0.1880; 0.3010, 0.7450, 0.9330; 0.6350, 0.0780, 0.1840];
QQG_years={'2011','2012','2013','2014','2015','2016'};
figure15 = figure();
sc=gobjects(12,6);
for m=1:12
subplot(4,3,m)
if m==1 || m==2 || m==3 || m==4 || m==5 || m==6 || m==8 || m==11 || m==12 %Month
for r=1:5 %The row this time
sc(m,r)=scatter(QQG_Amm3M_T_split(m).months.NOAA_ONI(r),QQG_Amm3M_T_split(m).months.mean_Tmelt(r),25,'filled');hold on;
end
end
if m==7 || m==9 || m==10
for r=1:4 %The row this time
sc(m,r)=scatter(QQG_Amm3M_T_split(m).months.NOAA_ONI(r),QQG_Amm3M_T_split(m).months.mean_Tmelt(r),25,'filled');hold on;
end
end
if m==11 || m==12
for r=1:5 %The row this time
sc(m,r).MarkerFaceColor=st_colours(r,:);
sc(m,r).DisplayName=QQG_years{r};
end
elseif m==1 || m==2 || m==3 || m==4 || m==5 || m==6 || m==8
for r=1:5 %The row this time
sc(m,r).MarkerFaceColor=st_colours(r+1,:);
sc(m,r).DisplayName=QQG_years{r+1};
end
else %m==7 or 9 or 10
for r=1:4 %The row this time
sc(m,r).MarkerFaceColor=st_colours(r+1,:);
sc(m,r).DisplayName=QQG_years{r+1};
end
end
title(Month_labels(m));
xlim([-2 2.5]);
ylim([0 1]);
end
f1L=legend(sc([11 23 35 47 59 50]),'Location','SouthOutside','Orientation','Horizontal');
f1P = [0.5 0.02 0.03 0.03];
set(f1L,'Position', f1P,'Units', 'normalized');
%Oh look you can add a subplot title
sgtitle('Quisoquipina Glacier');
LIU
LIU 2022 年 3 月 21 日
Thank you very much, this helps me a lot.

サインインしてコメントする。

その他の回答 (1 件)

Mario Malic
Mario Malic 2020 年 9 月 29 日
Legend command is in the loop, therefore it is generated for each subplot. If you want to have it on particular month, you can put this within condition
if m == 1 % Jan
legend(string(QQG_Amm3M_T_split(m).months.mean_Year));
end
Or you can put it just outside of loop, and legend will be on December.
  5 件のコメント
Mario Malic
Mario Malic 2020 年 9 月 29 日
Having an additional scatter command for the January, you can have enough entries in the legend, and for it make the legend, but it's not a proper solution.
scatter(nan, nan);
Or maybe you could add an entry to your structure (nan, nan) to December and adjust the code, as it's easier to append the last value rather than the first.
Catriona
Catriona 2020 年 9 月 29 日
Thanks Mario, that's a nice idea, that might be quite simple to implement.

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeLegend についてさらに検索

Community Treasure Hunt

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

Start Hunting!

Translated by