Quantcast
Viewing all articles
Browse latest Browse all 219

Plot legend title

This blog post was supposed to be a piece of cake: The problem description was that we wish to display a text title next to the legend box in plot axes. Sounds simple enough. After all, in HG1 (R2014a and earlier), a legend was a simple wrapper around a standard Matlab axes. Therefore, we can simply access the legend axes’s title handle, and modify its properties. This works very well in HG1:

hold all; 
hLine1 = plot(1:5); 
hLine2 = plot(2:6); 
hLegend = legend([hLine1,hLine2], 'Location','NorthWest');
hTitle = get(hLegend,'title');
set(hTitle, 'String','Plot types:', 'VerticalAlignment','middle', 'FontSize',8);

Image may be NSFW.
Clik here to view.
Matlab HG1 legend with title

Matlab HG1 legend with title

HG2

How hard then could a corresponding solution be in HG2 (R2014b+), right?

Well, it turns out that hard enough (at least for me)…

In this blog I’ve presented ~300 posts so far that discuss solutions to problems. Readers of this blog always hear the success stories, and might mistakenly think that every problem has a similarly simple solution that can be hacked away in a few lines of nifty code.

Well, the truth must be told that for each investigation that yields such a success story, there is at least one other investigation in which I failed to find a solution, no matter how hard I tried or countless hours spent digging (this is not to say that the success stories are easy – distilling a solution to a few lines of code often takes hours of research). In any case, maybe some of these problems for which I have not found a solution do have one that I have simply not discovered, and maybe they don’t – in most likelihood I will never know.

This is yet another example of such a spectacular failure on my part. Try as I may in HG2, I could find no internal handle anywhere to the legend’s axes or title handle. As far as I could tell, HG2′s legend is an standalone object of class matlab.graphics.illustration.Legend that derives from exactly the same superclasses as axes:

>> sort(superclasses('matlab.graphics.axis.Axes'))
ans = 
    'JavaVisible'
    'dynamicprops'
    'handle'
    'matlab.graphics.Graphics'
    'matlab.graphics.GraphicsDisplay'
    'matlab.graphics.internal.GraphicsJavaVisible'
    'matlab.mixin.CustomDisplay'
    'matlab.mixin.Heterogeneous'
    'matlab.mixin.SetGet'
>> sort(superclasses('matlab.graphics.illustration.Legend'))
ans = 
    'JavaVisible'
    'dynamicprops'
    'handle'
    'matlab.graphics.Graphics'
    'matlab.graphics.GraphicsDisplay'
    'matlab.graphics.internal.GraphicsJavaVisible'
    'matlab.mixin.CustomDisplay'
    'matlab.mixin.Heterogeneous'
    'matlab.mixin.SetGet'

This make sense, since they share many properties/features. But it also means that legends are apparently not axes but rather unrelated siblings. As such, if MathWorks chose to remove the Title property from the legend object, we will never find it.

So what can we do in HG2?

Well, we can always resort to the poor-man’s solution of an optical illusion: displaying a an invisible axes object having the same Position as the legend box, with an axes title. We attach property listeners on the legend’s Units, Position and Visible properties, linking them to the corresponding axes properties, so that the title will change if and when the legend’s properties change (for example, by dragging the legend to a different location, or by resizing the figure). We also add an event listener to destroy the axes (and its title) when the legend is destroyed:

% Create the legend
hLegend = legend(...);  % as before
 
% Create an invisible axes at the same position as the legend
hLegendAxes = axes('Parent',hLegend.Parent, 'Units',hLegend.Units, 'Position',hLegend.Position, ...
                   'XTick',[] ,'YTick',[], 'Color','none', 'YColor','none', 'XColor','none', 'HandleVisibility','off', 'HitTest','off');
 
% Add the axes title (will appear directly above the legend box)
hTitle = title(hLegendAxes, 'Plot types:', 'FontWeight','normal', 'FontSize',8);  % Default is bold-11, which is too large
 
% Link between some property values of the legend and the new axes
hLinks = linkprop([hLegend,hLegendAxes], {'Units', 'Position', 'Visible'});
% persist hLinks, otherwise they will stop working when they go out of scope
setappdata(hLegendAxes, 'listeners', hLinks);
 
% Add destruction event listener (no need to persist here - this is done by addlistener)
addlistener(hLegend, 'ObjectBeingDestroyed', @(h,e)delete(hLegendAxes));

Image may be NSFW.
Clik here to view.
Matlab HG2 legend with title

Matlab HG2 legend with title

Yes, this is indeed a bit of an unfortunate regression from HG1, but I currently see no other way to solve this. We can’t win ‘em all… If you know a better solution, I’m all ears. Please shoot me an email, or leave a comment below.

Update: As suggested below by Martin, here is a more elegant solution, which attaches a text object as a direct child of the legend’s hidden property DecorationContainer (we cannot add it as a child of the legend since this is prevented and results in an error):

hLegend = legend(...);
hlt = text(...
    'Parent', hLegend.DecorationContainer, ...
    'String', 'Title', ...
    'HorizontalAlignment', 'center', ...
    'VerticalAlignment', 'bottom', ...
    'Position', [0.5, 1.05, 0], ...
    'Units', 'normalized');

The title appears to stay attached to the legend and the Parent property of the text object even reports the legend object as its parent:

hLegend.Location = 'southwest';  % Test the title's attachment
hlt.Parent % Returns hLegend

- thanks Martin!

Happy Passover/Easter everybody!

 
Related posts:
  1. Transparent legend Matlab chart legends are opaque be default but can be made semi- or fully transparent. ...
  2. Multi-column (grid) legend This article explains how to use undocumented axes listeners for implementing multi-column plot legends...
  3. Bar plot customizations Matlab bar charts can be customized in various nifty ways. ...
  4. Plot LimInclude properties The plot objects' XLimInclude, YLimInclude, ZLimInclude, ALimInclude and CLimInclude properties are an important feature, that has both functional and performance implications....
 

Viewing all articles
Browse latest Browse all 219

Trending Articles