In one of my projects, I had to build a GUI in which users could interactively add and remove plot lines from an axes. The problem was that the legend needed to be kept in constant sync with the currently-displayed plot lines. This can of course be done programmatically, but a much simpler solution was to use legend’s semi-documented ‘-DynamicLegend’ feature. Here’s a simple example:
x=0:.01:10; plot(x, sin(x), 'DisplayName','sin'); legend('-DynamicLegend'); hold all; % add new plot lines on top of previous ones plot(x, cos(x), 'DisplayName','cos');
We can see how the dynamic legend automatically keeps in sync with its associated axes contents when plot lines are added/removed, even down to the zoom-box lines… The legend automatically uses the plot lines ‘DisplayName’ property where available, or a standard ‘line#’ nametag where not available:

Dynamic legend
DynamicLegend works by attaching a listener to the axes child addition/deletion callback (actually, it works on the scribe object, which is a large topic for several future posts). It is sometimes necessary to selectively disable the dynamic behavior. For example, in my GUI I needed to plot several event lines which looked alike, and so I only wanted the first line to be added to the legend. To temporarily disable the DynamicLegend listener, do the following:
% Try to disable this axes's legend plot-addition listener legendAxListener = []; try legendListeners = get(gca,'ScribeLegendListeners'); legendAxListener = legendListeners.childadded; set(legendAxListener,'Enable','off'); catch % never mind... end % Update the axes - the legend will not be updated ... % Re-enable the dynamic legend listener set(legendAxListener,'Enable','on');
Unfortunately, this otherwise-useful DynamicLegend feature throws errors when zooming-in on bar or stairs graphs. This can be replicated by:
figure; bar(magic(4)); %or: stairs(magic(3),magic(3)); legend('-DynamicLegend'); zoom on; % Now zoom-in using the mouse to get the errors on the Command Window
The fix: modify %MATLABROOT%\toolbox\matlab\scribe\@scribe\@legend\init.m line #528 as follows:
%old: str = [str(1:insertindex-1);{newstr};str(insertindex:length(str))]; %new: if size(str,2)>size(str,1) str=[str(1:insertindex-1),{newstr},str(insertindex:length(str))]; else str=[str(1:insertindex-1);{newstr};str(insertindex:length(str))]; end
The origin of the bug is that bar and stairs generate hggroup plot-children, which saves the legend strings column-wise rather than the expected row-wise. My fix solves this, but I do not presume this solves all possible problems in all scenarios (please report if you find anything else).
The DynamicLegend feature is semi-documented. This means that the feature is explained in a comment within the function (which can be seen via the edit(‘legend’) command), that is nonetheless not part of the official help or doc sections. It is an unsupported feature originally intended only for internal Matlab use (which of course doesn’t mean we can’t use it). This feature has existed many releases back (Matlab 7.1 for sure, perhaps earlier), so while it may be discontinued in some future Matlab release, it did have a very long life span… The down side is that it is not supported: I reported the bar/stairs issue back in mid-2007 and so far this has not been addressed (perhaps it will never be). Even my reported workaround in January this year went unanswered (no hard feelings…).
DynamicLegend is a good example of a useful semi-documented feature. Some other examples, which I may cover in future posts, include text(…,’sc’), drawnow(‘discard’), several options in pan and datacursormode etc. etc.
There are also entire semi-documented functions: many of the uitools (e.g., uitree, uiundo), as well as hgfeval and others.
Have you discovered any useful semi-documented feature or function? If so, then please share your finding in the comments section below.