How do I get a "tabular" legend?
36 views (last 30 days)
Show older comments
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?
0 Comments
Accepted Answer
Kelly Kearney
on 10 May 2017
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 Comments
Kelly Kearney
on 10 May 2017
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');
More Answers (2)
Shane L
on 23 Mar 2018
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.
0 Comments
Steven Lord
on 23 Mar 2018
% 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.
0 Comments
See Also
Categories
Find more on Axis Labels in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!