How do I get a "tabular" legend?

37 次查看(过去 30 天)
In MatlabR2015b, I am plotting a 2D scatter plot of "Performance" that is a function of two independent variables "Active agent" & "Temp". I have 3 Active Agents and 4 Temps. In scatter plot, I am using a 12 colors, one for each (ActiveAgent,Temp) pair. I want to customize legend so that it appears in a tabular form like (C1 would be like marker 'o' in its respective colors)
Temp1 Temp2 Temp3 Temp4
Agent1 C1 C2 C3 C4
Agent2 C5 C6 C7 C8
Agent3 C9 C10 C11 C12
How can I do this?

采纳的回答

Kelly Kearney
Kelly Kearney 2017-5-10
You can hack your way to a solution with my legendflex function. It's designed to make gridded-style legends like this, though unfortunately doesn't include the row/column label function yet (I'll keep that in mind for an enhancement, though... shouldn't be too hard to add).
Scatter only creates a single object to label, so to get individually-colored marker for a legend, you can create some invisible line objects:
% Data
nrow = 3;
ncol = 4;
ngrp = nrow*ncol;
x = rand(100,1);
y = rand(100,1);
group = ceil(rand(100,1)*ngrp);
datalabel = strtrim(cellstr(num2str((1:ngrp)', 'C%d')));
rowlabel = strtrim(cellstr(num2str((1:nrow)', 'Agent%d')));
collabel = strtrim(cellstr(num2str((1:ncol)', 'Temp%d')));
% Plot
scatter(x,y,[],group);
cmap = parula(ngrp);
colormap(cmap);
set(gca, 'clim', [0 ngrp] + 0.5, 'ylim', [-0.5 1.5]);
hln = line(nan(2,ngrp), nan(2, ngrp), 'marker', 'o', 'linestyle', 'none');
set(hln, {'color'}, num2cell(cmap,2));
% A regular legend to show the hidden-marker idea
hplain = legend(hln(:), datalabel(:));
export_fig('leggrid1', '-png');
delete(hplain);
There are two ways I can think of to get the grid layout. One is to add extra no-marker objects for both the row and column labels. The second is to add extra markers just for the row labels, and create multiple legends with legendflex's title property for the column labels. The latter centers the column titles over the label and object together, which I prefer, but it means you have to keep the box off (which may or may not work for your data):
% Option 1: add extra objects for row/column labels
hr = line(nan(2,nrow), nan(2,nrow), 'linestyle', 'none');
hc = line(nan(2,ncol+1), nan(2,ncol+1), 'linestyle', 'none');
allobj = [hc'; [hr reshape(hln,nrow,ncol)]];
alllbl = ['-' collabel'; [rowlabel reshape(datalabel,nrow,ncol)]];
hleg1 = legendflex(allobj(:), alllbl(:), 'nrow', nrow+1, 'xscale', 0.5);
% Option 2, multiple legends with titles
allobj = [hr reshape(hln,nrow,ncol)];
alllbl = [rowlabel reshape(datalabel,nrow,ncol)];
ttl = ['-' collabel'];
for ii = (ncol+1):-1:1
if ii == (ncol+1)
hleg2(ii) = legendflex(allobj(:,end), alllbl(:,end), 'ref', gca, ...
'anchor', {'se','se'}, 'buffer', [-10 10], 'xscale', 0.5, ...
'box', 'off', 'title', collabel{end});
else
hleg2(ii) = legendflex(allobj(:,ii), alllbl(:,ii), 'ref', hleg2(ii+1), ...
'anchor', {'sw','se'}, 'buffer', [0 0], 'xscale', 0.5, ...
'box', 'off', 'title', ttl{ii});
end
end
  3 个评论
Kelly Kearney
Kelly Kearney 2017-5-10
That makes things a little more complicated with legendflex, since it can't handle completely blank labels (hence the little dash I added to the corner). For just straight symbols, I would probably forgo a legend altogether and just manually build a legend-like axis:
% Data
nrow = 3;
ncol = 4;
ngrp = nrow*ncol;
x = rand(100,1);
y = rand(100,1);
group = ceil(rand(100,1)*ngrp);
datalabel = strtrim(cellstr(num2str((1:ngrp)', 'C%d')));
rowlabel = strtrim(cellstr(num2str((1:nrow)', 'Agent%d')));
collabel = strtrim(cellstr(num2str((1:ncol)', 'Temp%d')));
% Plot
scatter(x,y,[],group);
cmap = parula(ngrp);
colormap(cmap);
set(gca, 'clim', [0 ngrp] + 0.5, 'ylim', [-0.5 1.5]);
% "Legend"
[ypt, xpt] = ndgrid(1:nrow, 1:ncol);
pos = get(gca, 'position');
sz = [0.4 0.2];
legax = axes('position', [pos(1)+pos(3)-sz(1) pos(2)+pos(4)-sz(2) sz], ...
'xlim', [-1 ncol+1], 'ylim', [-1 nrow+1], 'ydir', 'reverse', ...
'xtick', [], 'ytick', [], 'box', 'on');
hold on;
scatter(xpt(:), ypt(:), [], 1:ngrp);
text(1:ncol, zeros(1,ncol), collabel, 'horiz', 'center');
text(ones(1,nrow)*0.5, 1:nrow, rowlabel, 'horiz', 'right');
820408
820408 2017-5-11
Thank you. This is what I was looking for.

请先登录,再进行评论。

更多回答(2 个)

Shane L
Shane L 2018-3-23
If you are looking for a code that is built to create a "tabular" legend, my GridLegend function on the File Exchange will create a "legend" (actually a legend-like axis) with row and column labels. My GridLegend function is not as versatile as Kelly's legendflex function, but it will give you a "tabular" legend with no additional work on the user's end.

Steven Lord
Steven Lord 2018-3-23
In release R2018a, you can now control how many columns your legend has.
% Generate data and set up the axes
x = linspace(0, 2*pi, 500);
axis([0 2*pi -8 8]);
hold on
% Plot 8 sine curves, naming each n*sin(n*x) for legend purposes
for n = 1:8
plot(x, n.*sin(n*x), 'DisplayName', sprintf('%d*sin(%d*x)', n, n));
end
% Turn on the legend
L = legend('show');
% Make it 2-by-4 instead of 8-by-1
L.NumColumns = 4;
This isn't exactly what the original poster asked for, but it's close.

类别

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

标签

Community Treasure Hunt

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

Start Hunting!

Translated by