Preallocation performance

Array preallocation is a standard and quite well-known technique for improving Matlab loop run-time performance. Today’s article will show that there is more than meets the eye for even such a simple coding technique.

A note of caution: in the examples that follow, don’t take any speedup as an expected actual value – the actual value may well be different on your system. Your mileage may vary. I only mean to display the relative differences between different alternatives.

The underlying problem

Memory management has a direct influence on performance. I have already shown some examples of this in past articles here.

Preallocation solves a basic problem in simple program loops, where an array is iteratively enlarged with new data (dynamic array growth). Unlike other programming languages (such as C, C++, C# or Java) that use static typing, Matlab uses dynamic typing. This means that it is natural and easy to modify array size dynamically during program execution. For example:

fibonacci = [0, 1];
for idx = 3 : 100
   fibonacci(idx) = fibonacci(idx-1) + fibonacci(idx-2);
end

While this may be simple to program, it is not wise with regards to performance. The reason is that whenever an array is resized (typically enlarged), Matlab allocates an entirely new contiguous block of memory for the array, copying the old values from the previous block to the new, then releasing the old block for potential reuse. This operation takes time to execute. In some cases, this reallocation might require accessing virtual memory and page swaps, which would take an even longer time to execute. If the operation is done in a loop, then performance could quickly drop off a cliff.

The cost of such naïve array growth is theoretically quadratic. This means that multiplying the number of elements by N multiplies the execution time by about N2. The reason for this is that Matlab needs to reallocate N times more than before, and each time takes N times longer due to the larger allocation size (the average block size multiplies by N), and N times more data elements to copy from the old to the new memory blocks.

A very interesting discussion of this phenomenon and various solutions can be found in a newsgroup thread from 2005. Three main solutions were presented: preallocation, selective dynamic growth (allocating headroom) and using cell arrays. The best solution among these in terms of ease of use and performance is preallocation.

The basics of pre-allocation

The basic idea of preallocation is to create a data array in the final expected size before actually starting the processing loop. This saves any reallocations within the loop, since all the data array elements are already available and can be accessed. This solution is useful when the final size is known in advance, as the following snippet illustrates:

% Regular dynamic array growth:
tic
fibonacci = [0,1];
for idx = 3 : 40000
   fibonacci(idx) = fibonacci(idx-1) + fibonacci(idx-2);
end
toc
   => Elapsed time is 0.019954 seconds.
 
% Now use preallocation – 5 times faster than dynamic array growth:
tic
fibonacci = zeros(40000,1);
fibonacci(1)=0; fibonacci(2)=1;
for idx = 3 : 40000, 
   fibonacci(idx) = fibonacci(idx-1) + fibonacci(idx-2);
end
toc
   => Elapsed time is 0.004132 seconds.

On pre-R2011a releases the effect of preallocation is even more pronounced: I got a 35-times speedup on the same machine using Matlab 7.1 (R14 SP3). R2011a (Matlab 7.12) had a dramatic performance boost for such cases in the internal accelerator, so newer releases are much faster in dynamic allocations, but preallocation is still 5 times faster even on R2011a.

Non-deterministic pre-allocation

Because the effect of preallocation is so dramatic on all Matlab releases, it makes sense to utilize it even in cases where the data array’s final size is not known in advance. We can do this by estimating an upper bound to the array’s size, preallocate this large size, and when we’re done remove any excess elements:

% The final array size is unknown – assume 1Kx3K upper bound (~23MB)
data = zeros(1000,3000);  % estimated maximal size
numRows = 0;
numCols = 0;
while (someCondition)
   colIdx = someValue1;   numCols = max(numCols,colIdx);
   rowIdx = someValue2;   numRows = max(numRows,rowIdx);
   data(rowIdx,colIdx) = someOtherValue;
end
 
% Now remove any excess elements
data(:,numCols+1:end) = [];   % remove excess columns
data(numRows+1:end,:) = [];   % remove excess rows

Variants for pre-allocation

It turns out that MathWorks’ official suggestion for preallocation, namely using the zeros function, is not the most efficient:

% MathWorks suggested variant
clear data1, tic, data1 = zeros(1000,3000); toc
   => Elapsed time is 0.016907 seconds.
 
% A much faster alternative - 500 times faster!
clear data1, tic, data1(1000,3000) = 0; toc
   => Elapsed time is 0.000034 seconds.

The reason for the second variant being so much faster is because it only allocates the memory, without worrying about the internal values (they get a default of 0, false or ”, in case you wondered). On the other hand, zeros has to place a value in each of the allocated locations, which takes precious time.

In most cases the differences are immaterial since the preallocation code would only run once in the program, and an extra 17ms isn’t such a big deal. But in some cases we may have a need to periodically refresh our data, where the extra run-time could quickly accumulate.

Pre-allocating non-default values

When we need to preallocate a specific value into every data array element, we cannot use Variant #2. The reason is that Variant #2 only sets the very last data element, and all other array elements get assigned the default value (0, ‘’ or false, depending on the array’s data type). In this case, we can use one of the following alternatives (with their associated timings for a 1000×3000 data array):

scalar = pi;  % for example...
 
data = scalar(ones(1000,3000));           % Variant A: 87.680 msecs
data(1:1000,1:3000) = scalar;             % Variant B: 28.646 msecs
data = repmat(scalar,1000,3000);          % Variant C: 17.250 msecs
data = scalar + zeros(1000,3000);         % Variant D: 17.168 msecs
data(1000,3000) = 0; data = data+scalar;  % Variant E: 16.334 msecs

As can be seen, Variants C-E are about twice as fast as Variant B, and 5 times faster than Variant A.

Pre-allocating non-double data

7.4.5 Preallocating non-double data
When preallocating an array of a type that is not double, we should be careful to create it using the desired type, to prevent memory and/or performance inefficiencies. For example, if we need to process a large array of small integers (int8), it would be inefficient to preallocate an array of doubles and type-convert to/from int8 within every loop iteration. Similarly, it would be inefficient to preallocate the array as a double type and then convert it to int8. Instead, we should create the array as an int8 array in the first place:

% Bad idea: allocates 8MB double array, then converts to 1MB int8 array
data = int8(zeros(1000,1000));   % 1M elements
   => Elapsed time is 0.008170 seconds.
 
% Better: directly allocate the array as a 1MB int8 array – x80 faster
data = zeros(1000,1000,'int8');
   => Elapsed time is 0.000095 seconds.

Pre-allocating cell arrays

To preallocate a cell-array we can use the cell function (explicit preallocation), or the maximal cell index (implicit preallocation). Explicit preallocation is faster than implicit preallocation, but functionally equivalent (Note: this is contrary to the experience with allocation of numeric arrays and other arrays):

% Variant #1: Explicit preallocation of a 1Kx3K cell array
data = cell(1000,3000);
   => Elapsed time is 0.004637 seconds. 
 
% Variant #2: Implicit preallocation – x3 slower than explicit
clear('data'), data{1000,3000} = [];
   => Elapsed time is 0.012873 seconds.

Pre-allocating arrays of structs

To preallocate an array of structs or class objects, we can use the repmat function to replicate copies of a single data element (explicit preallocation), or just use the maximal data index (implicit preallocation). In this case, unlike the case of cell arrays, implicit preallocation is much faster than explicit preallocation, since the single element does not actually need to be copied multiple times (ref):

% Variant #1: Explicit preallocation of a 100x300 struct array
element = struct('field1',magic(2), 'field2',{[]});
data = repmat(element, 100, 300);
   => Elapsed time is 0.002804 seconds. 
 
% Variant #2: Implicit preallocation – x7 faster than explicit 
element = struct('field1',magic(2), 'field2',{[]});
clear('data'), data(100,300) = element;
   => Elapsed time is 0.000429 seconds.

When preallocating structs, we can also use a third variant, using the built-in struct feature of replicating the struct when the struct function is passed a cell array. For example, struct('field1',cell(100,1), 'field2',5) will create 100 structs, each of them having the empty field field1 and another field called field2 with value 5. Unfortunately, this variant is slower than both of the previous variants.

Pre-allocating class objects

When preallocating in general, ensure that you are using the maximal expected array size. There is no point in preallocating an empty array or an array having a smaller size than the expected maximum, since dynamic memory reallocation will automatically kick-in within the processing-loop. For this reason, do not use the empty() method of class objects to preallocate, but rather repmat as explained above.

When using repmat to replicate class objects, always be careful to note whether you are replicating the object itself (this happens if your class does NOT derive from handle) or its reference handle (which happens if you derive the class from handle). If you are replicating objects, then you can safely edit any of their properties independently of each other; but if you replicate references, you are merely using multiple copies of the same reference, so that modifying referenced object #1 will also automatically affect all the other referenced objects. This may or may not be suitable for your particular program requirements, so be careful to check carefully. If you actually need to use independent object copies, you will need to call the class constructor multiple times, once for each new independent object.

Next week: what if we can’t avoid dynamic array resizing? – apparently, all is not lost. Stay tuned…


Do you have any similar allocation-related tricks you’re using? or unexpected differences such as the ones shown above? If so, then please do post a comment.

Categories: Low risk of breaking in future versions, Memory, Stock Matlab function, Undocumented feature
Tags: , , , ,
6 Comments

Customizing menu items part 3

In the past weeks I’ve shown how Matlab menus can be customized in a variety of undocumented manners, using HTML, pure Matlab, and Java. Today I conclude this mini-series with an article that explains how to use the underlying Java object to customize menu item icons. Menu customizations are explored in depth in section 4.6 of my book.

A reminder: accessing the underlying Java object

Matlab menus (uimenu) are basically simple wrappers for the much more powerful and flexible Java Swing JMenu and JMenuItem on which they are based. Many important functionalities that are available in Java menus are missing from the Matlab uimenus.

Getting the Java reference for the figure window’s main menu is very easy:

jFrame = get(handle(hFig),'JavaFrame');
try
    % R2008a and later
    jMenuBar = jFrame.fHG1Client.getMenuBar;
catch
    % R2007b and earlier
    jMenuBar = jFrame.fFigureClient.getMenuBar;
end

There are many customizations that can only be done using the Java handle: setting icons, several dozen callback types, tooltips, background color, font, text alignment, and so on. etc. Interested readers may wish to get/set/inspect/methodsview/uiinspect the jSave reference handle and/or to read the documentation for JMenuItem. Today’s article will focus on icon customizations.

Setting simple menu item icons

Many of Matlab’s icons reside in either the [matlabroot '/toolbox/matlab/icons/'] folder or the [matlabroot '/java/jar/mwt.jar'] file (a JAR file is simply a zip file that includes Java classes and resources such as icon images). Let us create icons from the latter, to keep a consistent look-and-feel with the rest of Matlab (we could just as easily use our own external icon files):

% External icon file example
jSave.setIcon(javax.swing.ImageIcon('C:\Yair\save.gif'));
 
% JAR resource example
jarFile = fullfile(matlabroot,'/java/jar/mwt.jar');
iconsFolder = '/com/mathworks/mwt/resources/';
iconURI = ['jar:file:/' jarFile '!' iconsFolder 'save.gif'];
iconURI = java.net.URL(iconURI);  % not necessary for external files
jSave.setIcon(javax.swing.ImageIcon(iconURI));

Note that setting a menu item’s icon automatically re-aligns all other items in the menu, including those that do not have an icon (an internal bug that was introduced in R2010a causes a misalignment, as shown below):

Menu item with a custom Icon (R2009b)

Menu item with a custom Icon (R2009b)

   
...and the same in R2010a onward

...and the same in R2010a onward

Checkmark icon

The empty space on the left of the menu is reserved for the check mark. Each Matlab menu item is check-able, since it is an object that extends the com.mathworks.mwswing.MJCheckBoxMenuItem class. I have not found a way to eliminate this empty space, which is really unnecessary in the File-menu case (it is only actually necessary in the View and Tools menus). Note that if an icon is set for the item, both the icon and the checkmark will be displayed, side by side.

The check mark is controlled by the State property of the Java object (which accepts logical true/false values), or the Checked property of the Matlab handle (which accepts the regular ‘on’/'off’ string values):

% Set the check mark at the Matlab level
set(findall(hFig,'tag','figMenuFileSave'), 'Checked','on');
 
% Equivalent - set the checkmark at the Java level
jSave.setState(true);

State = true, Icon = [ ]

State = true, Icon = [ ]

   
State = true, Icon = custom

State = true, Icon = custom

Customizing menu icons

Icons can be customized: modify the gap between the icon and the label with the IconTextGap property (default = 4 [pixels]); place icons to the right of the label by setting HorizontalTextPosition to jSave.LEFT (=2), or centered using jSave.CENTER (=0). Note that the above-mentioned misalignment bug does not appear in these cases:

jSave.setHorizontalTextPosition(jSave.LEFT)

jSave.setHorizontalTextPosition
(jSave.LEFT)

   
jSave.setHorizontalTextPosition(jSave.CENTER)

jSave.setHorizontalTextPosition
(jSave.CENTER)

Note how the label text can be seen through (or on top of) the icon when it is centered. This feature can be used to create stunning menu effects as shown below. Note how the width and height of the menu item automatically increased to accommodate my new 77×31 icon size (icons are normally sized 16×16 pixels):

Overlaid icon (HorizontalTextPosition = CENTER)

Overlaid icon (HorizontalTextPosition = CENTER)

To resize an icon programmatically before setting it in a Java component, we can use the following example:

myIcon = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif');
imageToolkit = java.awt.Toolkit.getDefaultToolkit;
iconImage = imageToolkit.createImage(myIcon);
iconImage = iconImage.getScaledInstance(32,32,iconImage.SCALE_SMOOTH);
jSave.setIcon(javax.swing.ImageIcon(iconImage));

Remember when rescaling images, particularly small ones with few pixels, that it is always better to shrink than to enlarge images: enlarging a small icon image might introduce a significant pixelization effect:

16x16 icon image resized to 32x32

16x16 icon image resized to 32x32

Separate icons can be specified for a different appearance during mouse hover (RolloverIcon; requires RolloverEnabled=1), item click/press (PressedIcon), item selection (SelectedIcon, RolloverSelectedIcon, DisabledSelectedIcon), and disabled menu item (DisabledIcon). All these properties are empty ([]) by default, which applies a predefined default variation (image color filter) to the main item’s Icon. For example, let us modify DisabledIcon:

myIcon = 'C:\Yair\Undocumented Matlab\Images\save_disabled.gif';
jSaveAs.setDisabledIcon(javax.swing.ImageIcon(myIcon));
jSaveAs.setEnabled(false);

Enabled, main Icon

Enabled, main Icon

   
Disabled, default Icon variation

Disabled, default Icon variation

   
Disabled, custom DisabledIcon

Disabled, custom DisabledIcon

Note the automatic graying of disabled menu items, including their icon. This effect can also be achieved programmatically using the static methods in com.mathworks.mwswing.IconUtils: changeIconColor(), createBadgedIcon(), createGhostedIcon(), and createSelectedIcon(). When we use a non-default custom DisabledIcon, it is used instead of the gray icon variant.

This concludes my mini-series of customizing menus in Matlab. If you have used any nifty customization that I have not mentioned, please post a comment about it below.

Ken & MikeIn an unrelated note, I would like to extend good wishes to Mike Katz, who has left the MathWorks mobile development team to join Kinvey a few days ago. Mike has been with MathWorks since 2005 and has been responsible for maintaining the official MATLAB Desktop blog, together with Ken Orr. I’m not sure yet which direction the Desktop blog will take, and by whom, but in any case it won’t be the same. You’re both missed, Mike & Ken!

 

Categories: GUI, Icons, Java, Medium risk of breaking in future versions, Undocumented feature
Tags: , , , , ,
Leave a comment

Customizing menu items part 2

Last week I explained how to customize Matlab’s menu items using some undocumented tricks that do not need Java. Today I will show how using just a tiny bit of Java magic powder we can add much more complex customizations to menu items. Menu customizations are explored in depth in section 4.6 of my book.

Accessing the underlying Java object

Matlab menus (uimenu) are basically simple wrappers for the much more powerful and flexible Java Swing JMenu and JMenuItem on which they are based. Many important functionalities that are available in Java menus are missing from the Matlab uimenus.

Getting the Java reference for the figure window’s main menu is very easy:

jFrame = get(handle(hFig),'JavaFrame');
try
    % R2008a and later
    jMenuBar = jFrame.fHG1Client.getMenuBar;
catch
    % R2007b and earlier
    jMenuBar = jFrame.fFigureClient.getMenuBar;
end

Note that we have used the figure handle’s hidden JavaFrame property, accessed through the reference’s handle() wrapper, to prevent an annoying warning message.

There are many customizations that can only be done using the Java handle: setting icons, several dozen callback types, tooltips, background color, font, text alignment, and so on. etc. Interested readers may wish to get/set/inspect/methodsview/uiinspect the jSave reference handle and/or to read the documentation for JMenuItem. Some useful examples are provided below.

Dynamic menu behavior

As a first example of Java-based customization, let us add DHTML-like behavior to the menu, such that the menu items will automatically be displayed when the mouse hovers over the item, without waiting for a user mouse click. First, get the jMenuBar reference as described above. Now, set the MouseEnteredCallback to automatically simulate a user mouse click on each menu item using its doClick() method. Setting the callback should be done separately to each of the top-level menu components:

for menuIdx = 1 : jMenuBar.getComponentCount
    jMenu = jMenuBar.getComponent(menuIdx-1);
    hjMenu = handle(jMenu,'CallbackProperties');
    set(hjMenu,'MouseEnteredCallback','doClick(gcbo)');
end

Note that using this mechanism may be awkward if the top-level menu does not have a sub-menu but is rather a stand-alone menu item. For example, if the top-level menu-item “Help” is a stand-alone menu button (i.e., there are no help menu-items, just the single Help item), then moving the mouse over this item will trigger the help event, although the user did not actually click on the item. To prevent this behavior, we should modify the code snippet above to only work on those menu items that have sub-items.

Custom accelerator shortcut keys

As another example, Matlab automatically assigns a non-modifiable keyboard accelerator key modifier of , while JMenus allow any combination of Alt/Ctrl/Shift/Meta (depending on the platform). Let us modify the default File/Save accelerator key from ‘Ctrl-S’ to ‘Alt-Shift-S’ as an example. We need a reference for the “Save” menu item. Note that unlike regular Java components, menu items are retrieved using the getMenuComponent() method and not getComponent():

% File main menu is the first main menu item => index=0
jFileMenu = jMenuBar.getComponent(0);
 
% Save menu item is the 5th menu item (separators included)
jSave = jFileMenu.getMenuComponent(4); %Java indexes start with 0!
inspect(jSave) 	% just to be sure: label='Save' => good!
 
% Finally, set a new accelerator key for this menu item:
jAccelerator = javax.swing.KeyStroke.getKeyStroke('alt shift S');
jSave.setAccelerator(jAccelerator);

That is all there is to it – the label is modified automatically to reflect the new keyboard accelerator key. More info on setting different combinations of accelerator keys and modifiers can be found in the official Java documentation for KeyStroke.

Modification of menu item accelerator and tooltip

Modification of menu item accelerator and tooltip

Note that the Save menu-item reference can only be retrieved after opening the File menu at least once earlier; otherwise, an exception will be thrown when trying to access the menu item. The File menu does NOT need to remain open – it only needs to have been opened sometime earlier, for its menu items to be rendered. This can be done either interactively (by selecting the File menu) or programmatically:

% Simulate mouse clicks to force the File main-menu to open & close
jFileMenu.doClick; % open the File menu
jFileMenu.doClick; % close the menu
 
% Now the Save menu is accessible:
jSave = jFileMenu.getMenuComponent(4);

Tooltip and highlight

For some unknown reason, MathWorks did not include a tooltip property in its Matlab menu handle, contrary to all the other Matlab GUI components. So we must use the Java handle, specifically the ToolTipText property:

jSave.setToolTipText('modified menu item with tooltip');

Java menu items also contain a property called Armed, which is a logical value (default=false). When turned on, the menu item is highlighted just as when it is selected (see the Save As… menu item in the screenshot above). On a Windows system, this means a blue background:

jSave.setArmed(true);

When the item is actually selected and then de-selected, Armed reverts to a false (off) value. Alternating the Armed property value can achieve an effect of flashing the menu item.

Callbacks

In addition to the standard Swing control callbacks discussed in an earlier article, menu items possess several additional callbacks that are specific to menu items, including:

  • ActionPerformedCallback – fired when the menu item is invoked
  • StateChangedCallback – fired when the menu item is selected or deselected
  • MenuDragMouseXXXCallback (XXX=Dragged/Entered/Exited/Released) – fired when the menu item is dragged, for the corresponding event
  • MenuKeyXXXCallback (XXX=Pressed/Released/Typed) – fired when a keyboard click event occurs (the menu item’s accelerator was typed)

Using these callbacks, together with the 30-odd standard Swing callbacks, we can control our menu’s behavior to a much higher degree than possible using the standard Matlab handle.

Next week, I will conclude this mini-series with an article explaining how to customize menu item icons.

Categories: GUI, Java, Medium risk of breaking in future versions, Undocumented feature
Tags: , , , , ,
Leave a comment

Customizing menu items part 1

Over the past years, I have not posted articles dealing with menu items. I have shown how to directly access menu items’ hidden handles, but not much more than that. A year ago I promised a mini-series on menu customizations, and it’s time to keep my promise. In today’s article, the first in the mini-series, I will present several undocumented menu customization topics that rely on pure-Matlab (i.e, no Java today). The next article in this series will focus on Java-based customizations.

Invoking menu item callbacks

As noted above, a figure window’s menu items can be directly accessed. Once we access a menu item’s handle, we can extract its Callback property and directly invoke it (for example, using the semi-documented hgfeval function). Note that menu callbacks are kept in Callback, while toolbar callbacks are kept in ClickedCallback.

Menu callbacks generally use internal semi-documented functions (i.e., having a readable help section but no doc, online help, or official support), which are part of Matlab’s uitools folder. These functions are specific to each top-level menu tree: filemenufcn, editmenufcn, viewmenufcn, insertmenufcn, toolsmenufcn, desktopmenufcn, winmenu, and helpmenufcn implement the figure’s eight respective top-level menu trees’ callbacks. These functions accept an optional figure handle (otherwise, gcbf is assumed), followed by a string specifying the specific menu item whose action needs to be run. webmenufcn implements the Help menu’s Web Resources sub-menu callbacks in a similar manner.

Use of these functions makes it easy to invoke a menu action directly from our Matlab code: instead of accessing the relevant menu item and invoking its Callback, we simply find out the menu item string in advance and use it directly. For example,

filemenufcn FileClose;
editmenufcn(hFig,'EditPaste');

uimenufcn is a related fully-undocumented (built-in) function, available since Matlab R11 (late 1990s). It accepts a figure handle (or the zero [0] handle to indicate the desktop) and action name. For example, the fully-documented commandwindow function uses the following code to bring the Command Window into focus:

uimenufcn(0, 'WindowCommandWindow');

Customizing menus via uitools

makemenu is another semi-documented uitool function that enables easy creation of hierarchical menu trees with separators and accelerators. It is a simple and effective wrapper for uimenu. makemenu is a useful function that has been made obsolete (grandfathered) without any known replacement.

makemenu accepts four parameters: a figure handle, a char matrix of labels (‘>’ indicating sub item, ‘>>’ indicating sub-sub items etc.; ‘&’ indicating keyboard shortcut; ‘^x’ indicating an accelerator key; ‘-’ indicating a separator line), a char matrix of callbacks, and an optional char matrix of tags (empty by default). makemenu makes use of another semi-documented grandfathered function, menulabel, to parse the specified label components. makemenu returns an array of handles of the created uimenu items:

labels = str2mat('&File', ...    % File top menu
           '>&New^n', ...           % File=>New
           '>&Open', ...            % File=>Open
           '>>Open &document^d', ...    % File=>Open=>doc
           '>>Open &graph^g', ...       % File=>Open=>graph
           '>-------', ...          % File=>separator line
           '>&Save^s', ...          % File=>Save
           '&Edit', ...		% Edit top menu
           '&View', ...		% View top menu
           '>&Axis^a', ...          % View=>Axis
           '>&Selection region^r'); % View=>Selection
calls = str2mat('', ...		% no action: File top menu
           'disp(''New'')', ...
           '', ...			% no action: Open sub-menu
           'disp(''Open doc'')', ...
           'disp(''Open graph'')', ...
           '', ...			% no action: Separator
           'disp(''Save'')', ...
           '', ...			% no action: Edit top menu
           '', ...			% no action: View top menu
           'disp(''View axis'')', ...
           'disp(''View selection region'')');
handles = makemenu(hFig, labels, calls);
set(hFig,'menuBar','none');

A simple figure menu

A simple figure menu

Customizing menus via HTML

Since menu items share the same HTML/CSS support feature as all Java Swing labels, we can specify font size/face/color, bold, italic, underline, superscript/subscript, and practically any HTML formatting.

Note that some features, such as the font or foreground/background colors, have specific properties that we can set using the Java handle, instead of using HTML. The benefit of using HTML is that it enables setting all the formatting in a single property. HTML does not require using Java – just pure Matlab (see the following example).

Multi-line menu items can easily be done with HTML: simply include a <br> element in the label – the menu item will split into two lines and automatically resize vertically when displayed:

txt1 = '<html><b><u><i>Save</i></u>';
txt2 = '<font color="red"><sup>this file</sup></font></b></html>';
txt3 = '<br />this file as...';
set(findall(hFig,'tag','figMenuFileSave'),   'Label',[txt1,txt2]);
set(findall(hFig,'tag','figMenuFileSaveAs'), 'Label',[txt1,txt3]);

A multi-line HTML-rendered menu item

A multi-line HTML-rendered menu item

set(hMenuItem, 'Label',['<html>&2: C:\My Documents\doc.txt<br />'
   '<font size="-1" face="Courier New" color="red">&nbsp;&nbsp; '
   'Date: 15-Jun-2011 13:23:45<br />&nbsp;&nbsp; Size: 123 KB</font></html>']);

HTML-rendered menu items

HTML-rendered menu items

Much more complex customizations can be achieved using Java. So stay tuned to part 2 of this mini-series…

Note: Menu customization is explored in depth in section 4.6 of my book.

Categories: Figure window, GUI, Low risk of breaking in future versions, Semi-documented function
Tags: , , , , ,
5 Comments

Setting axes tick labels format

Have you ever tried to customize the way in which tick labels appear in Matlab plot axes?

For example, setting the numerical precision of the labels, or adding some short descriptive text (for example, the units)? If you have, then I bet that you have encountered the following dilemma: Once we modify the tick labels (for discussion sake, let’s assume the Y axis, so this is done by updating the YTickLabel property), then the corresponding YTickLabelMode property changes from ‘auto’ to ‘manual’ and loses its relationship to the tick values (YTick). So, if we now zoom or pan the plot, our new labels remain unchanged although the tick values have changed, causing much panic and frustration… If we also set the tick values manually, this solves that problem but leaves us with another: now, when we zoom or pan, we no longer see any ticks or tick labels at all!

Original plot Manual labels, auto ticks Manual labels, manual ticks

Original plot (left)
Manual labels, auto ticks (center)
Manual labels, manual ticks (right)

Of course, we can always trap the zoom and pan callback functions to update the tick labels dynamically while keeping the tick values automatically. This will work for these cases, but we need to do it separately for zoom and pan. Also, if we modify the axes limits explicitly (via the corresponding YLim property) or indirectly (by modifying the displayed plot data), then the callbacks are not called and the labels are not updated.

The solution – using a property change listener

A better way to solve this problem is to simply trap changes to the displayed tick values, and whenever these occur to call our dedicated function to update the labels according to the new tick values. This can be done by using UDD, or more precisely the ability to trap update events on any property (in our case, YTick). Such a mechanism was already demonstrated here in 2010, as one way to achieve continuous slider feedback. The idea is to use the built-in handle.listener function with the PropertyPostSet event, as follows:

hhAxes = handle(hAxes);  % hAxes is the Matlab handle of our axes
hProp = findprop(hhAxes,'YTick');  % a schema.prop object
hListener = handle.listener(hhAxes, hProp, 'PropertyPostSet', @myCallbackFunction);
setappdata(hAxes, 'YTickListener', hListener);

Note that we have used setappdata to store the hListener handle in the axes. This ensures that the listener exists for exactly as long as the axes does. If we had not stored this listener handle somewhere, then Matlab would have immediately deleted the listener hook and our callback function would not have been called upon tick value updates. Forgetting to store listener handles is a common pitfall when using them. If you take a look at the addlistener function’s code, you will see that it also uses setappdata after creating the listener, for exactly this reason. Unfortunately, addlistsner cannot always be used, and I keep forgetting under which circumstances, so I generally use handle.listener directly as above: It’s simple enough to use that I find I never really need to use the simple addlistener wrapper, but you are welcome to try it yourself.

That’s all there is to it: Whenever YTick changes its value(s), our callback function (myCallbackFunction) will automatically be called. It is quite simple to set up. While we cannot use TeX in tick labels yet (this will change in the upcoming HG2), using sprintf formatting does enable quite a bit of flexibility in formatting the labels. For example, let’s say I want my tick labels to have the format ‘%.1fV’ (i.e., always one decimal, plus the Volts units):

function myCallbackFunction(hProp,eventData)    %#ok - hProp is unused
   hAxes = eventData.AffectedObject;
   tickValues = get(hAxes,'YTick');
   newLabels = arrayfun(@(value)(sprintf('%.1fV',value)), tickValues, 'UniformOutput',false);
   set(hAxes, 'YTickLabel', newLabels);
end  % myCallbackFunction

Manual labels, automatically updated Manual labels, automatically updated

Manual labels, automatically updated

Handling duplicate tick labels

Of course, ‘%.1fV’ may not be a good format when we zoom in to such a degree that the values differ by less than 0.1 – in this case all the labels will be the same. So let’s modify our callback function to add extra decimals until the labels become distinct:

function myCallbackFunction(hProp,eventData)    %#ok - hProp is unused
   hAxes = eventData.AffectedObject;
   tickValues = get(hAxes,'YTick');
 
   %newLabels = arrayfun(@(value)(sprintf('%.1fV',value)), tickValues, 'UniformOutput',false);
   digits = 0;
   labelsOverlap = true;
   while labelsOverlap
      % Add another decimal digit to the format until the labels become distinct
      digits = digits + 1;
      format = sprintf('%%.%dfV',digits);
      newLabels = arrayfun(@(value)(sprintf(format,value)), tickValues, 'UniformOutput',false);
      labelsOverlap = (length(newLabels) > length(unique(newLabels)));
 
      % prevent endless loop if the tick values themselves are non-unique
      if labelsOverlap && max(diff(tickValues))< 16*eps
         break;
      end
   end
 
   set(hAxes, 'YTickLabel', newLabels);
end  % myCallbackFunction

non-distinct labels distinct labels

Non-distinct labels                   distinct labels

ticklabelformat

Based on a file that I received from an anonymous reader a few years ago, I have prepared a utility called ticklabelformat that automates much of the set-up above. Feel free to download this utility and modify it for your needs - it's quite simple to read and follow. The usage syntax is as follows:

ticklabelformat(gca,'y','%.6g V')  % sets y axis on current axes to display 6 significant digits
ticklabelformat(gca,'xy','%.2f')   % sets x & y axes on current axes to display 2 decimal digits
ticklabelformat(gca,'z',@myCbFcn)  % sets a function to update the Z tick labels on current axes
ticklabelformat(gca,'z',{@myCbFcn,extraData})  % sets an update function as above, with extra data
Categories: Handle graphics, Listeners, Medium risk of breaking in future versions, Undocumented function
Tags: , , , ,
1 Comment

Specialized Matlab plots

A few weeks ago, MathWorks has added a new section on its website called the “Plot Gallery“. This section highlights specialized Matlab plots that were posted on the Matlab File Exchange (FEX) and can be used by Matlab users in their GUIs. Unfortunately, for the moment this list only includes some 20 customized plots posted by MathWorks employees, in addition to some 50 examples of using the standard Matlab plots. I have a suspicion that one day, if this proves popular, we will find the gallery integrated in the main Matlab Desktop, possibly next to the current plot selector component.

Since the Plot Gallery section is a new effort at reducing plotting complexity to Matlab users, I think that it should be encouraged by user feedback. Please feel free to leave them a comment with your feedback, either on this page, or on their semi-official blog announcement page.

My personal beef with the new Plot Gallery is the fact that it does not currently include user submissions. FEX actually contains numerous user-submitted specialized plotting utilities, answering a wide variety of needs in multiple discipline fields. These can easily be found using FEX’s search functionality or tags. For example, the FEX “plot” tag currently has 440 separate submissions. Perhaps one day these user submissions will be added to the Plot Gallery in some searchable structured manner.

One set of specialized plots that I’d like to highlight today is based on the open-source JFreeChart, that I have described here last year. Sven Körner has used this to provide a dozen different customized Matlab plots, a few of which can be seen below, showing the power of integrating external code in Matlab GUI. JFreeChart contains many more customizable chart, plot and gauge types so Sven’s examples should merely be considered as appetizers:

MATLAB-integrated dial gauge chart

MATLAB-integrated dial gauge chart


MATLAB-integrated multi-axes chart

MATLAB-integrated multi-axes chart


Categories: GUI, Low risk of breaking in future versions
Tags: , ,
5 Comments