Archive for the ‘Low risk of breaking in future versions’ Category

uitree

Wednesday, August 11th, 2010

Can you guess which built-in Matlab function is the top search-term on UndocumentedMatlab.com and yet one of the least discussed topic on the CSSM forum?

The answer is uitree – Matlab’s built-in function for displaying data in a hierarchical (tree) GUI component. uitree has been included in all Matlab 7 releases, but has never been officially supported. Like most other uitools in the %matlabroot%/toolbox/matlab/uitools/ folder, uitree and its companion uitreenode are semi-documented, meaning that they have no support or doc-page, but do have readable help sections within their m-files. In our case, edit the uitree.m and uitreenode.m files to see their help section.

Note the following comment within %matlabroot%/toolbox/local/hgrc.m, which implies that uitree may soon become fully supported, although its interface might change somewhat (as was the case when uitable became supported in R2008a):
Temporarily turn off old uitree and uitreenode deprecated function warning… When we introduce the new documented uitree to replace the old undocumented uitree …

Like most other uitools (e.g. uitable and uitab), uitree is based on an underlying Java component, which ultimately extends Swing’s standard JTree. uitree sets up a scrollable JTree on-screen without the hassle of setting up a scrollable viewport and other similar nuts and bolts. In fact, you don’t need to know any Java to use uitree (although knowing JTree can greatly help you customize it) – uitrees can be manipulated using pure Matlab code, as shall be seen below.

uitree accepts an optional figure handle followed by P-V (property-value) pairs. Settable properties are Root, ExpandFcn, SelectionChangeFcn, Position (also Parent, but read on). As in uitab, a ‘v0′ input argument may be necessary to suppress a warning message. Note that uitrees are always created as a direct child of the containing figure, ignoring creation-time Parent values. However, the Parent property can be modified following the tree’s creation:

[mtree, container] = uitree('v0', 'Root','C:\', 'Parent',hPanel); % Parent is ignored
set(container, 'Parent', hPanel);  % fix the uitree Parent

A simple uitree

A simple uitree

uitree returns two arguments: a handle to the created tree (a Java object wrapped within a Matlab handle) and an entirely-undocumented second optional argument holding a handle to the Matlab GUI container of the created tree. These two arguments are exactly the two arguments returned from the javacomponent function that I described last week.

uitreenode

uitree automatically understands Root objects of type Handle Graphics, Simulink model or char string (interpreted as a file-system folder name). Other Root types require setting dedicated ExpandFcn, SelectionChangeFcn Matlab callbacks (see uitree’s help section or below for examples).

If we need to create a custom tree hierarchy (i.e., our root node is not an HG object, Simulink model or folder name), then we need to use the semi-documented uitreenode function as follows:

node = uitreenode('v0',handle(mtree),'my root','c:\root.gif',false);
mtree.setRoot(node);
set(mtree,'Root',node);  % alternative to mtree.setRoot()

uitreenode accepts 4 arguments: a string or handle value (the node’s “internal” value), a string description (shown next to the node’s icon), an icon filename ([] will result in an icon assigned based on the node value), and a flag indicating whether the node is a leaf (no children) or not.

uitreenode returns a node object, which is little more than a Matlab handle wrapper for a Java Swing DefaultMutableTreeNode.

Node manipulation

Nodes can be added, moved or removed by node methods: node.add(anotherNode) adds anotherNode to the end of this node’s children list (possibly detaching it from its previous parent); node.insert(anotherNode,index) does the same but inserts anotherNode at a specific child index, rather than at the end; node.clone() makes a duplicate of this node that can then be added to another node; node.remove(index) and node.remove(node) remove a specific node whereas node.removeFromParent() removes this node; node.removeAllChildren() removes all children, if any, of this node.

Nodes can also be added and removed at the tree level: mtree.add(parent,nodes) allows adding a list of nodes to a parent node and mtree.remove(nodes) removes the specified nodes.

In order to programmatically collapse and expand nodes, use mtree.collapse(node) and mtree.expand(node).

Nodes can be programmatically selected using mtree.setSelectedNode(node). Multiple nodes may be selected using mtree.setSelectedNodes, if an earlier call to mtree.setMultipleSelectionEnabled(true) was made (default is multiple-selection disabled):

mtree.setSelectedNode(root);  % root is a node
mtree.setSelectedNodes([root,node1,node2]);  % select 3 nodes

programmatically selecting multiple tree nodes

programmatically selecting multiple tree nodes

The currently-selected node(s) can be accessed using mtree.getSelectedNodes. Node selection callbacks often require knowledge of the currently selected rows:

% Tree set up
mtree = uitree(..., 'SelectionChangeFcn',@mySelectFcn);
set(mtree, 'SelectionChangeFcn',@mySelectFcn); % an alternative
 
% The tree-node selection callback
function nodes = mySelectFcn(tree, value)
    selectedNodes = tree.getSelectedNodes;
    if ~isempty(selectedNodes)
        % ...
    end
end  % mySelectFcn

Interested readers might also benefit from looking at the tree manipulations that I have programmed in my FindJObj utility.

Next week’s article will show how uitrees can be customized. There are numerous possible customizations, including icons, labels, appearance, and behavior. So if you have any special request, please post a comment below.

COM/ActiveX tips & tricks

Wednesday, July 28th, 2010

Matlab’s COM/ActiveX interface has been supported and well-documented for many releases. However, there are still some aspects that are either not detailed, or that escape the casual documentation reader.

Accessing collection items

COM collections is a COM interface for sets of similar objects such as the worksheets in an Excel file or the images in a PowerPoint document. The items in a collection can be accessed using a numeric index (starting at 1) or the item’s string name.

The “normal” way to access collection items is using the Item() method that accepts a numeric index or the item’s name (a string).

Since collections are so common, Microsoft devised a short-cut of passing the parameter directly to the collection. For example, in our Excel VB code, instead of using Worksheets.Item(2) or Worksheets.Item(‘Sheet2′), we could write Worksheets(2) or Worksheets(‘Sheet2′). This shortcut is so common that the “normal” way of using Item() is rarely seen.

Unfortunately, Matlab’s implementation of the COM interface does not recognize this shortcut. Instead, we must use the more verbose way of using the Item():

% Invalid - shortcut is not recognized by Matlab
>> hSheet = hWorkbook.Worksheets(2);
??? Index exceeds matrix dimensions
 
% Valid
>> hSheet = hWorkbook.Worksheets.Item(2);
>> hSheet = hWorkbook.Worksheets.Item('Sheet2')
hSheet =
	Interface.Interface.Microsoft_Excel_11.0_Object_Library._Worksheet

Note that the dot-notation used above only works on recent Matlab 7 releases. Earlier releases (for example, Matlab 6.0 R12) have bugs that prevent it from functioning properly. The workaround is to use the following even-more-verbose way, which work on all Matlab releases:

hSheet = invoke(get(hWorkbook,'Worksheets'),'Item',2);

Matlab’s documentation actually has a short section describing the valid way to access COM collection. IMHO, a special warning about the invalid but widely-used short-cut would have been useful. In any case, the issue of accessing collection items has often appeared on CSSM (for example, here and here), so I guess many programmers have overlooked this.

Using enumerated values

When setting COM property values, Matlab supports some enumerated (constant) values but not all (read here). In practice, this can be very frustrating since the VB code and documentation almost always refers to the enumerated values only. Without the ability to set enumeration values, some properties become unusable in Matlab.

Well, not really. There’s a workaround: Since every enumerated COM value hides a numeric value, we can pass the numeric values rather than the enumerated (string) value when setting such properties. The numeric values are seldom documented, but can often be easily found online (use Google!). Quite often, they appear in C header-files that #define the enumerated values as pre-processor items with the required numeric value. For example, the numeric value for xlXYScatterLines is easily found to be 74.

Some of the enumerated constants are harder to find in this manner. You can use one of the following resources to search for your requested constant: Excel, PowerPoint (or here), OLE/Office (includes Word, Access and Internet Explorer), and an even larger list.

Again, old Matlab versions have problems understanding string enumerations, but the numeric values are always accepted and so are backward-compatible. If your application needs to support old Matlab versions, always use the numeric values (add a comment with the enumerated name, for maintainability).

Office 2010

Microsoft Office 2010 has apparently changed its COM interface, so accessing it from Matlab cannot easily be done. Luckily, Samuel Foucher has posted a workaround to this problem on CSSM yesterday. The trick is basically to have both an older Office and Office 2010 installed at the same time. As Samuel notes, “This is far from an optimal solution but it seems to work so far“.

Modifying Matlab’s Look-and-Feel

Wednesday, July 7th, 2010

A couple of days ago, a reader of this blog posted a comment, asking whether it is possible to change Matlab’s Desktop color scheme, and its general UI look. Instead of providing a short answer, I will use the opportunity to answer in a full article. So this is for you, Egon :-)

Matlab’s underlying Look-and-Feel

One of Matlab’s great advantages is cross-platform compatibility. Generally speaking, Matlab applications written on Windows will work as-is on Macintosh and Linux.

Java has similar cross-platform compatibilities, but enables much greater control over the look-and-feel (L&F or PLAF) of application GUI. In a nutshell, L&Fs affect the appearance and behavior of menus, controls, color schemes etc., using a properties plug-in architecture. Java programmers can choose to use either a platform-independent L&F (called the Metal L&F), or a platform-specific L&F. The benefit of using Metal is that the application looks essentially the same on all Java-supported platforms; the drawback is that they do not look like native applications on any platform…

Metal L&F   Motif L&F   Windows L&F

Metal, Motif & Windows L&F

Matlab, whose GUI is based on Java (not surprising to readers of this website), has chosen to use a platform-specific L&F on each of the platforms on which it is supported. So, Matlab on Windows looks like a native Windows application, whereas on Macs it looks similar to Mac apps (notwithstanding the well-known X11 migration issues). Of course, this means that Windows Matlab looks and behaves differently from Mac/Linux Matlabs. Note that the differences only affect the Desktop, tools/utilities (Editor etc.) and the general L&F – it does not affect the displayed plots. In practice, the differences are visible but easily understandable.

Changing the L&F

We can get the list of available L&Fs on our system as follows (below is the list on my Windows system):

>> lafs = javax.swing.UIManager.getInstalledLookAndFeels
lafs =
javax.swing.UIManager$LookAndFeelInfo[]:
    [javax.swing.UIManager$LookAndFeelInfo]
    [javax.swing.UIManager$LookAndFeelInfo]
    [javax.swing.UIManager$LookAndFeelInfo]
    [javax.swing.UIManager$LookAndFeelInfo]
    [javax.swing.UIManager$LookAndFeelInfo]
 
>> for lafIdx = 1:length(lafs),  disp(lafs(lafIdx));  end
javax.swing.UIManager$LookAndFeelInfo[Metal javax.swing.plaf.metal.MetalLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[Nimbus com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[CDE/Motif com.sun.java.swing.plaf.motif.MotifLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[Windows com.sun.java.swing.plaf.windows.WindowsLookAndFeel]
javax.swing.UIManager$LookAndFeelInfo[Windows Classic com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel]

We can change the L&F to any of the installed L&Fs, as follows:

javax.swing.UIManager.setLookAndFeel('javax.swing.plaf.metal.MetalLookAndFeel');

Although not listed in the installed L&Fs, Matlab also enables access to a 3rd-party L&F called Plastic3D by www.jgoodies.com. Plastic3D L&F generates slick stylish GUI:

javax.swing.UIManager.setLookAndFeel('com.jgoodies.looks.plastic.Plastic3DLookAndFeel')

Plastic3D L&F

Plastic3D L&F

The JIDE class library by www.jidesoft.com, which is bundled with Matlab, and specifically its jide-common.jar file, contains a separate set of 3rd-party L&Fs: Aqua, Eclipse (Metal & Windows variants), Office2003, VSNet (Metal & Windows variants) and Xerto. Unfortunately, in Matlab releases starting around 2009, JIDE stopped including full L&F classes in jide-common.jar, and started using L&F extensions using their com.jidesoft.plaf.LookAndFeelFactory class. I have not been able to use this class properly, but readers are welcome to try (please tell me if you succeed).

External L&Fs can also be downloaded and then used in Matlab. For example: Alloy, Synthetica and many others.

The current and standard L&Fs can be retrieved by using the respective static methods javax.swing.UIManager.getLookAndFeel() and getSystemLookAndFeelClassName().

Matlab also has a utility class com.mathworks.mwswing.plaf.PlafUtils that contains static methods that query the current L&F: isPlasticLookAndFeel(), isAquaLookAndFeel(), isMetalLookAndFeel(), isMotifLookAndFeel() and isWindowsLookAndFeel(). For some reason there is no method for the new (R2010a+) Nimbus L&F.

Nimbus L&F offers great potential for a cross-platform vectorized appearance, the ability to customize/skin pretty much every aspect of the visual appearance and component behavior, replacing Swing’s Synth L&F which was used for such customizations in earlier Matlab/Java releases. Nimbus is pre-installed as a non-default L&F in Matlab R2010a (7.10) onward, because it seems that most designers who target a single platform still prefer the native L&F.

Component-specific L&F

You can also modify the L&F of specific components, not just the entire Matlab. To do this, simply modify the L&F immediately before creating your GUI component, and restore the original L&F afterward (note how you can use either the L&F class name or its class reference):

% Update the current L&F
originalLnF = javax.swing.UIManager.getLookAndFeel;  %class
newLnF = 'javax.swing.plaf.metal.MetalLookAndFeel';  %string
javax.swing.UIManager.setLookAndFeel(newLnF);
 
% Create GUI using the modified L&F
hFig = figure(...);
hComponent = uicontrol(...);
jComponent = javacomponent(...);
 
% Restore the original L&F
javax.swing.UIManager.setLookAndFeel(originalLnF);

Components can update their L&F to the current L&F using their jComponent.updateUI() method. Components that are not specifically updated by invoking their updateUI() method will retain their existing (original) L&F – the L&F which was active when the components were created or last updated.

Fine-grained L&F property control

The default settings for the L&F can be retrieved using the static method javax.swing.UIManager.getDefaults(), which returns an enumeration of the thousand or so default settings:

>> defaults = javax.swing.UIManager.getDefaults;
>> propValues = defaults.elements; propKeys = defaults.keys;
>> while propKeys.hasMoreElements
     key = propKeys.nextElement;
     value = propValues.nextElement;
     disp([char(key) ' = ' evalc('disp(value)')]);
   end
 
com.sun.java.swing.plaf.windows.WindowsLabelUI = class com.sun.java.swing.plaf.windows.WindowsLabelUI
... (~1000 other property settings)
SplitPane.dividerSize =      5
DockableFrameTitlePane.stopAutohideIcon = javax.swing.ImageIcon@1f4e4c0
FormattedTextField.caretBlinkRate =    500
Table.gridColor = javax.swing.plaf.ColorUIResource[r=128,g=128,b=128]

Specific settings can be modified by using javax.swing.UIManager.put(key,newValue).

Have you found any useful L&F or property that you are using in your application? If so, please share them in the comments section below.

Tab panels – uitab and relatives

Wednesday, June 23rd, 2010

In the past year, readers of this blog have used its search box thousands of times. Can you guess what the top search terms are?

It turns out that 7 of the top 15 search terms relate to tables, trees and tab-panes.

These items are related in being standard GUI elements that unfortunately have very lacking support in Matlab. They all have corresponding functions in the %matlabroot%/toolbox/matlab/uitools folder, which was already introduced here as containing many unsupported GUI functions. Specifically, uitable for tables (this became supported in R2008a, but even the supported version has many important undocumented aspects); uitree and uitreenode for trees; and uitab and uitabgroup for tab-panes, which are today’s subject. Future articles will describe tables, trees and tab-panes in more detail.

uitab & uitabgroup

Like most other uitools, the uitab and uitabgroup functions are semi-documented, meaning that they have no support or doc-page, but do have readable help sections within their m-files. In our case, edit the uitab.m and uitabgroup.m files to see their help section.

Available since 2004 (R14 SP2, aka 7.0.4), Matlab’s uitabgroup uses the Matlab Java widget com.mathworks.hg.peer.UITabGroupPeer, which extends the standard javax.swing.JTabbedPane. Unlike uitable and uitree, which use actual Java objects to both store and present the data, uitabgroup only sets up the Java object to display the tabs, whereas the tab contents themselves are placed in entirely unrelated Matlab uicontainers. Matlab uses very clever double-booking to keep the Java and Matlab objects synchronized. The ability to “switch” tabs is actually a deception: in reality, a listener placed on the SelectedIndex property of the tab group causes the relevant Matlab container to display and all the rest to become hidden. Other listeners control containers’ position and size based on the tab group’s. Adding and removing tabs uses similar methods to add/remove empty tabs to the JTabbedPane. Read uitabgroup’s schema.m for details.

A drawback of this complex mechanism is the absence of a single customizable Java object. The benefit is that it allows us to place any Matlab content within the tabs, including plot axes which cannot be added to Java containers. Had uitabgroup been a Java container, we could not add axes plots or images to its tabs. In my humble opinion, Matlab’s tab implementation is an ingenious piece of engineering.

Here’s a simple tab-group adapted from uitabgroup’s help section:

hTabGroup = uitabgroup; drawnow;
tab1 = uitab(hTabGroup, 'title','Panel 1');
a = axes('parent', tab1); surf(peaks);
tab2 = uitab(hTabGroup, 'title','Panel 2');
uicontrol(tab2, 'String','Close', 'Callback','close(gcbf)');

(recent Matlab releases throw a warning when using this code: either add the ‘v0′ input arg to uitabgroup and uitab calls, or suppress the MATLAB:uitabgroup:MigratingFunction warning)

Here, the returned uitabgroup object hTabGroup is actually a Matlab container (deriving from uiflowcontainer) that always displays two elements: the Java tab-group, and the active Matlab uicontainer (the active tab’s contents). Understanding this, hTabGroup’s FlowDirection property becomes clear. However, it is better to use hTabGroup’s TabLocation property, which accepts ‘top’, ‘bottom’, ‘left’ and ‘right’:

TabLocation = 'top'

TabLocation = 'top'

TabLocation = 'left'

TabLocation = 'left'

Another hTabGroup property of interest is Margin, which sets the margin in pixels before each of the displayed elements – not just between them as might be expected: Increasing Margin (default=2 pixels) increases the gap between the tab group and the active tab’s contents, but also the gap between the tab group and figure edge:

TabLocation = 'bottom', Margin = 20   TabLocation = 'left', Margin = 20

Margin = 20

Tabs can be selected programmatically, by setting hTabGroup’s SelectedIndex property. Reading this property is useful when setting tab-selection callbacks using the SelectionChangeFcn property:

set(hTabGroup,'SelectionChangeFcn',@myCallbackFcn);
set(hTabGroup,'SelectedIndex',2);   % activate second tab

(R2010b pre-release documentation has some incorrect information about this, which I have reported. Unfortunately, I cannot disclose any additional details here since usage of the pre-release implies an NDA. When the official release is made, I will update this post accordingly).

Additional control over the tab group’s behavior can be achieved by customizing the underlying Java object. This object is not directly exposed by uitabgroup, but can be found using the FindJObj utility or via the hidden ApplicationData. Remember that Java objects use 0-based indexing so tab #1 is actually the second tab. Also remember that HTML is accepted just as in any other Swing-based label:

% Get the underlying Java reference using FindJObj
jTabGroup = findjobj('class','tabgroup');
 
% A direct alternative for getting jTabGroup
jTabGroup = getappdata(handle(hTabGroup),'JTabbedPane');
 
% Now use the Java reference to set the title, tooltip etc.
jTabGroup.setTitleAt(1,'Tab #2');
jTabGroup.setTitleAt(1,'<html><b><i><font size=+2>Tab #2');
jTabGroup.setToolTipTextAt(1,'Tab #2');
 
% Disabling tabs can only be done using the Java handle:
jTabGroup.setEnabledAt(1,0);  % disable only tab #1 (=2nd tab)
jTabGroup.setEnabled(false);  % disable all tabs

A future post will describe tab customization, including fonts, colors, icons and even addition of close buttons as in modern web browsers.

tabdlg

tabdlg is a related semi-documented and unsupported uitool that, like uitabgroup, creates a tabbed user interface. However, unlike uitabgroup, tabdlg uses plain-vanilla Matlab, without reliance on Java (well, actually all Matlab GUI controls ultimately rely on Java, but tabdlg does not use any Java beyond that). The end result looks less professional than uitabgroup, but it works even when Java does not.

tabdlg has an extensive help section, so it will not be detailed here. In brief, the input parameters specify the tab labels, dimensions, offsets, callbacks, font, default tab, sheet dimensions and parent figure. Here is a sample usage, taken from tabdlg’s help section. This code is executed whenever tabdlg is invoked without any input arguments:

tabdlg left tab

tabdlg left tab

tabdlg right tab

tabdlg right tab

File Exchange alternatives

There are many implementations of tab panels in the Matlab File Exchange. Matlab’s official Desktop Blog had an article about one specific example, which was that week’s Peek of the Week, and relied on adjacent buttons that are easy to implement, but in my personal opinion are a far cry from our expectations of a tab panel.

Better FEX utilities are: Multiple Tab GUI, Highlight Tab Objects easily, and best of all: uitabpanel or TabPanel Constructor.

Another very recent submission was this week’s POTW. This utility gives a professional (although somewhat non-standard) look, and is very easy to program – an excellent utility indeed.

All of the numerous tab-panel FEX utilities, as well as the fact that tab-panels are one of the most searched-for terms in this website, indicate the Matlab community’s desire to have supported native-looking tab-panel GUI in Matlab. Perhaps after 6 years it is time to bring uitab and uitabgroup into the light?

Plot performance

Wednesday, June 16th, 2010

I recently consulted to a client who wanted to display an interactive plot with numerous data points that kept updating in real-time. Matlab’s standard plotting functions simply could not keep up with the rate of data change. Today, I want to share a couple of very simple undocumented hacks that significantly improve plotting performance and fixed my problem.

I begin by stating the obvious: whenever possible, try to vectorize your code, preallocate the data and other performance-improving techniques suggested by Matlab. Unfortunately, sometimes (as in my specific case above) all these cannot help. Even in such cases, we can still find important performance tricks, such as these:

Performance hack #1: manual limits

Whenever Matlab updates plot data, it checks whether any modification needs to be done to any of its limits. This computation-intensive task is done for any limit that is set to ‘Auto’ mode, which is the default axes limits mode. If instead we manually set the axes limits to the requested range, Matlab skips these checks, enabling much faster plotting performance.

Let us simulate the situation by adding 500 data points to a plot, one at a time:

>> x=0:0.02:10; y=sin(x);
>> clf; cla; tic;
>> drawnow; plot(x(1),y(1)); hold on; legend data;
>> for idx = 1 : length(x); plot(x(idx),y(idx)); drawnow; end;
>> toc
 
Elapsed time is 21.583668 seconds.

simple plot with 500 data points

simple plot with 500 data points

And now let’s use static axes limits:

>> x=0:0.02:10; y=sin(x);
>> clf; cla; tic; drawnow; 
>> plot(x(1),y(1)); hold on; legend data;
 
>> xlim([0,10]); ylim([-1,1]);  % static limits
 
>> for idx = 1 : length(x); plot(x(idx),y(idx)); drawnow; end;
>> toc
 
Elapsed time is 16.863090 seconds.

Note that this trick is the basis for the performance improvement that occurs when using the plot’s undocumented set of LimInclude properties.

Of course, setting manual limits prevents the axes limits from growing and shrinking automatically with the data, which can actually be a very useful feature sometimes. But if performance is important, we now know that we have this tool to improve it.

Performance hack #2: static legend

Hack #1 gave us a 22% performance boost, but we can do much better. Running the profiler on the code above we see that much of the time is spent recomputing the legend. Looking inside the legend code (specifically, the legendcolorbarlayout function), we detect several short-circuits that we can use to make the legend static and prevent recomputation:

>> x=0:0.02:10; y=sin(x);
>> clf; cla; tic; drawnow; 
>> plot(x(1),y(1)); hold on; legend data;
 
>> xlim([0,10]); ylim([-1,1]);  % static limits
 
>> % Static legend
>> set(gca,'LegendColorbarListeners',[]); 
>> setappdata(gca,'LegendColorbarManualSpace',1);
>> setappdata(gca,'LegendColorbarReclaimSpace',1);
 
>> for idx = 1 : length(x); plot(x(idx),y(idx)); drawnow; end;
>> toc
 
Elapsed time is 5.209053 seconds.

Now this is much much better – a 76% performance boost compared to the original plot (i.e., 4 times faster!). Of course, it prevents the legend from being dynamically updated. Sometimes we actually wish for this dynamic effect (last year I explained how to use the legend’s undocumented -DynamicLegend feature for even greater dynamic control). But when performance is important, we can still display a legend without its usual performance cost.

In conclusion, I have demonstrated that Matlab performance can often be improved significantly, even in the absence of any vectorization, by simply understanding the internal mechanisms and bypassing those which are irrelevant in our specific case.

Have you found other similar performance hacks? If so, please share them in the comments section below.

Matlab layout managers: uicontainer and relatives

Wednesday, June 9th, 2010

When designing Matlab applications, we can either use Matlab’s designer (guide), or manually position each GUI component programmatically, using its Position property. Matlab lacks the layout managers so common in Java, that enable easy relative component positioning, taking into account dynamic container size, components spacing weights etc. Of course, we can always trap the container’s ResizeFcn callback to update our layout, but doing so is one royal pain in the so-and-so…

Luckily, there is (of course) an undocumented solution to this problem, and at the public’s demand I will detail it below. It doesn’t solve all layout-management needs, but it goes a long way. Most importantly, it uses pure Matlab – no Java knowledge whatsoever is needed.

uicontainer

Matlab’s uicontainer family (uicontainer, uiflowcontainer and uigridcontainer) consists of container objects that enable customizable layout management of contained components. Uicontainers can contain any Matlab component that may have a uipanel handle as a Parent property. This includes uicontrols, plot axes etc., as well as other uicontainers.

The basic uicontainer object appears to be little more than a transparent container for contained objects. It can be used interchangeably with uipanel, which appears to be a specialized type of a uicontainer. Indeed, as MathWorks notes:
The UICONTAINER function is undocumented, and is not intended for direct use. The UIPANEL function should be used instead, as it provides more functionality.

In some cases, Matlab itself uses uicontainer instead of uipanel: for example, ActiveX controls are enclosed within transparent uicontrol objects when added to a figure:

>> [hActivex,hContainer] = actxcontrol('OWC11.Spreadsheet.11');
>> get(hContainer,'Type')
ans =
uicontainer

uicontainer objects are not very customizable. For example, unlike uipanels, uicontainers have no titles or borders. We would therefore usually prefer to use uipanels, as Mathworks suggested above. An exception to this rule is a case where we need to derive our own customized container class. An example of this is found in %matlabroot%/toolbox/matlab/uitools/@uitools/@uitab/schema.m, which derives uicontainer to create a uitab container (which will be described in a future article).

Relatives of uicontainer are more useful in general: uiflowcontainers and uigridcontainers act similarly to Java’s layout managers – specifically, FlowLayout and GridLayout. I expect to see additional layout managers incarnated within Matlab uicontainers in future Matlab versions (perhaps in the R2010b pre-release that came out today – I can’t wait to see…).

uiflowcontainer

uiflowcontainer is a uicontainer that enables adding uicontrols to the container without specifying an exact position as would be required for uicontainer or uipanel (actually, positions may be specified, but they are simply ignored).

By default, objects are added from the top-left corner, depending on the uiflowcontainer’s available space and dimensions: if width > height then rightward, otherwise downward. If the container’s dimensions change, for example by resizing the figure window, then the container’s components will automatically be resized accordingly:

hc = uiflowcontainer('Units','norm','Position',[.1,.1,.8,.8]);
h1 = uicontrol('string','1','parent',hc);
h2 = uicontrol('string','2','parent',hc);
h3 = uicontrol('string','3','parent',hc);

'Auto' - before resizing figure

'Auto' - before resizing figure

…and after resizing

…and after resizing

The components flow direction within the container may be modified by setting the uiflowcontainer’s FlowDirection property from its default value of ‘Auto’ to ‘AutoReverse’, ‘BottomUp’, ‘TopDown’, ‘LeftToRight’, or ‘RightToLeft’:

set(hc,'FlowDirection','BottomUp')
set(hc,'FlowDirection','RightToLeft')

'BottomUp'

'BottomUp'

'RightToLeft'

'RightToLeft'

Spacing between the components and the container’s border, and between themselves, may be controlled via the Margin property. By default, Margin is set to 2 (pixels):

Margin = 2 (default)

Margin = 2 (default)

Margin = 10

Margin = 10

The advantage of using uiflowcontainer is its automatic resizing and positioning of components. Notice how we simply specified the uiflowcontainer’s handle as the control’s parent, and got all this functionality out-of-the-box!

If we need to use fixed-dimensions components, we can use uicontrol’s undocumented properties HeightLimits and WidthLimits, each of which is a 2-element numeric vector specifying the minimal and maximal allowed value for the height or width (both of these vectors are [2,Inf] by default). uiflowcontainer tries to accommodate the requested limits by stretching or compressing its components (we need to resize the figure for the component resizing to become visible):

set(h1, 'HeightLimits',[10,20], 'WidthLimits',[30,30])
set(h2, 'HeightLimits',[50,50])
set(h3, 'HeightLimits',[2,inf])   % =default value

WidthLimits set

WidthLimits set

Sometimes, however, no amount of component resizing is enough to fully contain all components within the uiflowcontainer:

set(h2, 'WidthLimits',[150,150])
set(h3, 'HeightLimits',[50,50])  % resize figure to see effect

WidthLimits set

WidthLimits set

Note: uiflowcontainer normally ignores the specified limits if they would cause the component to stretch beyond the container boundaries. This happens unless the limits are identical (as in the preceding example), which informs uiflowcontainer that it has no judgment in the component’s dimensions.

In more complex cases, consider coding your own customized class deriving from uiflowcontainer. An example for such a customization can be seen in %matlabroot%/toolbox/matlab/uitools/@uitools/@uitabgroup/schema.m, which derives uiflowcontainer to create a uitabgroup container.

Components within a uiflowcontainer are ordered according to the order they were added to the container. This order can be modified by rearranging the handles in the container’s Children property, or by using the uistack function which does the same. Note that a side-effect of this is that the components dimensions are re-normalized:

uistack(h2,'top')

uistack(h2,'top')

uistack(h2,'bottom')

uistack(h2,'bottom')

uigridcontainer

uigridcontainer is similar to uiflowcontainer in its specialization of the layout: in this case, the container is divided into a transparent grid of N-by-M cells (1×1 by default), each of which can contain its own component:

hc = uigridcontainer('Units','norm','Position',[.1,.1,.8,.8]);
set(hc, 'GridSize',[2,3]);  % default GridSize is [1,1]
h1 = uicontrol('string','1','parent',hc);
h2 = uicontrol('string','2','parent',hc);
h3 = uicontrol('string','3','parent',hc);
h4 = axes('parent',hc); x = -4:.1:4; plot(h4,x,sin(x));
set(h4,'YTickLabel',[],'XTickLabel',[]);

A 2-by-3 uigridcontainer

A 2-by-3 uigridcontainer

The grid cells relative size can be controlled via the HorizontalWeight and VerticalWeight properties (set to NaN by default). These properties should be a numeric vector the same size as the corresponding number of cells. The property values are not important – only their relative values are used to control the relative cell dimensions. The EliminateEmptySpace property (default=’off’) controls whether empty grid rows/columns are eliminated from the container or displayed. As in uiflowcontainers, the Margin property controls the spacing between the internal components and borders:

set(hc, 'HorizontalWeight',[6,3,1], 'VerticalWeight',[0.2,0.5])
delete([h2,h3]);  % only h1,h4 remain
set(hc,'EliminateEmptySpace','on')

Non-equal grid weights

Non-equal grid weights

EliminateEmptySpace='on'

EliminateEmptySpace='on'

...and 'off'

...and 'off'

Other layout alternatives

Brad Phelan of XTargets has created Matlab equivalents of Java’s BorderLayout and SpringLayout. The advantage of using Brad’s layout managers is that they appear to have full Matlab interoperability, including the ability to add Matlab components, unlike Java’s layout managers.

A File Exchange contributor named Jason has added a GridBagLayout implementation, mimicking Java’s well-known GridBagLayout.

Additional and more flexible layout managers are available in Java (one of my favorites is JGoodies Forms, which is pre-bundled with Matlab). Just remember the limitation that no Matlab component (such as GUI controls or plot axes) can be added to Java containers. Therefore, feel free to use these Java containers as long as their contained GUI is limited to Java components (JButton, JComboBox etc.).

Other uitools

Today’s article about uicontainer and its relatives was the first of several posts that will describe undocumented functions that reside in the %matlabroot%/toolbox/matlab/uitools folder. Feel free to look within this folder for other interesting undocumented functions. Most of these functions are semi-documented, meaning that they have a usable help-section hidden within the m-file (type “edit uicontainer.m” for example). Many have existed more-or-less unchanged for many releases. Note that there is no guarantee that they will remain in future releases. When using unsupported functionality, always code defensively.

Modifying default toolbar/menubar actions

Wednesday, June 2nd, 2010

Did you ever wish to modify Matlab’s default toolbar/menubar items?

I recently consulted to a client who needed to modify the default behavior of the legend action in the toolbar, and the corresponding item on the main menu (Insert / Legend). The official version is that only user-added items can be customized, whereas standard Matlab items cannot.

Luckily, this can indeed be done using simple pure-Matlab code. The trick is to get the handles of the toolbar/menubar objects and then to modify their callback properties.

Default legend insertion action

Default legend insertion action

Using the toolbar/menubar item handles

Getting the handles can be done in several different ways. In my experience, using the object’s tag string is often easiest, fastest and more maintainable. Note that the Matlab toolbar and main menu handles are normally hidden (HandleVisibility = ‘off’). Therefore, in order to access them we need to use the findall function rather than the better-known findobj function. Also note that to set the callbacks we need to access differently-named properties: ClickedCallback for toolbar buttons, and Callback for menu items:

hToolLegend = findall(gcf,'tag','Annotation.InsertLegend');
set(hToolLegend, 'ClickedCallback',{@cbLegend,hFig,myData});
 
hMenuLegend = findall(gcf,'tag','figMenuInsertLegend');
set(hMenuLegend, 'Callback',{@cbLegend,hFig,myData});

As a side note, two undocumented/unsupported functions, uitool(hFig,tagName) and uigettoolbar, also retrieve toolbar items. Since using findall is so simple and more supported, I suggest using the findall approach.

To see the list of available toolbar/menubar tags, use the following code snippet:

% Toolbar tag names:
>> hToolbar = findall(gcf,'tag','FigureToolBar');
>> get(findall(hToolbar),'tag')
ans = 
    'FigureToolBar'
    'Plottools.PlottoolsOn'
    'Plottools.PlottoolsOff'
    'Annotation.InsertLegend'
    'Annotation.InsertColorbar'
    'DataManager.Linking'
    'Exploration.Brushing'
    'Exploration.DataCursor'
    'Exploration.Rotate'
    'Exploration.Pan'
    'Exploration.ZoomOut'
    'Exploration.ZoomIn'
    'Standard.EditPlot'
    'Standard.PrintFigure'
    'Standard.SaveFigure'
    'Standard.FileOpen'
    'Standard.NewFigure'
    ''
 
% Menu-bar tag names:
>> get(findall(gcf,'type','uimenu'),'tag')
ans = 
    'figMenuHelp'
    'figMenuWindow'
    'figMenuDesktop'
    'figMenuTools'
    'figMenuInsert'
    'figMenuView'
    'figMenuEdit'
    'figMenuFile'
    'figMenuHelpAbout'
    'figMenuHelpPatens'
    'figMenuHelpTerms'
    'figMenuHelpActivation'
    'figMenuDemos'
    'figMenuTutorials'
    'figMenuHelpUpdates'
    'figMenuGetTrials'
    'figMenuWeb'
    'figMenuHelpPrintingExport'
    'figMenuHelpAnnotatingGraphs'
    'figMenuHelpPlottingTools'
    'figMenuHelpGraphics'
    ''
    ''                    <= Note the missing tag names...
    ''
    'figMenuToolsBFDS'    <= note the duplicate tag names...
    'figMenuToolsBFDS'
    'figDataManagerBrushTools'
    'figMenuToolsAlign'
    'figMenuToolsAlign'
    ... (plus many many more...)

Unfortunately, as seen above, Matlab developers forgot to assign tags to some default toolbar/menubar items. Luckily, in my particular case, both legend handles (toolbar, menu) have valid tag names that can be used: ‘Annotation.InsertLegend’ and ‘figMenuInsertLegend’.

If an item’s tag is missing, you can always find its handle using its Parent, Label, Tooltip or Callback properties. For example:

hPrintMenuItem = get(findall(gcf,'Label','&Print...'));

Note that property values, such as the tag names or labels, are unsupported and undocumented. They may change without warning or notice between Matlab releases, and have indeed done so in the past. Therefore, if your code needs to be compatible with older Matlab releases, ensure that you cover all the possible property values, or use a different way to access the handles. While using the tag name or label as shown above is considered “Low risk” (I don’t expect it to break in the near future), their actual values should be considered somewhat more risky and we should therefore code defensively.

Another simple example: Print Preview

As another simple and very useful example, let’s modify the default Print action (and tooltip) on the figure toolbar to display the Print-Preview window rather than send the figure directly to the printer:

Matlab's default toolbar Print action

Matlab's default toolbar Print action

hToolbar = findall(gcf,'tag','FigureToolBar');
hPrintButton = findall(hToolbar,'tag','Standard.PrintFigure');
set(hPrintButton, 'ClickedCallback','printpreview(gcbf)', ...
                  'TooltipString','Print Preview');

Matlab's Print Preview window

Matlab's Print Preview window

More advanced customization of the toolbar and menu items are possible, but require a bit of Java code. Examples of toolbar customizations were presented in past articles (here and here). A future article will explain how to customize menu items.

Have you found a nifty way to customize the menubar or toolbar? If so, please share it in the comments section below.

Image Easter egg

Tuesday, April 6th, 2010

Last year I presented the Matlab Spy Easter egg for the 2009 Easter holiday. This year, slightly late, I present another Easter egg in the well-known image function: When we run image with no input arguments, we get a default image of an inverted boy:

image;

Default image

Default image

To see the image right-side up:

image;
colormap(gray(32));
axis ij image off

Corrected default image

Corrected default image

In fact, it turns out that there are quite a few hidden super-imposed images here, and that there is an interesting story behind them, which was explained by Steve Eddins in his Image Processing blog. For those interested, the boy above is Steve’s eldest, but that’s only a small part of the story…

Happy Holiday!

Yair

p.s. – The default image has not changed in many years. I guess the boy should be in high school or college by now. Perhaps it’s time to post an updated picture in the R2010b release, Steve?

Plot LimInclude properties

Wednesday, March 31st, 2010

Concluding my three-part mini-series on hidden and undocumented plot/axes properties, I would like to present a set of properties that I find very useful in dynamic plots: XLimInclude, YLimInclude, ZLimInclude, ALimInclude and CLimInclude. These properties, which are relevant for plot/axes objects, have an ‘on’ value by default. When set to ‘off’, they exclude their object from the automatic computation of the corresponding axes limits (XLim/YLim/ZLim/ALim/CLim).

For example, here’s a simple sine wave with a wavefront line marker. Note how the too-tall wavefront line affects the entire axes Y-limits:

cla;
t=0:.01:7.5;
plot(t,sin(t));
line('xdata',[7.5,7.5], 'ydata',[-5,5], 'color','r'); 
box off

Regular plot (YLimInclude on)

Regular plot (YLimInclude on)

This situation is quickly fixed using the YLimInclude property:

cla;
t=0:.01:7.5;
plot(t,sin(t));
line('xdata',[7.5,7.5], 'ydata',[-5,5], 'color','r', ...
     'YLimInclude','off'); 
box off

YLimInclude off

YLimInclude off

Beside the functional importance of this feature, it also has a large potential for improved application performance: I recently designed a monitor-like GUI for a medical application, where the data is constantly updated from an external sensor connected to the computer. The GUI presents the latest 10 seconds of monitored data, which bounce up and down the chart. A red wave-front line is presented and constantly updated, to indicate the current data position. Since the monitored data jumps up and down, the Y-limits of the monitor chart often changes, and with it I would need to modify the wavefront’s YData based on the updated axes YLim. This turned out to steal precious CPU time from the actual monitoring application. Came YLimInclude to the rescue, by letting me specify the wavefront line as:

hWavefront = line(..., 'YData',[-99,99], 'YLimInclude','off');

Now the wavefront line never needed to update its YData (only XData, which is much less CPU-intensive) – it always spanned the entire axes height, since [-99,99] were assured (in my particular case) to exceed the actual monitored data. This looked better (no flicker effects) and performed faster than the regular (documented) approach.

Note that although all these properties exist, to the best of my knowledge, for all Handle-Graphic plot objects, they are sometimes meaningless. For example, ZLimInclude is irrelevant for a 2D patchless plot; CLimInclude relates to the axes color limits which are irrelevant if you’re not using a colormap or something similar; ALimInclude relates to patch transparency (alpha-channel) and is irrelevant elsewhere. In these and similar cases, setting these properties, while allowed and harmless, will simply have no effect.

This concludes my mini-series of undocumented plot/axes properties. To recap, the other articles dealt with the LooseInset and LineSmoothing properties.

Have you found other similar properties or use-cases that you find useful? I will be most interested to read about them in the comments section below.

Axes LooseInset property

Wednesday, March 24th, 2010

Last week, I wrote an article about the hidden/undocumented LineSmoothing plot property. This week, I want to introduce another useful hidden/undocumented property – the plot axes’ LooseInset property. This follows on the wake of an email I received from a reader about this property, which had some new information for me (thanks Ben!).

Apparently, LooseInset, which is automatically set to a factory value of [0.13, 0.11, 0.095, 0.075], is used by Matlab axes to reserve a small empty margin around the axes, presumably to enable space for tick marks. These empty margins can be very annoying at times, especially when we have directly control on the axes contents.

figure; t=0:0.01:7; plot(t,2*sin(t));

Axes with default LooseInset values (note the excessive margins)

Axes with default LooseInset values
(note the excessive margins)

If you set Position to [0 0 1 1], the labels are cut-off; if you set Position to something like [0.05 0.05 0.9 0.9], you can get the labels to show up, but if you now resize the image the labels may be cut off… Similarly, setting TightInset also does not work.

Theoretically, the solution should be to set OuterPosition to [0 0 1 1]. This is supposed to make the axes (including labels) take up the entire figure. However, it usually over-estimates the required margins, causing wasted space. Using OuterPosition also causes unexpected behaviors with sub-plots.

Solution: simply set LooseInset to [0 0 0 0]:

set(gca, 'LooseInset', [0,0,0,0]);

Axes with empty LooseInset values

Axes with empty LooseInset values

To modify all future axes in the same way (i.e., have an empty LooseInset):

set(0,'DefaultAxesLooseInset',[0,0,0,0])

Clearing the LooseInset margins has a drawback: if the axes is zoomed or modified in such a way that the labels change, then the active axes plot region needs to shrink accordingly. For example:

Axes with empty LooseInset values, wide tick labels (note the changed plot region size)

Axes with empty LooseInset values, wide tick labels
(note the changed plot region size)

When determining the size of the axes, it seems that Matlab takes into account larger of the documented TightInset and the undocumented LooseInset. So, perhaps a better generic solution would be the one suggested by another blog reader:

set(gca,'LooseInset',get(gca,'TightInset'))

Note that the LooseInset property was first reported on CSSM back in 2007 (also here). The LooseInset property has remained hidden and undocumented to this day (Matlab 7.10, R2010a), although it has even featured in an official MathWorks Technical Solution to a reported problem about unexpected axes sizes last year.

p.s. – another undocumented property of Matlab axes, ContentsVisible, was described by Matt Whittaker in a comment on my original article that introduced undocumented properties.