Quantcast
Channel: Undocumented Matlab
Viewing all 219 articles
Browse latest View live

Auto-completion widget

$
0
0

Do you ever get a feeling when designing a Matlab GUI, that existing components/controls are simply not enough to achieve the desired functionality/appearance?

Such a case happened to me, when a consulting client asked me to integrate an auto-completion widget in a GUI that I designed for them. The idea was simple enough: the user selects a class of financial assets from a drop-down, then one or more actual financial securities from a dynamically-populated drop-down (based on the asset class), then the date range and analysis function, and finally the results are plotted in the main panel. The idea was for Matlab to automatically auto-complete the financial instruments matching the entered text, as it is being typed, similarly to other standard auto-completion widgets (e.g., Google’s search box), including the use of wildcards and regular expressions:

Interactive Matlab auto-completion widget

Interactive Matlab auto-completion widget

Note that in this particular case, I use the term “auto-completion” loosely. The correct term should actually be “auto-winnowing” or “auto-filtering”. Auto-completion is usually reserved for the case of the user-entered text being automatically completed as they type, whereas auto-winnowing only updates the drop-down options on-the-fly. These two functionalities are often correlated, and today’s article will discuss both.

AutoCompletionList

Before I dive into details of the implementation I ended up with, note that there are simpler alternatives. For example, we can use Matlab’s internal com.mathworks.widgets.AutoCompletionList widget:

strs = {'This','is','test1','test2'};
strList = java.util.ArrayList;
for idx = 1 : length(strs),  strList.add(strs{idx});  end
jPanelObj = com.mathworks.widgets.AutoCompletionList(strList,'');
javacomponent(jPanelObj.getComponent, [10,10,200,100], gcf);

AutoCompletionList widget

AutoCompletionList widget

The AutoCompletionList control is actually a list (rather than a drop-down), where the user types an entry in the header row. The control automatically selects the first corresponding list item and auto-completes the rest of the entry. Invalid user entries generate a beep and are not allowed by default (unless the widget’s Strict property is cleared: jPanelObj.setStrict(false)). The visible list size can be controlled by setting the widget’s VisibleRowCount property (jPanelObj.setVisibleRowCount(6)).

Items can be selected by either typing in the header row, by selecting a list item, or programmatically (jPanelObj.setSelectedValue('test1')). The currently selected item is retrieved via the same SelectedValue property (selectedValue = char(jPanelObj.getSelectedValue)). As with many other actionable Java controls, we can attach a callback on the ActionPerformed event:

set(handle(jPanelObj,'callbackproperties'), 'ActionPerformedCallback', @myMatlabCallbackFunc);

We can attach a similar callback to key-typing within the header row (text field), by accessing the widget’s internal component (which is the one that is actually being displayed via the javacomponent function):

set(handle(jPanelObj.getComponent,'callbackproperties'), 'KeyTypedCallback', @myMatlabCallbackFunc);

SearchTextField

For my client’s purposes, however, AutoCompletionList could not be used. We wanted a drop-down selector that takes up far less space than a listbox. The first thought was to use a modified drop-down (editable combo-box). This turned out to be less effective than hoped, because of the interference between the Matlab KeyTypedCallback function and the automatic behavior of the combo-box. I do not rule out the use of such an editable combo-box in other use-cases, but for this implementation I chose to use a different control, namely Matlab’s internal com.mathworks.widgets.SearchTextField, which has some nice additional features such as an optional light-gray prompt, and a clickable search icon that changes its appearance and behavior based on the entered text:

jPanelObj = com.mathworks.widgets.SearchTextField('Enter search term:');
[jhPanel,hContainer] = javacomponent(jPanelObj.getComponent, [10,10,150,25], gcf);
SearchTextField initial view

SearchTextField initial view

user clicks in entry box (prompt text disappears)

user clicks in entry box (prompt text disappears)

user types something (icon changes, clicking it will clear the text)

user types something
(icon changes, clicking it will clear the text)

An optical illusion

As with a regular combo-box, the dropdown-menu integration in Matlab proved a bit difficult, especially due to the auto-completion feature. Again, I do not rule out using it in other use-cases, but for this implementation I chose to use a visual illusion: an actual combo-box is placed beneath (hidden by) the SearchTextField control. So basically, we are seeing two disparate parts of two separate components: the edit-box of the SearchTextField and the dropdown panel (a JPopupMenu) of the hidden combo-box. They appear attached, providing the optical illusion of being a single widget, when in fact they are not. Neat, right?

Callback events are used to synchronize the components, update the combo-box’s dropdown options and display the dropdown panel. We attach the same callback function to 3 separate events: MouseClickedCallback on the search button (icon), KeyPressedCallback on the search text-box, and another KeyPressedCallback on the combo-box’s text-box (which is not visible, but automatically receives focus when the user interacts with the popup menu (drop-down panel):

% Create the SearchTextField component (after the hidden combo was created)
jAssetChooser = com.mathworks.widgets.SearchTextField('Enter search:');
jAssetComponent = jAssetChooser.getComponent;
[jhAssetComponent, hContainer] = javacomponent(jAssetComponent,[],hPanel);
 
% Set callbacks
hjSearchButton = handle(jAssetComponent.getComponent(1), 'CallbackProperties');
set(hjSearchButton, 'MouseClickedCallback', {@updateSearch,jCombo,jAssetChooser});
 
hjSearchField = handle(jAssetComponent.getComponent(0), 'CallbackProperties');
set(hjSearchField, 'KeyPressedCallback', {@updateSearch,jCombo,jAssetChooser});
 
jComboField = handle(jCombo.getComponent(2), 'CallbackProperties');
set(jComboField, 'KeyPressedCallback', {@updateSearch,jCombo,[]});

The user can now select an item either from the combo-box’s dropdown panel, or by typing in the search text-box. Here is the implementation of the updateSearch() callback function:

% Asset search popup combo button click callback
function updateSearch(hObject, eventData, jCombo, jAssetChooser) %#ok<INUSL>
    persistent lastSearchText
    if isempty(lastSearchText),  lastSearchText = '';  end
 
    try
        % event occurred on the search field component
        try
            searchText = jAssetChooser.getSearchText;
            jSearchTextField = jAssetChooser.getComponent.getComponent(0);
        catch
            % Came via asset change - always update
            jSearchTextField = jAssetChooser.getComponent(0);
            searchText = jSearchTextField.getText;
            lastSearchText = '!@#$';
        end
    catch
        try
            % event occurred on the jCombo-box itself
            searchText = jCombo.getSelectedItem;
        catch
            % event occurred on the internal edit-field sub-component
            searchText = jCombo.getText;
            jCombo = jCombo.getParent;
        end
        jSearchTextField = jCombo.getComponent(jCombo.getComponentCount-1);
    end
    searchText = strrep(char(searchText), '*', '.*');  % turn into a valid regexp
    searchText = regexprep(searchText, '<[^>]+>', '');
    if strcmpi(searchText, lastSearchText) && ~isempty(searchText)
        jCombo.showPopup;
        return;  % maybe just clicked an arrow key or Home/End - no need to refresh the popup panel
    end
    lastSearchText = searchText;
 
    assetClassIdx = getappdata(handles.cbAssetClass, 'assetClassIdx');
    if isempty(assetClassIdx)
        jCombo.hidePopup;
        return;
    elseif isempty(searchText)
        assetNamesIdx = assetClassIdx;
    else
        searchComponents = strsplit(searchText, ' - ');
        assetCodeIdx = ~cellfun('isempty',regexpi(data.header.AssetCode(assetClassIdx),searchComponents{1}));
        assetNameIdx = ~cellfun('isempty',regexpi(data.header.AssetName(assetClassIdx),searchComponents{end}));
        if numel(searchComponents) > 1
            assetNamesIdx = assetClassIdx(assetCodeIdx & assetNameIdx);
        else
            assetNamesIdx = assetClassIdx(assetCodeIdx | assetNameIdx);
        end
    end
    setappdata(handles.cbAssetSearch, 'assetNameIdx', assetNamesIdx);
    if isempty(assetNamesIdx)
        jCombo.hidePopup;
        jSearchTextField.setBackground(java.awt.Color.yellow);
        jSearchTextField.setForeground(java.awt.Color.red);
        newFont = jSearchTextField.getFont.deriveFont(uint8(java.awt.Font.BOLD));
        jSearchTextField.setFont(newFont);
        return;
    else
        jSearchTextField.setBackground(java.awt.Color.white);
        jSearchTextField.setForeground(java.awt.Color.black);
        newFont = jSearchTextField.getFont.deriveFont(uint8(java.awt.Font.PLAIN));
        jSearchTextField.setFont(newFont);
    end
 
    % Compute the filtered asset names (highlight the selected search term)
    assetNames = strcat(data.header.AssetCode(assetNamesIdx), ' -=', data.header.AssetName(assetNamesIdx));
    assetNames = regexprep(assetNames, '(.+) -=\1', '$1', 'ignorecase');
    assetNames = unique(strrep(assetNames, ' -=', ' - '));
    if ~isempty(searchText)
        assetNames = regexprep(assetNames, ['(' searchText ')'], '<b><font color=blue>$1</font></b>', 'ignorecase');
        assetNames = strcat('<html>', assetNames);
    end
 
    % Redisplay the updated combo-box popup panel
    jCombo.setModel(javax.swing.DefaultComboBoxModel(assetNames));
    jCombo.showPopup;
end  % updateSearch

Here is the final result:

Matlab GUI with integrated auto-completion & date selection widgets

Matlab GUI with integrated auto-completion & date selection widgets


Would you believe that this entire program is only 400 lines of code?!

Conclusion

I’ve heard it say on occasion that Matlab GUI is not really suited for professional applications. I completely disagree, and hope that today’s article proves otherwise. You can make Matlab GUI do wonders, in various different ways. Matlab does have limitations, but they are nowhere close to what many people believe. If you complain that your GUI sucks, then it is likely not because of Matlab’s lack of abilities, but because you are only using a very limited portion of them. This is no different than any other programming environment (admittedly, such features are much better documented in other environments).

In short, to improve your GUI’s functionality and appearance, you just need to spend a bit of time searching for the right components (possibly using my book), or hire a professional consultant to do it for you. But of course, just bitching about Matlab’s supposed limitations is much easier…

Do you have a GUI that you find hard to believe can be done (or improved) in Matlab? Contact me for a consulting proposal and let me surprise you!

 
Related posts:
  1. Class object tab completion & improper field names Tab completions and property access can be customized for user-created Matlab classes. ...
  2. Plot-type selection components Several built-in components enable programmatic plot-type selection in Matlab GUI - this article explains how...
  3. Animated busy (spinning) icon An animated spinning icon label can easily be embedded in Matlab GUI. ...
  4. FindJObj GUI – display container hierarchy The FindJObj utility can be used to present a GUI that displays a Matlab container's internal Java components, properties and callbacks....
 

General-use object copy

$
0
0

When using Matlab objects, either a Matlab class (MCOS) or any other (e.g., Java, COM, C# etc.), it is often useful to create a copy of the original object, complete with all internal property values. This enables modification of the new copy without affecting the original object. This is not important for MCOS value-class objects, since value objects use the COW (Copy-on-Write/Update, a.k.a. Lazy Copy) and this is handled automatically by the Matlab interpreter when it detects that a change is made to the copy reference. However, it is very important for handle objects, where modifying any property of the copied object also modifies the original object.

Most OOP languages include some sort of a copy constructor, which enables programmers to duplicate a handle/reference object, internal properties included, such that it becomes entirely separate from the original object. Unfortunately, Matlab did not include such a copy constructor until R2011a (matlab.mixin.Copyable.copy()).

On Matlab R2010b and older, as well as on newer releases, we do not have a readily-available solution for handle object copy. Until now, that is.

There are several ways by which we can create such a copy function. We might call the main constructor to create a default object and then override its properties by iterating over the original object’s properties. This might work in some cases, but not if there is no default constructor for the object, or if there are side-effects to object property modifications. If we wanted to implement a deep (rather than shallow) copy, we’d need to recursively iterate over all the properties of the internal objects as well.

A simpler solution might be to save the object to a temporary file (tempname, then load from that file (which creates a copy), and finally delete the temp file. This is nice and clean, but the extra I/O could be relatively slow compared to in-memory processing.

Which leads us to today’s chosen solution, where we use Matlab’s builtin functions getByteStreamFromArray and getArrayFromByteStream, which I discussed last year as a way to easily serialize and deserialize Matlab data of any type. Specifically, getArrayFromByteStream has the side-effect of creating a duplicate of the serialized data, which is perfect for our needs here (note that these pair of function are only available on R2010b or newer; on R2010a or older we can still serialize via a temp file):

% Copy function - replacement for matlab.mixin.Copyable.copy() to create object copies
function newObj = copy(obj)
    try
        % R2010b or newer - directly in memory (faster)
        objByteArray = getByteStreamFromArray(obj);
        newObj = getArrayFromByteStream(objByteArray);
    catch
        % R2010a or earlier - serialize via temp file (slower)
        fname = [tempname '.mat'];
        save(fname, 'obj');
        newObj = load(fname);
        newObj = newObj.obj;
        delete(fname);
    end
end

This function can be placed anywhere on the Matlab path and will work on all recent Matlab releases (including R2010b and older), any type of Matlab data (including value or handle objects, UDD objects, structs, arrays etc.), as well as external objects (Java, C#, COM). In short, it works on anything that can be assigned to a Matlab variable:

obj1 = ... % anything really!
 
obj2 = obj1.copy();  % alternative #1
obj2 = copy(obj2);   % alternative #2

Alternative #1 may look “nicer” to a computer scientist, but alternative #2 is preferable because it also handles the case of non-object data (e.g., [] or ‘abc’ or magic(5) or a struct or cell array), whereas alternative #1 would error in such cases.

In any case, using either alternatives, we no longer need to worry about inheriting our MCOS class from matlab.mixin.Copyable, or backward compatibility with R2010b and older (I may possibly be bashed for this statement, but in my eyes future compatibility is less important than backward compatibility). This is not such a wild edge-case. In fact, I came across the idea for this post last week, when I developed an MCOS project for a consulting client that uses both R2010a and R2012a, and the same code needed to run on both Matlab releases.

Using the serialization functions also solves the case of creating copies for Java/C#/COM objects, which currently have no other solution, except if these objects happen to contain their own copy method.

In summary, using Matlab’s undocumented builtin serialization functions enables easy implementation of a very efficient (in-memory) copy constructor, which is expected to work across all Matlab types and many releases, without requiring any changes to existing code – just placing the above copy function on the Matlab path. This is expected to continue working properly until Matlab decides to remove the serialization functions (which should hopefully never happen, as they are so useful).

Sometimes, the best solutions lie not in sophisticated new features (e.g., matlab.mixin.Copyable), but by using plain ol’ existing building blocks. There’s a good lesson to be learned here I think.

p.s. – I do realize that matlab.mixin.Copyable provides the nice feature of enabling users to control the copy process, including implementing deep or shallow or selective copy. If that’s your need and you have R2011a or newer then good for you, go ahead and inherit Copyable. Today’s post was meant for the regular Joe who doesn’t need this fancy feature, but does need to support R2010b, and/or a simple way to clone Java/C#/COM objects.

 
Related posts:
  1. Undocumented cursorbar object Matlab's internal undocumented graphics.cursorbar object can be used to present dynamic data-tip cross-hairs...
  2. Accessing private object properties Private properties of Matlab class objects can be accessed (read and write) using some undocumented techniques. ...
  3. Class object tab completion & improper field names Tab completions and property access can be customized for user-created Matlab classes. ...
  4. Class object creation performance Performance aspects of Matlab class object creation are discussed, with specific suggestions. ...
 

copyobj behavior change in HG2

$
0
0

As a followup to last-week’s post on class-object and generic data copies, I would like to welcome back guest blogger Robert Cumming, who developed a commercial Matlab GUI framework. Today, Robert will highlight a behavior change of Matlab’s copyobj function in HG2.

One of the latest features that was introduced to the GUI Toolbox was the ability to undock or copy panels, that would be displayed in a standalone figure window, but remain connected to the underlying class object:

Panel copy in the GUI framework toolbox

Panel copy in the GUI framework toolbox

These panel copies had to remain fully functional, including all children and callbacks, and they needed to retain all connections back to the source data. In the example above I have altered the plot to show that it’s an actual copy of the data, but has separate behavior from the original panel.

To simply undock a uipanel to a new figure, we can simply re parent it by updating its Parent property to the new figure handle. To make a copy we need to utilize the copyobj function, rather than re-parenting. copyobj can be used to make a copy of all graphic objects that are “grouped” under a common parent, placing their copy in a new parent. In HG2 (R2014b onwards) the default operation of copyobj has changed.

When I started developing this feature everything looked okay and all the objects appeared copied. However, none of the callbacks were functinoal and all the information stored in the object’s ApplicationData was missing.

I had used copyobj in the past, so I knew that it originally worked ok, so I investigated what was happening. Matlab’s documentation for HG2 code transition suggests re-running the original code to create the second object to populate the callbacks. Unfortunately, this may not be suitable in all cases. Certainly in this case it would be much harder to do, than if the original callbacks had been copied directly. Another suggestion is to use the new ‘lagacy’ option’:

copyobj(___,’legacy’) copies object callback properties and object application data. This behavior is consistent with versions of copyobj before MATLAB® release R2014b.

So, instead of re-running the original code to create the second object to populate the callbacks, we can simply use the new ‘legacy’ option to copy all the callbacks and ApplicationData:

copyobj(hPanel, hNewParent, 'legacy')

Note: for some reason, this new ‘legacy’ option is mentioned in both the doc page and the above-mentioned HG2 code-transition page, but not in the often used help section (help copyobj). There is also no link to the relevant HG2 code-transition page in either the help section or the doc page. I find it unfortunate that for such a backward-incompatible behavior change, MathWorks has not seen fit to document the information more prominently.

Other things to note (this is probably not an exhaustive list…) when you are using copyobj:

  • Any event listeners won’t be copied
  • Any uicontextmenus will not be copied – it will in fact behave strangely due to the fact that it will have the uicontextmenu – but the parent is the original figure – and when you right-click on the object it will change the figure focus. For example:
    hFig= figure;
    ax = axes;
    uic = uicontextmenu ('parent', hFig);
    uim = uimenu('label','My Label', 'parent',uic);
    ax.UIContextMenu = uic;
     
    copyChildren = copyobj (ax, hFig, 'legacy');
     
    hFig2 = figure;
    copyChildren.Parent = hFig2;

Another note on undocked copies – you will need to manage your callbacks appropriately so that the callbacks manage whether they are being run by the original figure or in a new undocked figure.

Conclusions

  1. copyobj has changed in HG2 – but the “legacy” switch allows you to use it as before.
  2. It is unfortunate that backward compatibility was not fully preserved (nor documented enough) in HG2, but at least we have an escape hatch in this case.
  3. Take care with the legacy option as you may need to alter uicontextmenus and attached listeners as required to any objects.

 
Related posts:
  1. Property value change listeners HG handle property changes can be trapped in a user-defined callback. ...
  2. Handle Graphics Behavior HG behaviors are an important aspect of Matlab graphics that enable custom control of handle functionality. ...
  3. Undocumented scatter plot behavior The scatter plot function has an undocumented behavior when plotting more than 100 points: it returns a single unified patch object handle, rather than a patch handle for each specific...
  4. xlsread functionality change in R2012a The functionality of the xlsread function has changed without documentation or warning in the R2012a release. ...
 

Undocumented HG2 graphics events

$
0
0

R2014b brought a refreshing new graphics engine and appearance, internally called HG2 (the official marketing name is long and impossible to remember, and certainly not as catchy). I’ve already posted a series of articles about HG2. Today I wish to discuss an undocumented aspect of HG2 that I’ve encountered several times over the past months, and most recently today. The problem is that while in the previous HG1 system (R2014a and earlier) we could add property-change listener callbacks to practically any graphics object, this is no longer true for HG2. Many graphics properties, that are calculated on-the-fly based on other property values, cannot be listened-to, and so we cannot attach callbacks that trigger when their values change.

Property-change listeners in HG1

Take for example my post about setting axes tick labels format from 3 years ago: the idea there was to attach a Matlab callback function to the PropertyPostSet event of the XTick, YTick and/or ZTick properties, so that when they change their values (upon zoom/pan/resize), the corresponding tick-labels would be reformatted based on the user-specified format:

Formatted labels, automatically updated Formatted labels, automatically updated

Formatted labels, automatically updated


A simple HG1 usage might look as follows:

addlistener(handle(hAxes), 'YTick', 'PostSet', @reformatTickLabels);
 
function reformatTickLabels(hProperty, eventData)
    try
        hAxes = eventData.AffectedObject;
    catch
        hAxes = ancestor(eventData.Source,'Axes');
    end
    tickValues = get(hAxes, 'YTick');
    tickLabels = arrayfun(@(x)(sprintf('%.1fV',x)), tickValues, 'UniformOutput',false);
    set(hAxes, 'YTickLabel', tickLabels)
end

I prepared a utility called ticklabelformat that automates much of the set-up above. Feel free to download this utility from the Matlab File Exchange. Its 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

Property-change listeners in HG2

Unfortunately, this fails in HG2 when trying to listen to automatically-recalculated (non-Observable) properties such as the Position or axes Tick properties. We can only listen to non-calculated (Observable) properties such as Tag or YLim. Readers might think that this answers the need, since the ticks change when the axes limits change. This is true, but does not cover all cases. For example, when we resize/maximize the figure, Matlab may decide to modify the displayed ticks, although the axes limits remain unchanged.

So we need to have a way to monitor changes even in auto-calculated properties. Luckily this can be done by listening to a set of new undocumented HG2 events. It turns out that HG2′s axes (matlab.graphics.axis.Axes objects) have no less than 17 declared events, and 14 of them are hidden in R2015a:

>> events(gca)   % list the non-hidden axes events
Events for class matlab.graphics.axis.Axes:
    ObjectBeingDestroyed
    PropertyAdded
    PropertyRemoved
 
>> mc = metaclass(gca)
mc = 
  GraphicsMetaClass with properties:
                     Name: 'matlab.graphics.axis.Axes'
              Description: 'TODO: Fill in Description'
      DetailedDescription: ''
                   Hidden: 0
                   Sealed: 1
                 Abstract: 0
              Enumeration: 0
          ConstructOnLoad: 1
         HandleCompatible: 1
          InferiorClasses: {0x1 cell}
        ContainingPackage: [1x1 meta.package]
             PropertyList: [414x1 meta.property]
               MethodList: [79x1 meta.method]
                EventList: [17x1 meta.event]    EnumerationMemberList: [0x1 meta.EnumeratedValue]
           SuperclassList: [7x1 meta.class]
 
>> mc.EventList(10)
ans = 
  event with properties:
                   Name: 'MarkedClean'
            Description: 'description'
    DetailedDescription: 'detailed description'
                 Hidden: 1
           NotifyAccess: 'public'
           ListenAccess: 'public'
          DefiningClass: [1x1 matlab.graphics.internal.GraphicsMetaClass]
 
>> [{mc.EventList.Name}; ...
    {mc.EventList.ListenAccess}; ...
    arrayfun(@mat2str, [mc.EventList.Hidden], 'Uniform',false)]'
ans = 
    'LocationChanged'             'public'       'true' 
    'SizeChanged'                 'public'       'true' 
    'ClaReset'                    'public'       'true' 
    'ClaPreReset'                 'public'       'true' 
    'Cla'                         'public'       'true' 
    'ObjectBeingDestroyed'        'public'       'false'  % not hidden
    'Hit'                         'public'       'true' 
    'LegendableObjectsUpdated'    'public'       'true' 
    'MarkedDirty'                 'public'       'true' 
    'MarkedClean'                 'public'       'true' 
    'PreUpdate'                   'protected'    'true' 
    'PostUpdate'                  'protected'    'true' 
    'Error'                       'public'       'true' 
    'Reparent'                    'public'       'true' 
    'Reset'                       'public'       'true' 
    'PropertyAdded'               'public'       'false'  % not hidden
    'PropertyRemoved'             'public'       'false'  % not hidden

Similar hidden events exist for all HG2 graphics objects. The MarkedDirty and MarkedClean events are available for practically all graphic objects. We can listen to them (luckily, their ListenAccess meta-property is defined as ‘public’) to get a notification whenever the corresponding object (axes, or any other graphics component such as a plot-line or axes ruler etc.) is being redrawn. We can then refresh our own properties. It makes sense to attach such callbacks to MarkedClean rather than MarkedDirty, because the property values are naturally stabled and reliable only after MarkedClean. In some specific cases, we might wish to listen to one of the other events, which luckily have meaningful names.

For example, in my ticklabelformat utility I’ve implemented the following code (simplified here for readability – download the utility to see the actual code), which listens to the MarkedClean event on the axes’ YRuler property:

try
    % HG1 (R2014a or older)
    hAx = handle(hAxes);
    hProp = findprop(hAx, 'YTick');
    hListener = handle.listener(hAx, hProp, 'PropertyPostSet', @reformatTickLabels);
    setappdata(hAxes, 'YTickListener', hListener);  % must be persisted in order to remain in effect
catch
    % HG2 (R2014b or newer)
    addlistener(hAx, 'YTick', 'PostSet', @reformatTickLabels);
 
    % *Tick properties don't trigger PostSet events when updated automatically in R2014b
    %addlistener(hAx, 'YLim', 'PostSet', @reformatTickLabels);  % this solution does not cover all use-cases
    addlistener(hAx.YRuler, 'MarkedClean', @reformatTickLabels);
end
 
% Adjust tick labels now
reformatTickLabels(hAxes);

In some cases, the triggered event might pass some useful information in the eventData object that is passed to the callback function as the second input parameter. This data may be different for different events, and is also highly susceptible to changes across Matlab releases, so use with care. I believe that the event names themselves (MarkedClean etc.) are less susceptible to change across Matlab releases, but they might.

Performance aspects

The MarkedClean event is triggered numerous times, from obvious triggers such as calling drawnow to less-obvious triggers such as resizing the figure or modifying a plot-line’s properties. We therefore need to be very careful that our callback function is (1) non-reentrant, (2) is not active too often (e.g., more than 5 times per sec), (3) does not modify properties unnecessarily, and in general (4) executes as fast as possible. For example:

function reformatTickLabels(hProperty, eventData)
    persistent inCallback
    if ~isempty(inCallback),  return;  end
    inCallback = 1;  % disable callback re-entrancy
 
    % Update labels only every 0.2 secs or more
    persistent lastTime
    try
        tnow = datenummx(clock);  % fast
    catch
        tnow = now;  % slower
    end
    ONE_SEC = 1/24/60/60;
    if ~isempty(lastTime) && tnow - lastTime < 0.2*ONE_SEC
        inCallback = [];  % re-enable callback
        return;
    end
    lastTime = tnow;
 
    % This is the main callback logic
    try
        hAxes = eventData.AffectedObject;
    catch
        hAxes = ancestor(eventData.Source,'Axes');
    end
    prevTickValues = getappdata(hAxes, 'YTick');
    tickValues = get(hAxes, 'YTick');
    if ~isequal(prevTickValues, tickValues)
        tickLabels = arrayfun(@(x)(sprintf('%.1fV',x)), tickValues, 'UniformOutput',false);
        set(hAxes, 'YTickLabel', tickLabels)
    end
 
    inCallback = [];  % re-enable callback
end

Unfortunately, it seems that retrieving some property values (such as the axes’s YTick values) may by itself trigger the MarkedClean event for some reason that eludes my understanding (why should merely getting the existing values modify the graphics in any way?). Adding callback re-entrancy checks as above might alleviate the pain of such recursive callback invocations.

A related performance aspect is that it could be better to listen to a sub-component’s MarkedClean than to the parent axes’ MarkedClean, which might be triggered more often, for changes that are entirely unrelated to the sub-component that we wish to monitor. For example, if we only monitor YRuler, then it makes no sense to listen to the parent axes’ MarkedClean event that might trigger due to a change in the XRuler.

In some cases, it may be better to listen to specific events rather than the all-encompassing MarkedClean. For example, if we are only concerned about changes to the Position property, we should listen to the LocationChanged and/or SizeChanged events (more details).

Additional graphics-related performance tips can be found in my Accelerating MATLAB Performance book.

Have you used MarkedClean or some other undocumented HG2 event in your code for some nice effect? If so, please share your experience in a comment below.

 
Related posts:
  1. Matlab callbacks for Java events Events raised in Java code can be caught and handled in Matlab callback functions - this article explains how...
  2. Handle Graphics Behavior HG behaviors are an important aspect of Matlab graphics that enable custom control of handle functionality. ...
  3. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
  4. Waiting for asynchronous events The Matlab waitfor function can be used to wait for asynchronous Java/ActiveX events, as well as with timeouts. ...
 

Persisting transparent colors in HG2

$
0
0

Several months ago, I showed how we can set semi- and fully-transparent colors in HG2 (Matlab’s new graphics engine, starting in R2014b) for multiple graphic objects, including plot lines, plot markers, and area charts:

hLine = plot([0,150], [-0.5,0.5], 'r');
box off; hold on;
ydata = sin(0:0.1:15);
hArea = area(ydata);
drawnow; pause(0.05);  % this is important!
hArea.Face.ColorType = 'truecoloralpha';
hArea.Face.ColorData(4) = 40;  % 40/255 = 0.16 opacity = 84% transparent

Unfortunately, these settings are automatically overridden by Matlab when the figure is printed, saved, or exported:

% These commands result in an opaque (non-transparent) plot
print(gcf);
saveas(gcf, 'plot.png');

Transparent area plot (ok)   Opaque area plot (not ok)

Area plot: transparent (ok) and opaque (not ok)


In some cases, the settings are lost even when the figure or axes is resized, or properties (e.g., Box) are changed. This is evident, for example, when the hLine plot line is not drawn, only the area plot.

The solution of one blog reader here was to simply set the undocumented color transparency settings at the very end of the graphics set-up. However, as noted, this still does not answer the need to preserve the color settings when the figure is printed, saved, exported, or resized, or when axes properties change.

Another reader, Richard de Garis of Collins Capital, found an undocumented feature that seems to solve the problem for good. It turns out that the solution is simply to set the color to a “legal” (documented, non-transparent) color before setting the transparency values:

hArea = area(ydata);
hArea.FaceColor = 'b';  % or any other non-transparent colordrawnow; pause(0.05);  % this is important!
hArea.Face.ColorType = 'truecoloralpha';
hArea.Face.ColorData(4) = 40;  % 40/255 = 0.16 opacity = 84% transparent

Now the transparency settings are preserved, even when the figure is printed, saved, exported, resized etc.

The obvious explanation is that by manually updating the graphic object’s FaceColor, Matlab automatically updates the hidden property FaceColorMode from ‘auto’ to ‘manual’. This signals the graphics engine not to override the Face‘s color when such an update would otherwise be called for. The mechanism of having a <PropName>Mode property associated with the <PropName> was used in HG1 (Matlab’s previous Matlab graphics engine, up to R2014a). In HG2, more properties have added such associated *Mode properties. In most cases, these additional *Mode properties are hidden, as FaceColorMode is. I find this justified, because in most cases users shouldn’t update these properties, and should let Matlab handle the logic.

Unfortunately, this explanation is apparently false, as evident by the fact that setting FaceColorMode from ‘auto’ to ‘manual’ does not have the same desired effect. So for now I don’t know how to explain this phenomenon. At least we know it works, even if we don’t fully understand why [yet]. Oh well, I guess we can’t win ‘em all…

Have you discovered and used some other interesting undocumented feature of HG2? If so, please share it in a comment below, or email me the details.

 
Related posts:
  1. Transparent legend Matlab chart legends are opaque be default but can be made semi- or fully transparent. ...
  2. Transparent uipanels Matlab uipanels can be made transparent, for very useful effects. ...
  3. Transparent Matlab figure window Matlab figure windows can be made fully or partially transparent/translucent or blurred - this article explains how...
  4. Changing Matlab’s Command Window colors – part 2 The Matlab Command Window enables a limited degree of inline color customization - this post describes how to use it...
 

Sliders in Matlab GUI

$
0
0

One of my consulting clients asked me last week if I knew an easy way to integrate a range (dual-knob) slider control in Matlab GUI. Today’s post is an expansion of the answer I provided him, which I though might interest other Matlab users.

Matlab vs. Java sliders

As funny as it may sound, Matlab’s so-called “slider” control (uicontrol('Style','slider')) is actually implemented as a scroll-bar, rather than the more natural JSlider. I believe that this is due to a design decision that occurred sometime in the 1990′s (sliders were not as prevalent then as they are nowadays). This was never corrected, probably for backward-compatibility reasons. So to this day, Matlab’s so-called “slider” is actually a scroll-bar, and we do not [yet] have a real slider control in standard Matlab, apparently since the ‘slider’ uicontrol style is already in use. Spoiler alert: this will change soon — keep reading.

It gets worse: for some reason Matlab’s implementation of the so-called “slider” uses a Windows95 look-and-feel that makes the control look antique in today’s GUI standards. Using Java Swing’s standard JScrollBar control would at least have made it appear more consistent with the other Matlab controls, which are all based more closely on Java Swing:

Matlab "slider" uicontrol (bottom), Java JScrollBar (above), and JSlider (top 2)

Matlab "slider" uicontrol (bottom),
Java JScrollBar (above),
and JSlider (top 2)

% Standard Matlab "slider"
uicontrol('style','slider', 'position',[10,10,200,20]);
 
% Standard Java JScrollBar
jScrollbar = javax.swing.JScrollBar;
jScrollbar.setOrientation(jScrollbar.HORIZONTAL);
javacomponent(jScrollbar,[10,40,200,20]);
 
% Standard Java JSlider (20px high if no ticks/labels, otherwise use 45px)
jSlider = javax.swing.JSlider;
javacomponent(jSlider,[10,70,200,45]);

I advise users of the current Matlab GUI to use JScrollBar or JSlider, rather than Matlab’s standard “slider” uicontrol. The rest of today’s post will discuss the JSlider variant.

Using JSlider

As shown above, we can use the javacomponent function to display any Java component in a Matlab container (such as uipanel or figure). We can easily modify the slider’s appearance using its internal properties:

set(jSlider, 'Value',84, 'MajorTickSpacing',20, 'PaintLabels',true);  % with labels, no ticks

JSlider customization
set(jSlider, 'Value',22, 'PaintLabels',false, 'PaintTicks',true);  % with ticks, no labels

JSlider customization
jSlider.setPaintLabels(true);  % or: jSlider.setPaintLabels(1);  % with both ticks and labels

JSlider customization
[jhSlider, hContainer] = javacomponent(jSlider,[10,10,100,40]);
set(jSlider, 'Value',72, 'Orientation',jSlider.VERTICAL, 'MinorTickSpacing',5);
set(hContainer,'position',[10,10,40,100]); %note container size change

JSlider customization

We can query the current slider value via its Value property:

>> value = get(jSlider,'Value');  % or: value = jSlider.getValue;
value =
    29

We can easily attach Matlab callback functions to slider value-change events:

>> hjSlider = handle(jSlider, 'CallbackProperties')
hjSlider =
	javahandle_withcallbacks.javax.swing.JSlider
 
>> hjSlider.StateChangedCallback = @(hjSlider,eventData) disp(get(hjSlider,'Value'));
>> set(hjSlider, 'StateChangedCallback', @myCallback);  %alternative

As you can see, standard Java controls (such as JSlider here) are very simple to customize and use in Matlab GUI. I have shown more complex customizations elsewhere in this blog, as well as in my Matlab-Java programming book.

Range (dual-knob) sliders

This brings me to my client’s query that I mentioned at the beginning of this post: JSlider only contains a single knob. Is it possible to integrate a range (dual-knob) slider?

My initial response was to simply google for “Java range slider“. This returns numerous different controls, both open-source and commercial, that we can download and integrate in Matlab. All it takes is to download the *.class, *.zip or *.jar file that contains the component, add it to Matlab Java classpath using the javaaddpath function, and then use the javacomponent to display it, just as we did with JSlider above.

This is simple enough, but then I thought of an even simpler solution, namely to use JIDE’s library of commercial-grade controls that is pre-bundled in Matlab. Surely enough, a quick search in JIDE’s enormous catalog yielded its RangeSlider component, which extends JSlider with a dual knob. RangeSlider‘s appearance has changed somewhat across Matlab releases (or actually, JIDE releases, as they are integrated within the corresponding Matlab releases), but its basic functionality remained unchanged:

jRangeSlider = com.jidesoft.swing.RangeSlider(0,100,20,70);  % min,max,low,high
jRangeSlider = javacomponent(jRangeSlider, [0,0,200,80], gcf);
set(jRangeSlider, 'MajorTickSpacing',25, 'MinorTickSpacing',5, 'PaintTicks',true, 'PaintLabels',true, ...
    'Background',java.awt.Color.white, 'StateChangedCallback',@myCallbackFunc);

RangeSlider in R2010b   RangeSlider in R2014b

RangeSlider in R2010b (left), R2014b (right)

We can move the two knobs relative to each other. We can also move the entire range (i.e., both knobs at once), by either dragging the square on top of the right knob (R2010b), or by dragging the space between the two knobs (R2014b).

The benefit of JIDE controls is that they are pre-bundled in every Matlab installation and deployed MCR. There is no need to download anything, nor to use javaaddpath. All the richness of JIDE’s commercial-grade libraries (at least those libraries used in Matlab, which is plenty) is automatically available to us within Matlab, just as easily as the standard Java Swing controls. MathWorks has already paid a small fortune to integrate JIDE’s libraries in Matlab, and we can use it free of charge within Matlab GUIs. This is a great (and sadly undocumented) advantage of Matlab GUI. Matlab GUI programmers who wish to enrich their GUI are strongly encourages to take the time to review the long list of controls provide by JIDE in Matlab. I’ve posted quite a few articles on using JIDE components in Matlab – feel free to take a look and see the richness that JIDE can bring to your GUI. Additional material can be found in my Matlab-Java programming book.

In the specific case of RangeSlider, this control is part of the JIDE Common Layer that JideSoft open-sourced a few years ago. This means that we can download the latest version of this library and use it in Matlab, in case it has some new component that is still not available in our version of Matlab. For example, Matlab R2014b includes JIDE version 3.4.1, released by JideSoft on May 2012 – the latest version (3.6.9, released last week) includes numerous fixes and improvements that were integrated in the past 3 years:

>> com.jidesoft.utils.Lm.getProductVersion
ans =
3.4.1

Note that JIDE’s online documentation (PDF, javadoc, webpage) always refers to the latest version. To use the latest Common-layer library in Matlab, simply download it and replace Matlab’s pre-bundled <matlabroot>/java/jarext/jide/jide-common.jar file. Be careful with changing Matlab’s installation files (such as this one), as there is always a risk that some Matlab functionality might break. So always keep a copy of the original file, in case you need to revert your changes. Alternatively, place the jide-common.jar file in some other user folder and use it in Matlab on an as-needed basis using javaaddpath and javarmpath.

Using the latest commercial (non-open-sourced) JIDE libraries, such as jide-grids.jar, jide-components.jar or jide-charts.jar, is only possible if you purchase them from JideSoft. But as noted, we can freely use the older bundled libraries in our Matlab GUIs without paying JideSoft anything.

Disclaimer: I am an engineer, not a lawyer. What I said above is my personal opinion; it is not legal advice. If you are unsure about licensing of JIDE components in your programs, contact MathWorks or JideSoft.

AppDesigner – Matlab’s new GUI

Last autumn, with little fanfare, MathWorks released the App Designer toolbox, which can be freely downloaded from the File Exchange. This is not just another File Exchange utility. It is in fact an official MathWorks Technical Preview that is both functional by itself, and also provides very interesting insight of Matlab’s upcoming new GUI. MathWorks have not announced exactly when this new AppDesigner will replace the aging GUIDE in Matlab. But the fact that AppDesigner is an actual working product in the public domain since late 2014, and that MathWorks has officially endorsed it as a “Technical Preview”, mean that this day is close.

In the new AppDesigner, sliders finally appear modern, complete with all sorts of customizable properties:

Sliders in Matlab's new AppDesigner

Sliders in Matlab's new AppDesigner

Java controls still provide more customizability than Matlab, even in the new AppDesigner, but the functionality gap is now significantly reduced. This provides the flexibility of modern easy-to-create/maintain GUIs for users who do not need to preserve backward-compatibility with existing GUIs or extra customizabilty enabled by Java, while preserving the functionality for those who do.

Java components and even standard Matlab uicontrols cannot be added to an AppDesigner window because it is not a standard Java JFrame window. The new App window has its own set of controls, separate from uicontrols (topic for a separate blog post someday). However, we can always keep using javacomponent and uicontrol in plain-ol’ figures, as before, side-by-side with the new AppDesigned windows. The new App window can be created using the new appwindow function, whereas the existing figure function creates a standard figure window (basically a Java JFrame) that accepts javacomponent and uicontrol. Maybe one day I’ll find out if there’s a way to combine these two seemingly disparate sets of GUIs. In the meantime I’m content that there’s a new way to create Matlab GUIs that has not previously existed.

AppDesigner is a very nice addition for Matlab GUI builders, and it will get even better with time. Having looked at some of the internals, I’m drooling over the potential improvements. MathWorks has invested quite a bit in this new product, so I’m confident that many of these improvements will find their way into AppDesigner in the upcoming releases. I just hope it will remain a free utility and will not turn into an addon toolbox when officially released (I have not seen any mention about this either way, so it’s still an open question; I’ll clarify this point here when I learn something). For the time being, AppDesigner is free to use.

MathWorks is actively looking for ways to improve AppDesigner, so if you find any functionality that is missing or buggy, please provide feedback:

Feedback for Matlab's new AppDesigner

Feedback for Matlab's new AppDesigner

Conclusions and some personal musings

Matlab itself has kept its Desktop GUI relatively modern, and integrates advanced JIDE GUI controls internally. But until AppDesigner came about, Matlab application builders were not provided with similarly modern documented GUI components and design tools, in keeping with the times.

It is indeed possible, as I’ve repeatedly claimed in this blog, to create professional-looking GUIs in Matlab. However, this currently requires using undocumented features and Java controls.

In Matlab’s upcoming AppDesigner, making professional-looking Matlab GUIs will be easier, with sleek new controls, user-friendly visual layout, and easy-to-maintain class-based code. I still find the tech-preview to be lacking in some respects, and not integrated with the existing GUI functionality. Still, the fact that MathWorks has gone out of its way to provide a Technical Preview of its upcoming new GUI, despite its normal reluctance to provide a technical development roadmap, shows a commitment to improving Matlab’s user-facing front-end. This makes me optimistic that most shortcomings will be solved by the time AppDesigner is officially released, hopefully soon.

Until this happens, and possibly even later, we can significantly improve Matlab’s standard GUI using Java in standard figure windows. Interested readers can find out more information about integrating Java controls in Matlab GUI in my book “Undocumented Secrets of MATLAB-Java Programming” (CRC Press, 2011, ISBN 978-1439869031). If you already have this book, please be kind enough to post your feedback on it on Amazon (link), for the benefit of others.

 
Related posts:
  1. Using pure Java GUI in deployed Matlab apps Using pure-Java GUI in deployed Matlab apps requires a special yet simple adaptation. ...
  2. Matlab and the Event Dispatch Thread (EDT) The Java Swing Event Dispatch Thread (EDT) is very important for Matlab GUI timings. This article explains the potential pitfalls and their avoidance using undocumented Matlab functionality....
  3. Blurred Matlab figure window Matlab figure windows can be blurred using a semi-transparent overlaid window - this article explains how...
  4. FindJObj – find a Matlab component’s underlying Java object The FindJObj utility can be used to access and display the internal components of Matlab controls and containers. This article explains its uses and inner mechanism....
 

Some performance-tuning tips

$
0
0

Today’s post is about performance. My goal is to show that contrary to widespread perception, Matlab is not inherently too slow to be used for real-life programs. In fact, by taking a small amount of time (compared to the overall dev time), Matlab programs can be accelerated by a large factor. I wish to demonstrate this claim with work that I recently completed for the Crustal Dynamics research group at Harvard University. They have created interactive Matlab GUIs for earthquake hazard, visualizing deformation and motion at plate boundary zones, recorded as GPS velocities:

Crustal dynamics visualization GUI

Crustal dynamics visualization GUI

These GUIs served them well for several years. But when they recently tried to analyze larger problems that involved far more data, it was getting so slow that it limited their ability to interrogate the GUI results effectively and do productive science (take a look at all the data points around New Zealand in the screenshot above). This is when I stepped in to help.

Two main performance issues stood out above the rest: Loading the data, and displaying the textual labels of numeric slip rates.

I/O: Loading data

I began with optimizing the data load time. This involves loading several different data files, which have custom textual formats. Of course, had the data files been initially created in some binary format, we could load it much faster. But we were faced with an existing situation where the textual data format was a given fact. Using Matlab’s profiler, it quickly emerged, as expected, that most of the time was spent parsing the text files. Two specific types of parsing were used, and they were both quite slow: reading the input files using textread, and parsing the input data using str2num.

To read the data from the files, I replaced the textread calls with corresponding textscan ones:

% Old (slow) code:
[Station.lon, Station.lat, Station.eastVel, Station.northVel, ...
 Station.eastSig, Station.northSig, Station.corr, ...
 Station.other1, Station.tog, Station.name] = textread(fileName, '%f%f%f%f%f%f%f%d%d%s');
 
% New (fast) code:
fid = fopen(fileName,'rt');
c = textscan(fid, '%f%f%f%f%f%f%f%d%d%s');
fclose(fid);
fn = {'lon', 'lat', 'eastVel', 'northVel', 'eastSig', 'northSig', 'corr', 'other1', 'tog', 'name'};
Station = cell2struct(c,fn,2);

To improve the performance of the str2num calls, I differentiated between two sub-cases:

In some cases, str2num was simply used to round numeric input data to a certain numeric precision. I improved this by changing the str2num calls with corresponding calls to round (which accepts an optional precision argument since R2014b):

% Old (slow) code
Station.lon = str2num(num2str(Station.lon, '%3.3f'));
 
% New (fast) code
Station.lon = round(Station.lon,3);        % R2014b or newer
Station.lon = round(Station.lon*1e3)/1e3;  % R2014a or older

In other cases, str2num was used to convert strings into numeric values. This should normally be done using a textscan parameter but in this specific case this was complicated due to the way the data was formatted, which required parsing iterative blocks. Still, converting strings into numbers is far faster using sscanf than str2num. The down side is that str2num also works in certain edge-cases where sscanf doesn’t. For this reason, I created a utility function (str2num_fast.m) that uses sscanf where possible, and falls back to str2num in case of problems. I then simply replaced all calls to str2num in the code to str2num_fast:

% str2num_fast - faster alternative to str2num
function data = str2num_fast(str, numCols)
    try
        % Fast code:
        str = char(str);
        str(:,end+1) = ' ';
        data = sscanf(str','%f');
        if nargin>1 && ~isempty(numCols)
            data = reshape(data,numCols,[])';
        end
    catch
        % This is much slower...
        data = str2num(str);
    end
end

The result: loading a medium-sized data set, which used to take 5-6 minutes (and much longer for larger data sets), now takes less than 1 second, a speedup of x500. This may not seem important, but when you load different data sets continuously, it can mean the difference between a usable and an unusable program. Not bad for starters…

For many additional related techniques, read chapters 4 and 11 of my Accelerating MATLAB Performance book (string processing and I/O, respectively), or other performance-related articles on this website.

Displaying data

I now turned my attention to the graphic visualization aspects. As can be seen in the screenshot above, there are multiple layers of textual labels, arrows, lines and data points that can be added to the chart.

It turned out that in the interest of improved performance, the various checkboxes were designed such that they merely turned the visibility of the graphic components on and off. This does indeed improve performance in the specific use-case of checking and unchecking a specific checkbox. But in the general case, it significantly degrades performance by adding numerous graphic handles to the plot. By just checking 3 of these checkboxes (not all of them), I found that 37365 different graphic handles were created in the plot axes. That’s a HUGE number, and it’s no surprise that adding additional visualization layers, or zooming/panning the axes, became excruciatingly slow, even when the layers were turned off (i.e., made invisible). This is because Matlab’s internal graphics engine needs to manage all these handles, even when they are not visible.

The first rule of improving graphics performance is that except if the handles need to be frequently turned on/off, no graphic element should remain plotted if it is not visible. In our case, this meant that when a visualization layer’s checkbox is deselected, the corresponding handles are deleted, not made invisible (there is of course a throughput/latency tradeoff in the general case, between the recurring handle’s creation time and the performance impact of keeping numerous invisible handles):

% hCheckbox is the handle of the selected/deselected checkbox
% hPlotHandles is the list of corresponding plotted graphic handles
if get(hCheckbox, 'Value') == 0
   %set(hPlotHandles, 'Visible', 'off');  % Old (slow) code
   delete(hPlotHandles);  % Faster throughput in our use-case
else
   hPlotHandles = ...
end

A related aspect is that if the axes is zoomed-in (as is often the case in this specific GUI), then there is no need to plot any graphic element which is outside the axes limits:

% Old (slow) code:
text(lons, lats, labels);
 
% Much faster: limit the labels only to the visible axes area
hAxes = handle(gca);
validIdx = within(lons, hAxes.XLim) & within(lats, hAxes.YLim);
text(lons(validIdx), lats(validIdx), labels(validIdx,:));
 
function validIdx = within(data,limits)
    validIdx = data >= limits(1) & data <= limits(2);
end

Finally, in order to reduce the number of displayed graphic handles, we can unify the separate line segments into a single line that has NaN (or Inf) values interspaced between the segments. This is a very important technique, that enabled a reduction of ~7000 separate line handles into a single line, which improves both the line creation time and any subsequent axes action (e.g., zoom/pan). This is even faster than limiting the display to the axes limits (and yes, we could combine them by displaying a single line that has fewer data points that fit the axes limits, but the extra performance benefit would be negligible):

% Old (slow) code:
line([Segment.lon1'; Segment.lon2'], [Segment.lat1'; Segment.lat2']);
 
% Faster code: limit the display to the axes limits
hAxes = handle(gca);
lonLimits = hAxes.XLim;
latLimits = hAxes.YLim;
valid = (within(Segment.lon1,lonLimits) | within(Segment.lon2,lonLimits)) & ...
        (within(Segment.lat1,latLimits) | within(Segment.lat2,latLimits));
line([Segment.lon1(valid)', Segment.lon2(valid)'], ...
     [Segment.lat1(valid)', Segment.lat2(valid)']);
 
% New (fastest) code:
lats = [Segment.lon1'; Segment.lon2'; nan(1,numel(Segment.lon2)];
lons = [Segment.lat1'; Segment.lat2'; nan(1,numel(Segment.lat2))];
line(lats(:), lons(:));

The result: the time for displaying the slip-rate labels in the zoomed-in Australasia region in the screenshot above was reduced from 33 seconds to 0.6 secs; displaying the residual velocity vectors was reduced from 1.63 secs to 0.02 secs — speedups of x50-100. Again, not bad at all… The GUI is now fast enough to enable true interactivity. In Prof. Brendan Meade’s words:

[The GUI] is now tremendously fast with all arrow type visualizations! It’s amazing and enabling us to work with large scale data sets much more efficiently.​ Simply fantastic. Just awesome… It’s so fast on the load and showing the slip rates in zoom regions with large models almost instant! This is exactly what we were hoping for. This is really making a difference in terms of how fast we can do science!

The technique of converting multiple lines into a single line using NaNs was discussed last week by Mike Garrity. Users who are interested in additional ideas for improving Matlab graphics performance are encouraged to visit Mike’s blog. For many additional techniques, read chapter 10 of my Accelerating MATLAB Performance book, or other performance-related articles on this website.

Some other techniques for speeding up graphic objects creation that I’ve found useful over the years include:

  1. Avoid plotting non-visible elements, including elements that are outside the current axes limits, or have their Visible property set to ‘off’ or have a color that is the same as the axes background color.
  2. Avoid plotting overlapped elements, esp. those that are occluded by non-transparent patches, or lines having the same coordinates.
  3. Avoid using the scatter function with fewer than 100 data points – instead, duplicate these points so that scatter will work with more than 100 points, where vectorization kicks in (details), or even better: use line rather than scatter.
  4. Use low-level rather than high-level plotting functions – i.e., line instead of scatter/plot/plot3; surface instead of surf.
  5. Avoid creating straight line with multiple data points – instead, only keep the end-points for plotting such lines. I find that this is a very common use-case, which is often overlooked and could have a significant performance impact.
  6. Avoid using plot markers if possible, and use simple markers if this cannot be avoided. Various markers have different performance impacts in various situations, but ‘.’ and ‘o’ are typically faster than others.
  7. Use the plot function’s input triplets format, rather than multiple calls to plot. For example:
    plot(data1x,data1y,'r', data2x,data2y,'g', data3x,data3y,'b', ...);
  8. Set the axes properties to static values before plotting, in order to avoid run-time dynamic computation and update of things like the limits, tick-marks etc.
  9. Avoid creating legends or colorbars initially – let the user create them by clicking the corresponding toolbar icon if needed. Legends and colorbars take a second or more to create and can often be avoided in the initial display. If this cannot be avoided, then at least create static legends/colorbars.
  10. Only call drawnow once you’ve finished plotting. I’ve seen numerous cases where users call drawnow within the plotting loop and this has a horrendous performance impact. However, note that in some cases drawnow is very important (example1, example2).
  11. Generate the plot while the figure is hidden.
  12. Data-reduce the plotted data. We can program this ourselves, or use former MathWorker Tucker McClure’s reduce_plot utility (a POTW selection) to do it for us. Data reduction is especially important when displaying images that do not need to be zoomed-in.
  13. Cast image data to uint8 before using image or imagesc to display the image.
  14. Avoid clearing/deleting and then recreating the axes when we need to replot – instead, just delete the relevant axes children objects and replot in the existing axes.
  15. Avoid using the axes function to set the focus on a specific axes – instead, set the figure’s CurrentAxes property, or pass the axes handle directly to the plotting function.

Naturally, there are certain use-cases where applicative requirements might prevent using one or more of these techniques, but in the general case I find that following them improves performance.

Conclusions

Matlab is NOT inherently slow. It can be made to run much faster than many people assume, by simply using the built-in profiler tool, following several simple coding techniques and employing common sense. Too often I find that complains about Matlab’s speed stem from the fact that not even a minimal effort was invested in trying to follow these steps. The difference between an unoptimized and optimized Matlab code can be far larger in Matlab than in other programming languages, so Matlab users should invest more time optimizing their code than they would perhaps need to do in other programming environments. The potential benefits, as I’ve shown above and in my book, could be enormous.

MathWorks is constantly investing in making Matlab’s engine faster by default, and there is certainly room for improvement in certain aspects (e.g, OOP and HG2 performance). But there will always be room for human insight to optimize performance, and we should not neglect this. Moreover, we should not blame Matlab for our failure to invest even a minimal optimization effort. MathWorks cannot (of course) say this to their users, but I don’t have this limitation and I say it out loud: people should stop blaming MathWorks for everything. If you create a car with square wheels, don’t complain if it doesn’t drive as fast as you expect (even if its engine could indeed be improved). In this case, the customer is not always (or entirely) right.

Perhaps it’s just a matter of setting the user expectations straight: we do not expect Matlab to automatically solve our equations or generate the perfect engineering model. So too should we not expect Matlab to automatically run fast enough for our needs. Just as we expect to spend time to solve the scientific or engineering problem, so too should we spend a bit of time to optimize the code to run fast enough.

Luckily, there are numerous different ways in which we can improve Matlab’s performance. In fact, there are so many different ways to achieve our performance goals that we can take a pick based on aesthetic preferences and subjective experience: Some people use vectorization, others like parallelization, some others prefer to invest in smarter algorithms or faster hardware, others trade memory for performance or latency for throughput, still others display a GUI that just provides a faster impression with dynamic feedback. Even if one technique fails or is inapplicable, there are many other alternatives that we could try. Just use the profiler and some common sense and you are half-way there. Good luck!

 
Related posts:
  1. Performance: accessing handle properties Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  2. New book: Accelerating MATLAB Performance Accelerating MATLAB Performance (ISBN 9781482211290) is a book dedicated to improving Matlab performance (speed). ...
  3. Plot performance Undocumented inner plot mechanisms can significantly improve plotting performance ...
  4. datestr performance Caching is a simple and very effective means to improve code performance, as demonstrated for the datestr function....
 

JGraph in Matlab figures

$
0
0

I would like to introduce guest blogger Scott Koch. Scott is part of the development team at Eigenvector Research Inc., makers of PLS_Toolbox, a commercial chemometrics and multivariate data analysis toolbox. Today Scott will expand on JGraph, a Java-based open source graph visualization and diagramming library.

What is JGraph?

JGraph is an interactive Java-based diagramming and graph visualization library. The maintainers of JGraph have a product family that includes a Java Swing library (open-source), a JavaScript library (proprietary commercial), as well as other technologies. They call their product family “mxGraph”, and the Swing product specifically as “JGraphX”. The Swing library is available on GitHub and licensed under BSD. I will refer to the Swing library as JGraph, since that was the original library’s name until it was completely redesigned some years ago and renamed JGraphX. You can read additional information on JGraph and access various documentation alternatives in its README file.

Graphing is a powerful visualization tool that has not yet been integrated into the core Matlab product. I assume that this will be rectified by MathWorks in a future Matlab release. But until that time, or even later if you are still using R2015a or older, we do not have a solution in the core Matlab. In our toolbox product, we use a cleverly designed image to display a simple diagram, but I always thought it would be nice to have a “real” diagramming tool that was interactive and full-featured.

So, as a long time follower of Yair’s blog, I was thrilled to see his post several years ago about integrating Java libraries for charting and diagramming in Matlab figures. Unfortunately, my first attempts at getting JGraph to work in Matlab were not very successful. Thanks to a comment on that original post by Markus Behle, I was able to gain full access to JGraph in Matlab. Today’s post will show how we can use JGraph in Matlab.

Creating a new JGraph edge in a Matlab figure

Creating a new JGraph edge in a Matlab figure


Creating a simple graph

To install JGraph, first download the JGraph zip file, extract it in some folder, and then add the contained JGraph jar file to your Matlab’s Java path:

javaaddpath('jgraphx/lib/jgraphx.jar');

Having installed JGraph, we can now create graphs pretty easily in Matlab – see Yair’s original post for details.

Unfortunately, dragging doesn’t work and that’s a bummer. To enable dragging, create a custom graph component. I posted a followup comment showing how to do this. Note that the following code will work without creating a custom graph component but you won’t be able to drag (and drop).

In JGraph, a graph is made up of cells. A cell can be a vertex (node) or edge (connector). A cell can also hold other cells in a group.

Below is a code snippet similar to Yair’s original JGraph post, except we’ll use the custom graph component from above and add an additional vertex:

% Make the graph object
graph = javaObjectEDT('mymxGraph’);
 
% If not using custom graph component use the following
% graph = javaObjectEDT('com.mxgraph.view.mxGraph');
 
% Get the parent cell
parent = graph.getDefaultParent();
 
% Group update
graph.getModel().beginUpdate();
 
% Add some child cells
v1 = graph.insertVertex(parent, '', 'Hello', 240, 150, 80, 30);
v2 = graph.insertVertex(parent, '', 'World',  20,  20, 80, 30);
v3 = graph.insertVertex(parent, '', 'Vertex', 20, 150, 80, 30);
graph.insertEdge(parent, '', 'Edge', v1, v2);
 
graph.getModel().endUpdate();
 
% Get scrollpane
graphComponent = com.mxgraph.swing.mxGraphComponent(graph);
 
% Make a figure and stick the component on it
f = figure('units','pixels');
pos = get(f,'position'); 
mypanel = javax.swing.JPanel(java.awt.BorderLayout);
mypanel.add(graphComponent);
[obj, hcontainer] = javacomponent(mypanel, [0,0,pos(3:4)], f);
 
% Normalize units so resize works better
set(hcontainer,'Units','normalized');

We have 3 vertices and a single edge connecting two vertices. Each has a label. By default you can edit the labels and drag the vertices and edges. If you mouse over the middle of a vertex it will highlight, indicating that if you click and drag, you will be able to add an edge. Dragging the edge to another vertex will connect it. You can also resize and reposition vertices, as well as set edge labels, as shown in the animated image above.

Customizing graphs with HTML and CSS

If you look at online examples of JGraph, you can see there are lots of options for customizing your graph’s appearance. JGraph uses “styles” on vertices and edges, which are similar in concept to Cascading Style Sheets (CSS). You can add style information when you create a vertex, or by using the Graph Model. Rerun the code above with the following lines substituted:

v1 = graph.insertVertex(parent, '', 'Hello', 240, 150, 150, 150, 'rounded=1;');
v2 = graph.insertVertex(parent, '', 'World',  20,  20,  80,  30, 'rounded=1;strokeColor=blue;fillColor=lightblue');
v3 = graph.insertVertex(parent, '', 'Vertex', 20, 150,  80,  30, 'rounded=1;strokeColor=#000000;fillColor=#00CCFF;gradientColor=#333300;fontColor=white');
graph.insertEdge(parent, '', 'Edge', v1, v2, 'edgeStyle=elbowEdgeStyle;strokeColor=#5d65df;strokeWidth=2');

Simple JGraph with new styles

Simple JGraph with new styles

As Yair has taught us, most Java controls can render HTML. JGraph is no different, you just need to turn it on and add HTML to your label:

>> graph.setHtmlLabels(true);
>> htmltxt = ['<html><b>My HTML Vertex</b><hr noshade size=''3''>'...
              '<table border=1 cellspacing=1 cellpadding=5 '...
              'font color="#0000FF" FONT COLOR="black">'...
              '<tr><td><b>Style</b></td><td><b>Value</b></td></tr>'...
              '<tr><td>rounded</td><td>1</td></tr>'...
              '<tr><td>fillColor</td><td>yellow</td></tr>'...
              '</table></html>'];
>> v1.setValue(htmltxt)
>> graph.refresh

Vertex with HTML label

Vertex with HTML label

Adding a callback

Let’s add more functionality to our graph by adding a callback. To do this, we need to add a mouse-clicked callback to the graph scrollpane:

% Handle the scrollpane and add a click callback
scrollpanehandle = handle(graphComponent.getGraphControl, 'CallbackProperties');
set(scrollpanehandle, 'MouseClickedCallback', {@mouseClickCallback,f})

With a click callback in place, we can interrogate the click event and graph to determine what object is under the click. If the click happens over a vertex, a context menu is displayed allowing changing of the fill color.

function mouseClickCallback(Obj,eventData,myFig)
   %Graph mouse click callback
 
   %Extract graph object
   graphcomponent = Obj.getGraphContainer;
   graph = graphcomponent.getGraph;
   figpos = get(myFig,'position');
 
   %Get cell under click if it's there
   mycell = graphcomponent.getCellAt(eventData.getX,eventData.getY);
 
   if isempty(mycell) || mycell.isEdge
      %Clicking in open space
      return
   end
 
   if javax.swing.SwingUtilities.isRightMouseButton(eventData)
      mymenu = findobj(myFig,'tag','backgroundmenu');
      if isempty(mymenu)
         %Create context menu
         mymenu = uicontextmenu('tag','backgroundmenu');
         uimenu(mymenu,'Tag','graymenu','Label','Gray Background');
         uimenu(mymenu,'Tag','bluemenu','Label','Blue Background');
      end
 
      %Update callback with current cell object
      set(findobj(mymenu,'tag','graymenu'),'callback',{@changeFillColor,graph,mycell,'gray'});
      set(findobj(mymenu,'tag','bluemenu'),'callback',{@changeFillColor,graph,mycell,'blue'});
 
      %Show context menu
      set(mymenu,'position', [eventData.getX+8 figpos(4)-eventData.getY-8]);
      set(mymenu,'visible','on');
   end
end
 
function changeFillColor(Obj,eventData,varargin)
   % Change cell fill color
 
   %Pull graph object, current cell object, and new color value out of varargin
   mygraph = varargin{1};
   mycell = varargin{2};
   newcolor = varargin{3};
 
   %Get current style
   mystyle = char(mycell.getStyle);
 
   %Chop string into cells and locate fillcolor cell
   stylecell = strsplit(mystyle,';');
   fcloc = ~cellfun('isempty',strfind(stylecell,'fillColor='));
 
   %Make new fillcolor string
   switch newcolor
      case 'gray'
         newcolor = 'fillColor=#E8E8E8';
      case 'blue'
         newcolor = 'fillColor=#A9BCF5';
   end
 
   %Add new color into style
   if any(fcloc)
      stylecell{fcloc} = newcolor;
   else
      stylecell{end+1} = newcolor;
   end
 
   %Join styles back into single style string
   mystyle = strjoin(stylecell,';');
 
   %Set new style
   mygraph.getModel.setStyle(mycell,mystyle);
end

Conclusions

Hopefully this post gave enough information to get started making attractive and useful graphs with Matlab and JGraph. There is a lot of functionality included with JGraph and we’ve only scratched the surface today. I hope to have a future post discussing Groups, Drag and Drop, Layout Engines, and a few other topics that build upon what was discussed today.

Here are a few resources that could help you get started:

 
Related posts:
  1. JGraph and BDE This article shows how to display graph-theory diagrams in Matlab using several different Java libraries...
  2. Disabling menu entries in deployed docked figures Matlab's standard menu items can and should be removed from deployed docked figures. This article explains how. ...
  3. Docking figures in compiled applications Figures in compiled applications cannot officially be docked since R2008a, but this can be done using a simple undocumented trick....
  4. Matlab-Java interface using a static control The switchyard function design pattern can be very useful when setting Matlab callbacks to Java GUI controls. This article explains why and how....
 

Capturing print events

$
0
0

As a followup to my recent post on capturing and using HG2′s new graphic events, I would like to welcome back guest blogger Robert Cumming, who developed a commercial Matlab GUI framework. Today, Robert will highlight an unusual use of event listeners to enable print output customizations by tapping into print-related events.

One of my toolbox clients wanted to ensure that every print-out, of any Matlab GUI, would contain a datestamp footer and a project id header.

Initially I thought this would be a simple task, since the GUI framework already has saveAs and copyToClipboard methods that users could utilize. Moreover, as Yair has shown some years ago, we can easily adapt the standard callbacks associated with the Matlab figure toolbar’s <Print> button and the menu-bar’s Print action. We can even customize the standard print setup. However, all this does not help when directly invoking printout commands from the Matlab command line or from within the user program, for example:

% Create the GUI
[x,y,z] = peaks(75); 
surf(x,y,z);
 
% printout via print() or export_fig
print(gcf, .... )
export_fig filename  % see http://undocumentedmatlab.com/blog/export_fig

Printout with the expected header and footer stamps

Printout with the expected header and footer stamps


This initially posed a bit of a challenge – how could I capture the print event?

The key to solving this was using events in a different way. Rather than listen for a print event, we listen for something that print interacts with in the figure window. This will solve the problem for both print and export_fig, since export_fig uses print internally.

We can listen to get and set events on many Matlab properties. In this instance we can trap get events on a figure’s PaperPositioMode, or PaperSize property. print, saveas and export_fig all access these properties before doing the actual printing, so by trapping the event we can run our own function before the printing is done. For example:

classdef PrintListenerDemo
  properties
    referenceNo = 'R1234-56'
  end
 
  methods (Access=public)
    function obj = PrintListenerDemo
      hFig = figure;
      [x,y,z] = peaks(75);
      surf ( x, y, z );
 
      % add listener on event to prepare the figure for printing
      addlistener ( hFig, 'PaperPositionMode', 'PreGet', @obj.Prep );
 
      % Testing only:
      evalin ( 'base', 'print ( gcf, ''-dmeta'' )' );  % simulate user action in command-line
      print(hFig,'-dmeta');    % simulate programmatic printout
    end
 
    function Prep(obj, hFig, varargin)
      disp ( 'running function in preparation for printing.' );
 
      % Add datestamp and reference id UIControls
      str = sprintf ( 'Printed @ %s', datestr(now) );
      uicontrol ( 'parent',hFig, 'style','text', 'units','normalized', ...
                  'position',[0 0 1 0.07], 'string',str, 'BackgroundColor','white' );
    end
  end
end

When we run the above we can see that the disp message is displayed twice, because the property has two get calls in the print function. We can easily solve this by saving a temp variable that is created the first time it is run.

The next thing we need to do is to clean up afterwards, i.e. remove the uicontrols and reset the temp variable to ensure that any future print events are captured.
Here you might think the second get call I mentioned above was post printing, but it’s not. So we need to capture another event to do the cleaning up.

In this instance I thought about what was likely to happen – some sort of user interaction, e.g. a mouse move, press or key press. So we can listen for any of those events and run our clean up method. This is shown in the full code below:

% PrintListenerDemo - Demo of print listener methodology
classdef PrintListenerDemo
  properties
    referenceNo = 'R1234-56'
  end
 
  methods (Access=public)
    function obj = PrintListenerDemo
      hFig = figure;
      [x,y,z] = peaks(75);
      surf ( x, y, z );
 
      % add listener on event to prepare the figure for printing
      addlistener ( hFig, 'PaperPositionMode', 'PreGet', @obj.Prep );      
 
      % add a few different ways to clean up
      addlistener ( hFig, 'ButtonDown', @obj.CleanUp );
      addlistener ( hFig, 'WindowKeyPress', @obj.CleanUp );
      addlistener ( hFig, 'WindowMouseMotion', @obj.CleanUp );
 
      % Testing only:
      evalin ( 'base', 'print ( gcf, ''-dmeta'' )' );  % simulate user action in command-line
      print(hFig,'-dmeta');    % simulate programmatic printout
    end
 
    function Prep(obj, hFig, varargin)
      try
        hFig.ApplicationData.printPrepDone;
        return % If variable set do not run this method again
      end
      disp ( 'preparing for print.' );
 
      % create the date string
      str1 = sprintf ( 'Printed @ %s', datestr(now) );
      str2 = sprintf ( 'Reference: %s', obj.referenceNo );
 
      % create 2 UI controls to contain the information requested in the image
      hFig.ApplicationData.UIC1 = uicontrol ( 'parent',hFig, 'style','text', 'units','norm', 'string',str1, 'BackgroundColor','w', 'position',[0 0 1 0.07] );
      hFig.ApplicationData.UIC2 = uicontrol ( 'parent',hFig, 'style','text', 'units','norm', 'string',str2, 'BackgroundColor','w', 'position',[0 0.93 1 0.07] );
 
      % Save a temp variable to stop this function being called many times.
      hFig.ApplicationData.printPrepDone = true;
    end
 
    function CleanUp(obj, hFig, varargin)
      try
        if hFig.ApplicationData.printPrepDone
          % Clean up the uicontrols
          disp ( 'clean up post printing event' );
          delete ( hFig.ApplicationData.UIC1 );
          delete ( hFig.ApplicationData.UIC2 );
 
          % remove the temp variable, so the next print job will be captured
          hFig.ApplicationData = rmfield ( hFig.ApplicationData, 'printPrepDone' );
        end
      end
    end
  end
end

It is noted here that the datestamp and the reference number remain visible until the user interacts with the GUI but that’s a small price to pay.

Any suggestions on other ways to clean up the print event afterwards? If so, please post a comment below. Alternatively if you have used events and listeners in an unusual way please share this as well.

Conclusions

  1. It is possible to capture printout events in your code even when the print command is invoked programmatically, without a direct reference to your code
  2. We can use events for things that we might never have initially considered

 
Related posts:
  1. Customizing print setup Matlab figures print-setup can be customized to automatically prepare the figure for printing in a specific configuration...
  2. UDD Events and Listeners UDD event listeners can be used to listen to property value changes and other important events of Matlab objects...
  3. Detecting window focus events Matlab does not have any documented method to detect window focus events (gain/loss). This article describes an undocumented way to detect such events....
  4. Matlab callbacks for Java events Events raised in Java code can be caught and handled in Matlab callback functions - this article explains how...
 

Matlab designs by Tim Smith

$
0
0

Matlab has undergone significant facelifts in recent years: Matlab Mobile (first introduced in 2010, with various upgrades since), R2012b’s new desktop toolstrip, various Matlab Central’s website facelifts (example1, example2), R2014b’s new graphics system (HG2), Matlab on the Web (MOTW), and Matlab’s upcoming GUI framework (AppDesigner). That’s quite a lot of UI designs, new and overhauled, over a relatively short timespan.

Designer Tim Smith (designbytimsmith.com), is apparently responsible for many of the sleek UI designs, working with MathWorks’ internal User Experience (UX) team. Tim’s website showcases his work, philosophy, and design process for Matlab’s AppDesigner, Desktop toolstrip, Matlab Mobile, and Matlab on the Web.

I highly recommend reading what Tim has to say about these designs, as well as other designs that he created for other clients. Impressive work indeed.

Formerly a MathWorks visual designer, Tim left MathWorks in 2012 to join PayPal, and currently works at Google. designbytimsmith.com has no contact page, and Tim is apparently very secretive about his email address, which is a bit odd for someone who was the design lead for Google’s new Inbox product. Anyway, you can contact him via his LinkedIn profile or Google+ page.

If you want to get a feel for what Matlab might look like down the road, simply head over to Tim’s website.

Enjoy!

Various Tim Smith designs for AppDesigner's dial widget

Various Tim Smith designs for AppDesigner's dial widget

 
Related posts:
  1. Sliders in Matlab GUI Professional-looking slider controls can easily be integrated in Matlab GUI. ...
  2. Specialized Matlab plots The new MathWorks Plot Gallery provides access to some plotting examples on the File Exchange. Numerous others are available, extending the customizability of Matlab graphics. ...
  3. Matlab layout managers: uicontainer and relatives Matlab contains a few undocumented GUI layout managers, which greatly facilitate handling GUI components in dynamically-changing figures....
  4. Solving a Matlab hang problem A very common Matlab hang is apparently due to an internal timing problem that can easily be solved. ...
 

Using linkaxes vs. linkprop

$
0
0

One of my clients recently asked me to solve a very peculiar problem: He had several axes and was using Matlab’s builtin linkaxes function to link their axis limits. However, it didn’t behave quite the way that he expected. His axes were laid out as 2×2 subplots, and he wanted the two columns to be independently linked in the X axis, and the two rows to be independently linked in the Y axis:

% Prepare the axes
ax(1,1) = subplot(2,2,1); 
ax(1,2) = subplot(2,2,2); 
ax(2,1) = subplot(2,2,3); 
ax(2,2) = subplot(2,2,4);
 
% Plot something
x = 0 : 0.01 : 10;
line(x, sin(x),   'Parent',ax(1,1));
line(x, sin(2*x), 'Parent',ax(1,2));
line(x, cos(x),   'Parent',ax(2,1));
line(x, cos(5*x), 'Parent',ax(2,2));
 
% Link the relevant axes
linkaxes(ax(:,1),'x');  % left column
linkaxes(ax(:,2),'x');  % right column
linkaxes(ax(1,:),'y');  % top row
linkaxes(ax(2,:),'y');  % bottom row

The problem was that the plots didn’t behave as expected: when zooming in on the bottom-left axes, for example, only the bottom-right axes was updated (Y-limits synced), whereas the top-left axes’ X-limits remained unchanged:

Badly-synced axes limits

Badly-synced axes limits


Apparently, the second set of two linkaxes commands (to sync the rows’ Y-limits) overrode the first set of two linkaxes commands (to sync the columns’ X-limits).

Analysis

The reason for this unexpected behavior is that under the hood, linkaxes attaches property-change listeners to the corresponding axes, and stores these listeners in the axes’ hidden ApplicationData property (which is typically accessible via the getappdata / setappdata / isappdata / rmappdata set of functions). Specifically, up to a certain Matlab release (R2013b?), the listeners were placed in a field called ‘listener__’, and since then in a field called ‘graphics_linkaxes’. In either case, the field name was constant.

Therefore, when we placed the first set of linkaxes commands, the axes were correctly synced vertically (ax(1,1) with ax(2,1) in their X-limits, and similarly ax(1,2) with ax(2,2)). But when we placed the second set of linkaxes commands, the internal field in the axes’ ApplicationData property was overriden with the new listeners (that synced the rows’ Y-limits).

It so happens that Matlab listeners have a very nasty feature of being deleted when they are no longer referenced anywhere (within a workspace variable or object property). So when we overrode the first set of listener handles, we effectively deleted them, as if they were never set in the first place.

Some people may possibly complain about both issues at this point:

  • That Matlab listeners get deleted so easily without so much as a console warning, and certainly against naive intuition.
  • That repeated calls to linkaxes should override (rather than complement) each other.

As a side note, the addlistener function creates a listener and then persists it in the object’s hidden AutoListeners__ property. However, unlike the linkaxes behavior, addlistener‘s listener handles are always appended to AutoListeners__‘s contents, rather than replacing it. This ensures that all listeners are accessible and active until their container is deleted or they are specifically modified/removed. I wish that linkaxes used this mechanism, rather than its current ApplicationData one.

Workaround: linkprop

Luckily, there is a very easy and simple workaround, namely to use linkprop rather than linkaxes. The linkprop function is a lower-level function that creates a property-change listener that syncs corresponding properties in any specified array of object handles. In fact, linkaxes uses linkprop in order to create the necessary listeners. In our case, we can use linkprop directly, to independently attach such listeners to the axes’ XLim and YLim properties. We just need to ensure that all these listeners remain accessible to Matlab throughout the corresponding objects’ life-cycle. This is easily done using ApplicationData, as is done by linkaxes.m but in a smarter manner that does not override the previous values. The benefit of this is that when the axes are deleted, then so are the listeners; as long as the axes are accessible then so are the listeners. We just need to ensure that we don’t override these listener values:

setappdata(ax(1,1), 'YLim_listeners', linkprop(ax(1,:),'YLim')); 
setappdata(ax(2,1), 'YLim_listeners', linkprop(ax(2,:),'YLim'));
setappdata(ax(1,1), 'XLim_listeners', linkprop(ax(:,1),'XLim'));
setappdata(ax(1,2), 'XLim_listeners', linkprop(ax(:,2),'XLim'));

This results in the expected behavior:

properly-linked axes

properly-linked axes

Conclusions

The design decision by MathWorks to automatically delete Matlab listeners as soon as their reference count is zeroed and they get garbage-collected, causes a myriad of unexpected run-time behaviors, one of which is exemplified in today’s post on linkaxes. This would still have not caused any problem had the developers of linkaxes been aware of this listener feature and taken care to store the linked listener handles in an accumulating repository (e.g., adding the listener handle to an array of existing handles, rather than replacing a scalar handle).

Luckily, now that we know how Matlab listeners behave, we can easily identify abnormal behavior that results from listener handles going out of scope, and can easily take steps to persist the handles somewhere, so that they will remain active.

I wish to stress here that the listeners’ limited scope is fully documented in several places in the documentation (e.g., here as well as the linkprop doc page). The non-additive behavior of linkaxes is also documented, albeit in an almost-invisible footnote on its doc-page.

However, I humbly contend that the fact that these behaviors are documented doesn’t meant that they are correct. After all, figure windows or timers aren’t deleted when their handle goes out of scope, are they? At the very least, I hope that MathWorks will improve the relevant doc pages, to highlight these non-intuitive behaviors, and in the case of linkaxes to present a linkprop usage example as a workaround.

If you are interested in the topic of Matlab listeners, note that I’ve written quite a few listener-related posts over the years (about property-change listeners as well as event listeners). I urge you to take a look at the list of related articles presented below, or to use the search box at the top of the page.

 
Related posts:
  1. Multi-column (grid) legend This article explains how to use undocumented axes listeners for implementing multi-column plot legends...
  2. Property value change listeners HG handle property changes can be trapped in a user-defined callback. ...
  3. Plot LimInclude properties The plot objects' XLimInclude, YLimInclude, ZLimInclude, ALimInclude and CLimInclude properties are an important feature, that has both functional and performance implications....
  4. Determining axes zoom state The information of whether or not an axes is zoomed or panned can easily be inferred from an internal undocumented object....
 

Static Java classpath hacks

$
0
0

A few days ago I encountered a situation where I needed to incorporate a JAR file into Matlab’s static Java classpath. I came across several relevant hacks that I thought could be useful for others:

The documented approach

In most use-cases, adding Java classes (or ZIP/JAR files) to the dynamic Java classpath is good enough. This can easily be done in run-time using the javaaddpath function. In certain cases, for example where the Java code uses asynchronous events, the Java files need to be added to the static, rather than the dynamic, Java classpath. In other cases, the Java code misbehaves when loaded using Matlab’s dynamic Java classloader, rather than the system classloader (which is used for the static classpath (some additional info). One example of this are the JAR/ZIP files used to connect to various databases (each database has its own Java JDBC connector, but they all need to reside in the static Java classpath to work properly).

Adding class-file folders or ZIP/JAR files to the static Java classpath can be done in several manners: we can update the Matlab installation’s classpath.txt file, or (starting in R2012b) a user-prepared javaclasspath.txt file. Either of these files can be placed in the Matlab (or deployed application’s) startup folder, or the user’s Matlab preferences folder (prefdir). This is all documented.

There are several important drawbacks to this approach:

  1. Both classpath.txt and javaclasspath.txt do not accept relative paths, only full path-names. In other words, we cannot specify ../../libs/mylib.jar but only C:\Yair\libs\mylib.jar or similar variants. We can use the $matlabroot, $arch, and $jre_home place-holder macros, but not user folders. We can easily do this in our personal computer where the full path is known, but this is difficult to ensure if we deploy the application onto other computers.
    Matlab’s compiler only supports adding Java classes and JARs to the dynamic classpath, but not to the static one – we need to manually add a classpath.txt or javaclasspath.txt to the deployment folder, complete with the deployment target’s correct full path. Naturally this is problematic when we wish to grant the user the flexibility of installing the deployed application anywhere on their computer disk.
  2. The javaclasspath.txt file is only supported on R2012b onward. The classpath.txt file is supported in both old and new releases, but (1) modifying it in Matlab’s installation folder may require system privileges, and (2) require update upon each and every Matlab reinstallation or upgrade. A classpath.txt file from one Matlab release will NOT be compatible with another Matlab release – if we try using an incorrect file Matlab will crash or hang. If you are not using just a single matlab release, this quickly turns into a maintenance nightmare.
  3. The javaclasspath.txt file loads the user-specified classes after those loaded in Matlab’s pre-defined classpath.txt. If we edit The classpath.txt file, we can place our classes at the top of the file, but this again entails the maintenance nightmare described above

Luckily, there are a few hacks that can alleviate some of the pain when dealing with deployed applications that use static Java classes:

Fixing javaclasspath.txt in run-time

At the very top of our main function, we could fix (or create) the javaclasspath.txt file to include the current folder’s actual full path, and then relaunch the application and exit the current session. The newly-launched application will use this javaclasspath.txt file and everything should work well from that moment onward. Here’s a bare-bones implementation example:

function mainProgram()
   if ~exist('javaclasspath.txt','file')
      try
         fid = fopen('javaclasspath.txt', 'wt');
         fprintf(fid, [pwd '/classesFolder/']);  % add folder of *.class files
         fprintf(fid, [pwd '/subFolder/classes.jar']);  % add jar/zip file
         fclose(fid);
         system(['./' mfilename ' &']);
      catch err
         msg = sprintf('Could not create %s/javaclasspath.txt - error was: %s', pwd, err.message);
         uiwait(msgbox(msg, 'Error', 'warn'));  % need uiwait since otherwise exit below will delete the msgbox
      end
      exit
   end
 
   % If we reached this point, then everything is ok - proceed normally
   ...

A related solution is to recreate the classpath.txt file using the build-generation script, as described by Andrew Janke.

Preloading Java class files in javaclasspath.txt

Class folders and JAR/ZIP files can be loaded before those in classpath.txt, without having to modify the system’s classpath.txt, as exposed by Christopher Barber. All we need to do is to add a line containing the <before> string as a separate line in our javaclasspath.txt user-file. All entries beneath this line will be loaded into the front (rather than the end) of the static Java classpath. For example:

# This will be placed at the end of the static Java classpath
C:\placed\at\the\end\of\the\static\classpath\mylib1.jar
 
<before>
 
# This will be placed at the beginning of the static Java classpath
C:\placed\at\the\top\of\the\static\classpath\mylib2.jar

Loading Java class files into the static classpath in run-time (!)

The crown jewels in Java static classpath hacking belong without a doubt to power-users Andrew Janke and Amro. Based on Amro’s tip (based on a Java forum post from back in 2002), Andrew created a Matlab function that loads a Matlab class into the static classpath at run-time (i.e., without needing to modify/create either classpath.txt or javaclasspath.txt), slightly modified by me to include an optional classname input arg. Here’s the resulting javaaddpathstatic function:

function javaaddpathstatic(file, classname)
%JAVAADDPATHSTATIC Add an entry to the static classpath at run time
%
% javaaddpathstatic(file, classname)
%
% Adds the given file to the static classpath. This is in contrast to the
% regular javaaddpath, which adds a file to the dynamic classpath.
%
% Files added to the path will not show up in the output of
% javaclasspath(), but they will still actually be on there, and classes
% from it will be picked up.
%
% Caveats:
%  * This is a HACK and bound to be unsupported.
%  * You need to call this before attempting to reference any class in it,
%    or Matlab may "remember" that the symbols could not be resolved. Use
%    the optional classname input arg to let Matlab know this class exists.
%  * There is no way to remove the new path entry once it is added.
 
% Andrew Janke 20/3/2014 http://stackoverflow.com/questions/19625073/how-to-run-clojure-from-matlab/22524112#22524112
 
parms = javaArray('java.lang.Class', 1);
parms(1) = java.lang.Class.forName('java.net.URL');
loaderClass = java.lang.Class.forName('java.net.URLClassLoader');
addUrlMeth = loaderClass.getDeclaredMethod('addURL', parms);
addUrlMeth.setAccessible(1);
 
sysClassLoader = java.lang.ClassLoader.getSystemClassLoader();
 
argArray = javaArray('java.lang.Object', 1);
jFile = java.io.File(file);
argArray(1) = jFile.toURI().toURL();
addUrlMeth.invoke(sysClassLoader, argArray);
 
if nargin > 1
    % load the class into Matlab's memory (a no-args public constructor is expected for classname)
    eval(classname);
end

The usage is super simple: instead of using javaaddpath to load a class-files folder (or ZIP/JAR file) into Matlab’s dynamic Java classpath, we’d use javaaddpathstatic to load the same input into the static classpath – in runtime.

As Andrew notes, there are important caveats to using the new javaaddpathstatic function. One of the important caveats is that the class needs to be loaded before Matlab gets around to “discover” that it does not exist, because from then on even if we load the class into the static classpath, Matlab will report the class as missing. Therefore, we need to call javaaddpathstatic at the very top of the program (possibly even in our startup.m file). Moreover, if we directly call the class anywhere in the same m-file as our call to javaaddpathstatic, it will fail. The reason is that Matlab’s built-in interpreter processes the direct Java call when it pre-parses the file, before the javaaddpathstatic had a chance to run:

function this_Will_Fail()
   % mylib.jar contains the com.app.MyClass class
   javaaddpathstatic([pwd '/mylib.jar']);
   obj = com.app.MyClass;  % this will fail!

Instead, we need to prevent the interpreter from processing the class before run-time, by loading the class at run-time:

function this_Should_Work()
   % mylib.jar contains the com.app.MyClass class
   javaaddpathstatic([pwd '/mylib.jar']);
   obj = javaObject('com.app.MyClass');  % this should work ok

At least in one case, for a recent client project that required deploying a compiled Matlab application that used JDBC to connect to a database (and therefore relied on the static classpath), this saved the day for me.

I’m sad I wasn’t aware of this years ago, but now that I have posted it, we have less of an excuse to complain about static classpath files in Matlab. Hopefully MathWorks will incorporate this idea into Matlab so that we can more easily load classes into the static classpath in runtime, and remove the need for ugly deployment hacks (and yes, this includes MathWorks’ own toolboxes), hopefully removing the caveats listed above along the way.

Analyzing loaded Java classes in run-time

A related Matlab function, whereisjavaclassloadingfrom, was posted by Andrew Janke to report information about loaded classes, including whether they were loaded by the static (=standard Java) classloader, or the dynamic (=MathWorks’ custom) classloader, and from which location. For example:

% This is loaded into the static classpath as part of Matlab's standard classpath.txt file:
>> whereisjavaclassloadingfrom('java.util.HashMap')
Version: 8.6.0.232648 (R2015b)
Class:       java.util.HashMap
ClassLoader: sun.misc.Launcher$AppClassLoader@69365360
URL:         jar:file:/C:/Program%20Files/Matlab/R2015b/sys/java/jre/win64/jre/lib/rt.jar!/java/util/HashMap.class
 
% This is loaded into the dynamic classpath using MathWorks' custom classloader
>> javaaddpath('C:\Yair\Work\MultiClassTableModel')
>> whereisjavaclassloadingfrom('MultiClassTableModel')
Version: 8.6.0.232648 (R2015b)
Class:       MultiClassTableModel
ClassLoader: com.mathworks.jmi.CustomURLClassLoader@5270d6ad
URL:         file:/C:/Yair/Work/MultiClassTableModel/MultiClassTableModel.class
 
% This is an example of a class that is not loaded
>> whereisjavaclassloadingfrom('no.such.Class')
Error using javaArray
No class no.such.Class can be located on the Java class path
Error in whereisjavaclassloadingfrom (line 25)

Parting words

How risky is all this in terms of future compatibility? well, I’m not a prophet, but I’d say that using these hacks is pretty risky in this regard. Matlab’s custom classloader is way-deep in undocumented territory. This does not mean that the functionality will change tomorrow, but don’t be surprised if and when it does.

Have you ever used any additional undocumented hack relating to using the Java classpaths in Matlab? If so then please post a comment below.

Users who have endured my post this far, should probably also read my related article about Java class access pitfalls.

 
Related posts:
  1. Matlab-Java interface using a static control The switchyard function design pattern can be very useful when setting Matlab callbacks to Java GUI controls. This article explains why and how....
  2. Java class access pitfalls There are several potential pitfalls when accessing Matlab classes from Matlab. ...
  3. Matlab callbacks for Java events Events raised in Java code can be caught and handled in Matlab callback functions - this article explains how...
  4. JMI – Java-to-Matlab Interface JMI enables calling Matlab functions from within Java. This article explains JMI's core functionality....
 

Accessing internal Java class members

$
0
0

Following my previous post on using the Java classloader, I thought I’d follow up today with a somewhat-related peculiarity.

Inner classes

Whenever we have an enum or inner-class defined within a Java class, it can be accessed in Java using standard dot-notation. For example, com.mathworks.hg.peer.ComboboxPeer.MLComboBox refers to an inner class MLComboBox which is defined within the ComboboxPeer class. When compiled, the class would be stored in a file called ComboboxPeer$InnerClassName.class. In other words, the JVM uses the $ separator char to indicate that MLComboBox is internal to ComboboxPeer.

Within the Java code, we would simply use the regular dot-notation (ClassName.MLComboBox) – the $ separator is part of the internal JVM implementation that the Java programmer should not be concerned about.

Unfortunately, we cannot ignore this in Matlab: Matlab’s interpreter, which acts as a bridge to the JVM, is not smart enough to know that in certain cases the dot-notation should be converted into a $. Therefore, trying to access ClassName.MLComboBox directly in Matlab fails:

>> jObject = com.mathworks.hg.peer.ComboboxPeer.MLComboBox([])
Undefined function or variable 'MLComboBox'.
 
>> jObject = com.mathworks.hg.peer.ComboboxPeer$MLComboBox([])
 jObject = com.mathworks.hg.peer.ComboboxPeer$MLComboBox([])
                                             ↑
Error: The input character is not valid in MATLAB statements or expressions.

The solution in such cases is to use Matlab’s javaObject (or javaObjectEDT) function with the JVM’s internal $-representation:

>> jObject = javaObject('com.mathworks.hg.peer.ComboboxPeer$MLComboBox',[])
jObject =
com.mathworks.hg.peer.ComboboxPeer$MLComboBox[,0,0,0x0,invalid,layout=com.mathworks.hg.peer.types.HGWindowsComboBoxUI$1,alignmentX=...]

To access public methods (functions) of the inner class, we could similarly use the javaMethod (or javaMethodEDT) function.

Enumerations

Java Enums act in a very similar manner to inner classes: we access them using standard dot-notation in Java source code, and the JVM translates the enumerations into $-notation internally. Unfortunately, we cannot access Java enums in Matlab using javaObject as shown above; we need to use a more circuitous way.

For example, JVM 1.6 (in Matlab 7.5 R2007b onward) provides access to the new TrayIcon object (I explained its usage back in 2009). One of TrayIcon‘s functionalities is displaying a message next to the tray icon, using java.awt.TrayIcon.displayMessage(). This method expects an object of type java.awt.TrayIcon.MessageType, which is an enumeration within the TrayIcon class. However, Matlab’s dot-notation does not recognize what should have been the following correct notation, so we need to resort to Java reflection:

>> trayIcon.displayMessage('title','info msg',TrayIcon.MessageType.INFO);
??? No appropriate method or public field MessageType for class java.awt.TrayIcon

>> trayIconClasses = trayIcon.getClass.getClasses;
>> trayIconClasses(1)
ans =
class java.awt.TrayIcon$MessageType	<= hurray!!!
>> MessageTypes = trayIconClasses(1).getEnumConstants
MessageTypes =
java.awt.TrayIcon$MessageType[]:
    [java.awt.TrayIcon$MessageType]	<= 1: ERROR
    [java.awt.TrayIcon$MessageType]	<= 2: WARNING
    [java.awt.TrayIcon$MessageType]	<= 3: INFO
    [java.awt.TrayIcon$MessageType]	<= 4: NONE
>> trayIcon.displayMessage('title','info msg',MessageTypes(3));

systray INFO message

and another example, now with a WARNING icon:

systray WARNING message

We can also access Java enums using their built-in values() and valueOf() methods:

>> msgType=javaMethod('valueOf','java.awt.TrayIcon$MessageType','INFO')
msgType =
INFO		<= a java.awt.TrayIcon$MessageType object
 
>> enums = cell(javaMethod('values','java.awt.TrayIcon$MessageType'));
>> msgType = enums{3};   % alternative way to find the INFO enum value
>> cellfun(@(c)c.toString.char, enums, 'uniform',false)'
ans =
    'ERROR'    'WARNING'    'INFO'    'NONE'

Inner classes can also be accessed using the Java classloader, although this is more cumbersome.

Static fields

Using public Java static fields in Matlab is easy – in most cases we could use standard dot-notation. For example:

>> jColor = java.awt.Color.orange
jColor =
java.awt.Color[r=255,g=200,b=0]

We could use the struct function to get a Matlab struct with all the public static fields of a Java class object:

>> struct(java.awt.Color.red)
ans =
          white: [1x1 java.awt.Color]
          WHITE: [1x1 java.awt.Color]
      lightGray: [1x1 java.awt.Color]
     LIGHT_GRAY: [1x1 java.awt.Color]
           gray: [1x1 java.awt.Color]
           GRAY: [1x1 java.awt.Color]
       darkGray: [1x1 java.awt.Color]
      DARK_GRAY: [1x1 java.awt.Color]
          black: [1x1 java.awt.Color]
          BLACK: [1x1 java.awt.Color]
            red: [1x1 java.awt.Color]
            RED: [1x1 java.awt.Color]
           pink: [1x1 java.awt.Color]
           PINK: [1x1 java.awt.Color]
         orange: [1x1 java.awt.Color]
          ...

But in some cases, we may have static fields of an uninstantiable inner class, and in such cases dot-notation will fail in Matlab. Moreover, since the inner class is not instantiable, we cannot use javaObject as above.

For example, trying to access internal static fields in java.nio.channels.FileChannel.MapMode, in order to use them to create a memory-mapped file using FileChannel.map(…), is problematic. In this specific case, we have the built-in memmapfile Matlab function as a much simpler alternative, but for the record, we could do this:

>> channel = java.io.FileInputStream('234.jpg').getChannel
channel =
sun.nio.ch.FileChannelImpl@1c7a5d3    <= which extends FileChannel
 
>> innerClasses = channel.getClass.getSuperclass.getDeclaredClasses;
>> innerClasses(1)
ans =
class java.nio.channels.FileChannel$MapMode
 
>> read_only_const = innerClasses(1).getField('READ_ONLY').get(1)
read_only_const =
READ_ONLY    <= a java.nio.channels.FileChannel$MapMode object
 
>> fields = innerClasses(1).getFields;
>> read_only_const = fields(1).get(1);    % an alternative
 
>> buffer = channel.map(read_only_const, 0, channel.size);

Additional information can be found in my book, Undocumented Secrets of MATLAB-Java Programming (CRC Press, 2011). If you already have this book, please be kind enough to post a review on Amazon, to spread the word.

 
Related posts:
  1. Java class access pitfalls There are several potential pitfalls when accessing Matlab classes from Matlab. ...
  2. Extending a Java class with UDD Java classes can easily be extended in Matlab, using pure Matlab code. ...
  3. Performance: accessing handle properties Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  4. Setting system tray popup messages System-tray icons and messages can be programmatically set and controlled from within Matlab, using new functionality available since R2007b....
 

Solving an mput (FTP) hang problem

$
0
0

Matlab includes a variety of builtin utility functions that enable easy access to FTP. These functions are basically methods of an FTP object using Matlab’s old class system (for example, the mput function is implemented as mput.m in the %matlabroot%\toolbox\matlab\iofun\@ftp\ folder). These are pretty old files that haven’t changed much in years.

FTPI recently needed to upload files from Matlab onto an FTP server, and discovered that calling mput simply hang Matlab to the point that I needed to kill and restart the Matlab process. The problem was not in the FTP server, since it could be accessed normally using FTP clients such as FileZilla and WinSCP. So it had to be something internal to Matlab. My initial workaround was to create an automation script (using WinSCP in my case) for the file upload. But this kludge is bot non-robust as well as slow. A fix to the Matlab problem would be much better.

Some online research yielded others who have complained about similar issues over the years, but I saw no concrete answer. I saw many references online to problems that relate to the combination of passive FTP with Windows 7 / firewall / Java 7, that suggested several fixes (example 1, example 2, example 3, example 4). However, none of them solved the problem: calling mput (or dir etc.) continued to freeze Matlab, forcing either a hard process kill or waiting several minutes for the timeout.

Today, Malcolm Lidierth, author of the Waterloo graphics package, told me that he also saw a similar situation on Mac. Fortunately, Malcolm discovered a much better solution to the problem than my external scripts workaround. It seems that simply setting the Java object underlying Matlab’s FTP object to use passive mode fixes the problem (possibly in addition to the other fixes mentioned above).

This can be done in two manners:

The easiest is to add the following highlighted line in mput.m, on or about line 69 (the exact line may change based on your Matlab release):

...
% Upload this file.
fis = java.io.FileInputStream(fileObject);
h.jobject.enterLocalPassiveMode();  % Use passive modestatus = h.jobject.storeFile(name,fis);
fis.close;
...

This works but has several limitations: it does not solve the problems of other passive FTP commands (dir for example), but they can be solved in a similar manner; it creates a counter-problem when connecting to non-passive FTP servers (users might wish to make this a parameter of the ftp constructor function); and of course it requires changing Matlab’s installation files which is problematic in many aspects, as well as non-portable if you ever use your program on another machine or Matlab release.

Here’s a much simpler, portable and flexible solution: simply set the underlying Java object’s passive mode after connecting to the server (using the ftp constructor function) but before using mput or dir or any other command that uses passive FTP mode:

f = ftp('myftpserver.com',username,password);
cd(f);  sf=struct(f);  sf.jobject.enterLocalPassiveMode();mput(f,filename);
dir(f);
close(f);

Note that we need to connect first, then get the underlying Java reference using the struct hack (since direct access to f.jobject is prevented), then we enter local passive mode, and only then we call mput to upload the file. If we omit the highlighted line in the script above, then mput (and dir etc.) will hang.

This way, we can programmatically control when to use passive mode, and no changes to the Matlab install files is required: our Matlab script should now work on all platforms and Matlab releases.

Note the seemingly unnecessary call to cd(f) – this is done to ensure a valid connection before setting the passive mode. We should ensure to do this before each call to mput/dir etc., since otherwise, if the connection drops for any reason (e.g., timeout or some other disconnection), then the mput/dir command would reconnect without passive mode (causing a hang). By calling cd(f) we ensure that the connection is done and passive mode is re-entered before mput/dir are called.

As an interesting related note, ftp accepts an undocumented set of optional input parameters following its first 3 documented inputs (hostname, username and password). We can pass one or more of the following parameters in P-V (param name, param value) pairs format: System, LenientFutureDates, DefaultDateFormatStr, RecentDateFormatStr, ServerLanguageCode, ServerTimeZoneId, ShortMonthNames. All of these parameters expect string (char) values, except LenientFutureDates that expects a logical value (true/false). All the parameters have a default value of empty. An explanation of these parameters can be found in Apache’s documentation of the FTPClientConfig class (Matlab’s ftp uses a plain Apache FTPClient object, where you can also find an explanation of the enterLocalPassiveMode method that was used above).

Italy visit, Aug 26 – Sep 1, 2015

I will be traveling to north Italy between Aug 26 – Sep 1, 2015. If you happen to be in the area at that time, I will be happy to meet you to discuss how I could bring value to your work. Please email me (altmany at gmail) if you are interested.

Due to my travel, this blog will take a short summer vacation, and will return in early September. Stay tuned!

 
Related posts:
  1. Solving a Matlab hang problem A very common Matlab hang is apparently due to an internal timing problem that can easily be solved. ...
  2. Fixing a Java focus problem Java components added to Matlab GUIs do not participate in the standard focus cycle - this article explains how to fix this problem....
  3. Solving a MATLAB bug by subclassing Matlab's Image Processing Toolbox's impoint function contains an annoying bug that can be fixed using some undocumented properties....
  4. Using pure Java GUI in deployed Matlab apps Using pure-Java GUI in deployed Matlab apps requires a special yet simple adaptation. ...
 

Callback functions performance

$
0
0

Matlab enables a variety of ways to define callbacks for asynchronous events (such as interactive GUI actions or timer invocations). We can provide a function handle, a cell-array (of function handle and extra parameters), and in some cases also a string that will be eval‘ed in run-time. For example:

hButton = uicontrol(..., 'Callback', @myCallbackFunc);  % function handle
hButton = uicontrol(..., 'Callback', {@myCallbackFunc,data1,data2});  % cell-array
hButton = uicontrol(..., 'Callback', 'disp clicked!');  % string to eval

The first format, function handle, is by far the most common in Matlab code. This format has two variant: we can specify the direct handle to the function (as in @myCallbackFunc), or we could use an anonymous function, like this:

hButton = uicontrol(..., 'Callback', @(h,e) myCallbackFunc(h,e));  % anonymous function handle

All Matlab callbacks accept two input args by default: the control’s handle (hButton in this example), and a struct or object that contain the event’s data in internal fields. In our anonymous function variant, we therefore defined a function that accepts two input args (h,e) and calls myCallbackFunc(h,e).

These two variants are functionally equivalent:

hButton = uicontrol(..., 'Callback', @myCallbackFunc);             % direct function handle
hButton = uicontrol(..., 'Callback', @(h,e) myCallbackFunc(h,e));  % anonymous function handle

In my experience, the anonymous function variant is widely used – I see it extensively in many of my consulting clients’ code. Unfortunately, there could be a huge performance penalty when using this variant compared to a direct function handle, which many people are simply not aware of. I believe that even many MathWorkers are not aware of this, based on a recent conversation I’ve had with someone in the know, as well as from the numerous usage examples in internal Matlab code: see the screenshot below for some examples; there are numerous others scattered throughout the Matlab code corpus.

Part of the reason for this penalty not being well known may be that Matlab’s Profiler does not directly attribute the overheads. Here is a typical screenshot:

Profiling anonymous callback function performance

Profiling anonymous callback function performance

In this example, a heavily-laden GUI figure window was closed, triggering multiple cleanup callbacks, most of them belonging to internal Matlab code. Closing the figure took a whopping 8 secs. As can be seen from the screenshot, the callbacks themselves only take ~0.66 secs, and an additional 7.4 secs (92% of the total) is unattributed to any specific line. Think about it for a moment: we can only really see what’s happening in 8% of the time – the Profiler provides no clue about the root cause of the remaining 92%.

The solution in this case was to notice that the callback was defined using an anonymous function, @(h,e)obj.tableDeletedCallbackFcn(e). Changing all such instances to @obj.tableDeletedCallbackFcn (the function interface naturally needed to change to accept h as the first input arg) drastically cut the processing time, since direct function handles do not carry the same performance overheads as anonymous functions. In this specific example, closing the figure window now became almost instantaneous (<1 sec).

Conclusions

There are several morals that I think can be gained from this:

  1. When we see unattributed time in the Profiler summary report, odds are high that this is due to function-call overheads. MathWorks have significantly reduced such overheads in the new R2015b (released last week), but anonymous [and to some degree also class methods] functions still carry a non-negligible invocation overheads that should be avoided if possible, by using direct [possibly non-MCOS] functions.
  2. Use direct function handles rather than anonymous function handles, wherever possible
  3. In the future, MathWorks will hopefully improve Matlab’s new engine (“LXE”) to automatically identify cases of @(h,e)func(h,e) and replace them with faster calls to @func, but in any case it would be wise to manually make this change in our code today. It would immediately improve readability, maintainability and performance, while still being entirely future-compatible.
  4. In the future, MathWorks may also possibly improve the overheads of anonymous function invocations. This is more tricky than the straight-forward lexical substitution above, because anonymous functions need to carry the run-time workspace with them. This is a little known and certainly very little-used fact, which means that in practice most usage patterns of anonymous functions can be statically analyzed and converted into much faster direct function handles that carry no run-time workspace info. This is indeed tricky, but it could directly improve performance of many Matlab programs that naively use anonymous functions.
  5. Matlab’s Profiler should really be improved to provide more information about unattributed time spent in internal Matlab code, to provide users clues that would help them reduce it. Some information could be gained by using the Profiler’s -detail builtin input args (which was documented until several releases ago, but then apparently became unsupported). I think that the Profiler should still be made to provide better insights in such cases.

Oh, and did I mention already the nice work MathWorks did with 15b’s LXE? Matlab’s JIT replacement was many years in the making, possibly since the mid 2000′s. We now see just the tip of the iceberg of this new engine: I hope that additional benefits will become apparent in future releases.

For a definitive benchmark of Matlab’s function-call overheads in various variants, readers are referred to Andrew Janke’s excellent utility (with some pre-15b usage results and analysis). Running this benchmark on my machine shows significant overhead reduction in function-call overheads in 15b in many (but not all) invocation types.

For those people wondering, 15b’s LXE does improve HG2′s performance, but just by a small bit – still not enough to offset the large performance hit of HG2 vs. HG1 in several key aspects. MathWorks is actively working to improve HG2′s performance, but unfortunately there is still no breakthrough as of 15b.

Additional details on various performance issues related to Matlab function calls (and graphics and anything else in Matlab) can be found in my recent book, Accelerating MATLAB Performance.

 
Related posts:
  1. Controlling callback re-entrancy Callback reentrancy is a major problem for frequently-fired events. Luckily, it can easily be solved....
  2. Continuous slider callback Matlab slider uicontrols do not enable a continuous-motion callback by default. This article explains how this can be achieved using undocumented features....
  3. uicontextmenu performance Matlab uicontextmenus are not automatically deleted with their associated objects, leading to leaks and slow-downs. ...
  4. Undocumented mouse pointer functions Matlab contains several well-documented functions and properties for the mouse pointer. However, some very-useful functions have remained undocumented and unsupported. This post details their usage....
 

Adding dynamic properties to graphic handles

$
0
0

A client recently asked me to extend one of Matlab’s built-in graphic containers (uiflowcontainer in this specific case) with automatic scrollbars that would enable the container to act as a scroll-panel. The basic idea would be to dynamically monitor the container’s contents and when it is determined that they overflow the container’s boundaries, then attach horizontal/vertical scrollbars to enable scrolling the contents into view:

Scrollable Matlab container

Scrollable Matlab container

This may sound simple, but there are actually quite a few undocumented hacks that make this possible, including listening to ObjectChildAdded/ObjectChildRemoved events, location/size/visibility events, layout changes etc. Maybe I’ll blog about it in some future article.

Today’s post is focused on a specific aspect of this project, attaching dynamic properties to the builtin uiflowcontainer, that would enable users to modify the container’s properties directly, as well as control aspects of the scrolling using the new properties: handles to the parent container, as well as the horizontal and vertical scrollbars, and even a new refresh() method.

The “textbook” approach to this would naturally be to create a new class that extends (inherits) uiflowcontainer and includes these new properties and methods. Unfortunately, for some reason that escapes my understanding, MathWorks saw fit to make all of its end-use graphic object classes Sealed, such that they cannot be extended by users. I did ask for this to be changed long ago, but the powers that be apparently decided that it’s better this way.

So the fallback would be to create our own dedicated class having all the new properties as well as those of the original container, and ensure that all the property values are synchronized in both directions. This is probably achievable, if you have a spare few days and a masochistic state of mind. Being the lazy bum and authority-rebel that I am, I decided to take an alternate approach that would simply add my new properties to the built-in container handle. The secret lies in the undocumented function schema.prop (for HG1, R2014a and older) and the fully-documented addprop function (for HG2, R2014b and newer).

In the examples below I use a panel, but this mechanism works equally well on any Matlab HG object: axes, lines, uicontrols, figures, etc.

HG2 – addprop function

The addprop function is actually a public method of the dynamicprops class. Both the dynamicprops class as well as its addprop function are fully documented. What is NOT documented, as far as I could tell, is that all of Matlab’s builtin handle graphics objects indirectly inherit dynamicprops, via matlab.graphics.Graphics, which is a high-level superclass for all HG objects. The bottom line is that we can dynamically add run-time properties to any HG object, without affecting any other object. In other words, the new properties will only be added to the handles that we specifically request, and not to any others. This suits me just fine:

hProp = addprop(hPanel, 'hHorizontalScrollBar');
hPanel.hHorizontalScrollBar = hMyScrollbar;
hProp.SetAccess = 'private';  % make this property read-only

The new property hHorizontalScrollBar is now added to the hPanel handle, and can be accessed just like any other read-only property. For example:

>> get(hPanel, 'hHorizontalScrollBar')
ans =
    JavaWrapper

>> hPanel.hHorizontalScrollBar
ans =
    JavaWrapper

>> hPanel.hHorizontalScrollBar = 123
You cannot set the read-only property 'hHorizontalScrollBar' of UIFlowContainer.

Adding new methods is more tricky, since we do not have a corresponding addmethod function. The trick I used was to create a new property having the requested new method’s name, and set its read-only value to a handle of the requested function. For example:

hProp = addprop(hPanel, 'refresh');
hPanel.refresh = @myRefreshFunc;
hProp.SetAccess = 'private';  % make this property read-only

We can then invoke the new refresh “method” using the familiar dot-notation:

hPanel.refresh();

Note: if you ever need to modify the initial value in your code, you should revert the property’s SetAccess meta-property to 'public' before Matlab will enable you to modify the value:

try
    % This will raise an exception if the property already exists
    hProp = addprop(hPanel, propName);
catch
    % Property already exists - find it and set its access to public
    hProp = findprop(hPanel, propName);
    hProp.SetAccess = 'public';
end
hPanel.(propName) = newValue;

HG1 – schema.prop function

In HG1 (R2014a and earlier), we can use the undocumented schema.prop function to add a new property to any HG handle (which is a numeric value in HG1). Donn Shull wrote about schema.prop back in 2011, as part of his series of articles on UDD (Unified Data Dictionary, MCOS’s precursor). In fact, schema.prop is so useful that it has its own blog tag here and appears in no less than 15 separate articles (excluding today). With HG2′s debut 2 years ago, MathWorks tried very hard to rid the Matlab code corpus of all the legacy schema-based, replacing most major functionalities with MCOS-based HG2 code. But so far it has proven impossible to get rid of schema completely, and so schema code is still used extensively in Matlab to this day (R2015b). Search your Matlab path for “schema.prop” and see for yourself.

Anyway, the basic syntax is this:

hProp = schema.prop(hPanel, propName, 'mxArray');

The 'mxArray' specifies that the new property can accept any data type. We can limit the property to only accept certain types of data by specifying a less-generic data type, among those recognized by UDD (details).

Note that the meta-properties of the returned hProp are somewhat different from those of HG2′s hProp. Taking this into account, here is a unified function that adds/updates a new property (with optional initial value) to any HG1/HG2 object:

function addProp(hObject, propName, initialValue, isReadOnly)
    try
        hProp = addprop(hObject, propName);  % HG2
    catch
        try
            hProp = schema.prop(hObject, propName, 'mxArray');  % HG1
        catch
            hProp = findprop(hObject, propName);
        end
    end
    if nargin > 2
        try
            hProp.SetAccess = 'public';  % HG2
        catch
            hProp.AccessFlags.PublicSet = 'on';  % HG1
        end
        hObject.(propName) = initialValue;
    end
    if nargin > 3 && isReadOnly
        try
            % Set the property as read-only
            hProp.SetAccess = 'private';  % HG2
        catch
            hProp.AccessFlags.PublicSet = 'off';  % HG1
        end
    end
end

 
Related posts:
  1. Performance: accessing handle properties Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  2. UDD Properties UDD provides a very convenient way to add customizable properties to existing Matlab object handles...
  3. getundoc – get undocumented object properties getundoc is a very simple utility that displays the hidden (undocumented) properties of a specified handle object....
  4. Customizing axes part 4 – additional properties Matlab HG2 axes can be customized in many different ways. This article explains some of the undocumented aspects. ...
 

Font selection components

$
0
0

I’ve written here in the past about how Matlab includes multiple alternatives for color selection, plot-type selection and date selection components, that can easily be integrated in Matlab figures (GUI). Today, I will show that Matlab also contains various built-in components for font selection.

These components are used by Matlab itself, integrated within the Preferences panel, print setup popup, property inspector window and so on. In most cases the components have remained unchanged for multiple releases, some existing in Matlab releases for the past decade or more. However, since internal components can change without prior notice, there is no assurance that any particular component will continue to be available in future Matlab releases.

Readers who are interested in additional details about the components mentioned in today’s post are referred to sections 3.3.3 and 5.5.2 of my book, Undocumented Secrets of MATLAB-Java Programming.

uisetfont

The only documented font-selection alternative in Matlab is uisetfont, which presents a popup dialog window that returns the selected font properties in a simple Matlab struct:

>> font = uisetfont
font = 
      FontName: 'Arial'
    FontWeight: 'normal'
     FontAngle: 'normal'
     FontUnits: 'points'
      FontSize: 10

Matlab's uisetfont dialog

Matlab's uisetfont dialog


The main drawback of uisetfont is the fact that it displays a separate non-resizable modal dialog window. We cannot embed uisetfont within our own panel, integrated in our GUI figure.

DesktopFontPicker

DesktopFontPicker is a Swing component that presents a font selection panel that can easily be inserted into any Matlab GUI container (figure, panel or tab) using the javacomponent function:

font = java.awt.Font('Tahoma',java.awt.Font.PLAIN, 11);
jFontPanel = com.mathworks.widgets.DesktopFontPicker(true, font);
[jhPanel,hContainer] = javacomponent(jFontPanel, [10,10,250,170], gcf);

DesktopFontPicker panel

DesktopFontPicker panel

Instead of the “Use desktop font” label, we can use our own label:

jFontPanel.setUseDesktopFontLabel('Use Yair''s standard font...')

Non-standard DesktopFontPicker panel

Non-standard DesktopFontPicker panel

To extract the selected font, use one of the following methods provided by DesktopFontPicker:

jFont = jFontPanel.getSelectedFont();  % returns a java.awt.Font object
flag = jFontPanel.getUseDesktopFont();  % true if top radio-button is selected; false if custom font is selected

FontPrefsPanel

The builtin com.mathworks.mlwidgets.prefs.FontPrefsPanel class is used in Matlab to display the font preferences panel in the Preferences window. We can integrate it directly in our GUI:

jFontPanel=com.mathworks.mlwidgets.prefs.FontPrefsPanel(java.awt.Dimension);
[jhPanel,hContainer] = javacomponent(jFontPanel, [1,1,500,470], gcf);

Using this class is admittedly more cumbersome than DesktopFontPicker and I would not recommend using it in practice.

FontPicker

Font selection can also be shown with drop-downs (combo-boxes), rather than with lists as in DesktopFontPicker, FontPrefsPanel, or uisetfont. Use of drop-downs significantly reduces the display “real-estate” required by the control. This is useful in forms where the font selection is only one of several user-configurable options, and where enough space must be reserved for other configuration controls. We can do this using the com.mathworks.widgets.fonts.FontPicker class.

Up until Matlab release R2010a, FontPicker‘s constructor accepted optional parameters of a pre-selected font (a java.awt.Font object), an optional boolean flag indicating whether to display sample text using the selected font, an optional layout indicator, and optional list of selectable font names. Several screenshots of different parameter combinations are shown below:

import com.mathworks.widgets.fonts.FontPicker
jFontPicker = FontPicker(font, sampleFlag, layout);
[hjFontPicker, hContainer] = javacomponent(jFontPicker, position, gcf);
FontPickerFontPickerFontPicker
font=[]java.awt.Font('Tahoma', java.awt.Font.PLAIN, 8 )[]
sampleFlag=falsefalsetrue
layout=FontPicker.GRID_LAYOUT (=1)FontPicker.LONG_LAYOUT (=2)FontPicker.LONG_LAYOUT (=2)
position=[10,200,140,40][10,200,225,20][10,200,225,80]

As before, the selected font can be retrieved using jFontPicker.getSelectedFont().

In Matlab release R2010b, FontPicker‘s interface changed, and the above code no longer works. This highlights a common pitfall in future-compatibility of internal components: even when the components remain, their interface sometimes changes. Here is the new code format, starting with R2010b:

jLayout = javaMethod('valueOf', 'com.mathworks.widgets.fonts.FontPicker$Layout', 'WIDE_WITH_SAMPLE');  % options: COMPACT, WIDE, WIDE_WITH_SAMPLE
jFont = java.awt.Font('Tahoma', java.awt.Font.PLAIN, 10);  % initial font to display (may not be [])
jFontPicker = com.mathworks.widgets.fonts.FontPicker(jFont, jLayout);
jFontPanel = jFontPicker.getComponent;
[jhPanel,hContainer] = javacomponent(jFontPanel, [10,10,250,120], gcf);

FontChooserPanel

As a final alternative for font selection, we can use the JIDE font-selection component. This component has two variants: as a drop-down/combo-box (com.jidesoft.combobox.FontComboBox) and as a standard JPanel (com.jidesoft.combobox.FontChooserPanel):

jFont = java.awt.Font('arial black',java.awt.Font.PLAIN, 8);
jFontPicker = com.jidesoft.combobox.FontComboBox(jFont);
[hjFontPicker, hContainer] = javacomponent(jFontPicker, position, gcf);
set(hjFontPicker, 'ItemStateChangedCallback', @myCallbackFunction);

JIDE's FontComboBox

JIDE's FontComboBox

Within the callback function, use getSelectedFont() to retrieve the updated font (again, a java.awt.Font object). There is also a corresponding setSelectedFont(font) to programmatically update the control with the specified Font object.

The combo-box presents a FontChooserPanel, which can be accessed (via the PopupPanel property or the corresponding getPopupPanel() method) after it has been initially created. Thereafter, the panel can be customized. For example, the preview text can be modified via the panel’s PreviewText property (or the setPreviewText(text) method).

The same FontChooserPanel can also be displayed as a stand-alone font-selection panel, unrelated to any combo-box. Different GUI requirements might prefer using a compact combo-box approach, or the larger stand-alone panel.

This combo-box/panel duality is a common feature of JIDE controls. I have previously shown it in my color selection components and date selection components articles.

popupmenu uicontrol

As another example of using a font-selection drop-down (combo-box), we can use a standard Matlab popupmenu uicontrol, setting its String property value to a cell-array containing the supported system’s fonts (as returned by the listfonts function). A nice twist here is to use the undocumented trick that all Matlab uicontrols inherently support HTML to list each of the fonts in their respective font style:

fontStr = @(font) ['<html><font face="' font '">' font '</font></html>'];
htmlStr = cellfun(fontStr, listfonts, 'uniform',false);
uicontrol('style','popupmenu', 'string',htmlStr, 'pos',[20,350,100,20]);

HTML-rendered fonts popup menu

HTML-rendered fonts popup menu

Note that we could also use a listbox uicontrol using the same code.

Austria visit, 11-15 October, 2015

I will be travelling to clients in Austria next week, between October 11-15. If you are in Austria and wish to meet me to discuss how I could bring value to your work, then please email me (altmany at gmail).

 
Related posts:
  1. Date selection components The JIDE package, pre-bundled in Matlab, contains several GUI controls for selecting dates - this article explains how they can be used...
  2. Color selection components Matlab has several internal color-selection components that can easily be integrated in Matlab GUI...
  3. Plot-type selection components Several built-in components enable programmatic plot-type selection in Matlab GUI - this article explains how...
  4. Setting status-bar components Matlab status-bars are Java containers in which we can add GUI controls such as progress-bars, not just simple text labels...
 

Hyperlink text labels

$
0
0

It is often useful to include hyperlinked text labels in GUIs. Such labels provide single-click access to important functionality, improve branding, and are non-intrusive action controls having a lower visual impact than a full-blown button. There are several ways that we can display such hyperlinks in Matlab GUIs, and today I will show one of my favorites.

The basic idea is to create a Java text label control whose label displays an HTML link. The control is modified to change the mouse cursor when it hovers over the hyperlink, and a mouse-click callback is set to open the hyperlink target in the system browser:

hyperlink text label

hyperlink text label

% Create and display the text label
url = 'UndocumentedMatlab.com';
labelStr = ['<html>More info: <a href="">' url '</a></html>'];
jLabel = javaObjectEDT('javax.swing.JLabel', labelStr);
[hjLabel,hContainer] = javacomponent(jLabel, [10,10,250,20], gcf);
 
% Modify the mouse cursor when hovering on the label
hjLabel.setCursor(java.awt.Cursor.getPredefinedCursor(java.awt.Cursor.HAND_CURSOR));
 
% Set the label's tooltip
hjLabel.setToolTipText(['Visit the ' url ' website']);
 
% Set the mouse-click callback
set(hjLabel, 'MouseClickedCallback', @(h,e)web(['http://' url], '-browser'))

Note the visual illusion here: we do not directly click the hyperlink (note that its href is empty), but rather the label control. The end-result is the same.

Also note that this technique could be used to easily display clickable icons/images, including animated and transparent GIFs, by simply setting the label’s HTML string to display the relevant image. I have already shown how to do this in another post. Uses could range from clickable logo images to clickable help icons.

We could also use a flat (borderless) button. I have already posted related articles about button customizations in Matlab GUIs (here, here and here). In fact, I have already shown how we can use borderless buttons in Matlab axes to display a non-obtrusive control for controlling plot properties. The code would be very similar to the above, except that we would use a JButton rather than a JLabel, and also need to setBorder([]) and similar button-specific modifications. Buttons have a bit more functionality and customizability than simple text labels; the appearance would be the same, but the extra customizability may be handy in very special cases, although not for most use-cases.

One of the benefits of using either JLabels or JButtons is that they enable multiple callbacks (e.g., FocusGained,FocusLost) and properties (e.g., VerticalAlignment,ToolTipText) that the standard Matlab text uicontrol does not provide (not to mention their builtin ability to display HTML, which Matlab’s uicontrol text labels do not posses).

 
Related posts:
  1. Customizing Matlab labels Matlab's text uicontrol is not very customizable, and does not support HTML or Tex formatting. This article shows how to display HTML labels in Matlab and some undocumented customizations...
  2. Images in Matlab uicontrols & labels Images can be added to Matlab controls and labels in a variety of manners, documented and undocumented. ...
  3. Syntax highlighted labels & panels Syntax-highlighted labels and edit-boxes can easily be displayed in Matlab GUI - this article explains how. ...
  4. Setting status-bar text The Matlab desktop and figure windows have a usable statusbar which can only be set using undocumented methods. This post shows how to set the status-bar text....
 

Enabling user callbacks during zoom/pan

$
0
0

An annoying side-effect of Matlab figure uimodes (zoom, pan and rotate3d) is that they disable the user’s figure-wide callbacks (KeyPressFcn, KeyReleaseFcn, WindowKeyPressFcn, WindowKeyReleaseFcn, WindowButtonUpFcn, WindowButtonDownFcn and WindowScrollWheelFcn). In most cases, users will indeed expect the mouse and keyboard behavior to change when these modes are active (selecting a zoom region with the mouse for instance). However, in certain cases we may need to retain our custom callback behavior even when the modes are active. This is particularly relevant for the keyboard callbacks, which are not typically used to control the modes and yet may be very important for our figure’s interactive functionality. Unfortunately, Matlab’s mode manager installs property listeners that prevent users from modifying these callback when any mode is active:

>> hFig=figure; plot(1:5); zoom on
>> set(hFig, 'KeyPressFcn', @myKeyPressCallback)
Warning: Setting the "KeyPressFcn" property is not permitted while this mode is active.
(Type "warning off MATLAB:modes:mode:InvalidPropertySet" to suppress this warning.)
 
> In matlab.uitools.internal.uimodemanager>localModeWarn (line 211)
  In matlab.uitools.internaluimodemanager>@(obj,evd)(localModeWarn(obj,evd,hThis)) (line 86)
 
>> get(hFig, 'KeyPressFcn')  % the KeyPressFcn callback set by the mode manager
ans =
    @localModeKeyPressFcn
    [1x1 matlab.uitools.internal.uimode]
    {1x2 cell                          }

The question of how to override this limitation has appeared multiple times over the years in the CSSM newsgroup (example1, example2) and the Answers forum, most recently yesterday, so I decided to dedicate today’s article to this issue.

In Matlab GUI, a “mode” (aka uimode) is a set of defined behaviors that may be set for any figure window and activated/deactivated via the figure’s menu, toolbar or programmatically. Examples of predefined modes are plot edit, zoom, pan, rotate3d and data-cursor. Only one mode can be active in a figure at any one time – this is managed via a figure’s ModeManager. Activating a figure mode automatically deactivates any other active mode, as can be seen when switching between plot edit, zoom, pan, rotate3d and data-cursor modes.

This mode manager is implemented in the uimodemanager class in %matlabroot%/toolbox/matlab/uitools/+matlab/+uitools/internal/@uimodemanager/uimodemanager.m and its sibling functions in the same folder. Until recently it used to be implemented in Matlab’s old class system, but was recently converted to the new MCOS (classdef) format, without an apparent major overhaul of the underlying logic (which I think is a pity, but refactoring naturally has lower priority than fixing bugs or adding new functionality).

Anyway, until HG2 (R2014b), the solution for bypassing the mode-manager’s callbacks hijacking was as follows (credit: Walter Roberson):

% This will only work in HG1 (R2014a or earlier)
hManager = uigetmodemanager(hFig);
set(hManager.WindowListenerHandles, 'Enable', 'off');
set(hFig, 'WindowKeyPressFcn', []);
set(hFig, 'KeyPressFcn', @myKeyPressCallback);

In HG2 (R2014b), the interface of WindowListenerHandles changed and the above code no longer works:

>> set(hManager.WindowListenerHandles, 'Enable', 'off');
Error using set
Cannot find 'set' method for event.proplistener class.

Luckily, in MathWorks’ refactoring to MCOS, the property name WindowListenerHandles was not changed, nor its status as a public read-only hidden property. So we can still access it directly. The only thing that changed is its meta-properties, and this is due not to any change in the mode-manager’s code, but rather to a much more general change in the implementation of the event.proplistener class:

>> hManager.WindowListenerHandles(1)
ans =
  proplistener with properties:
 
       Object: {[1x1 Figure]}
       Source: {7x1 cell}
    EventName: 'PreSet'
     Callback: @(obj,evd)(localModeWarn(obj,evd,hThis))
      Enabled: 0
    Recursive: 0

In the new proplistener, the Enabled meta-property is now a boolean (logical) value rather than a string, and was renamed Enabled in place of the original Enable. Also, the new proplistener doesn’t inherit hgsetget, so it does not have set and get methods, which is why we got an error above; instead, we should use direct dot-notation.

In summary, the code that should now be used, and is backward compatible with old HG1 releases as well as new HG2 releases, is as follows:

% This should work in both HG1 and HG2:
hManager = uigetmodemanager(hFig);
try
    set(hManager.WindowListenerHandles, 'Enable', 'off');  % HG1
catch
    [hManager.WindowListenerHandles.Enabled] = deal(false);  % HG2
end
set(hFig, 'WindowKeyPressFcn', []);
set(hFig, 'KeyPressFcn', @myKeyPressCallback);

During an active mode, the mode-manager disables user-configured mouse and keyboard callbacks, in order to prevent interference with the mode’s functionality. For example, mouse clicking during zoom mode has a very specific meaning, and user-configured callbacks might interfere with it. Understanding this and taking the proper precautions (for example: chaining the default mode’s callback at the beginning or end of our own callback), we can override this default behavior, as shown above.

Note that the entire mechanism of mode-manager (and the related scribe objects) is undocumented and might change without notice in future Matlab releases. We were fortunate in the current case that the change was small enough that a simple workaround could be found, but this may possibly not be the case next time around. It’s impossible to guess when such features will eventually break: it might happen in the very next release, or 20 years in the future. Since there are no real alternatives, we have little choice other than to use these features, and document the risk (the fact that they use undocumented aspects). In your documentation/comments, add a link back here so that if something ever breaks you’d be able to check if I posted any fix or workaround.

For the sake of completeness, here is a listing of the accessible properties (regular and hidden) of both the mode-manager as well as the zoom uimode, in R2015b:

>> warning('off', 'MATLAB:structOnObject');  % suppress warning about using structs (yes we know it's not good for us...)
>> struct(hManager)
ans = 
                    CurrentMode: [1x1 matlab.uitools.internal.uimode]
                  DefaultUIMode: ''
                       Blocking: 0
                   FigureHandle: [1x1 Figure]
          WindowListenerHandles: [1x2 event.proplistener]
    WindowMotionListenerHandles: [1x2 event.proplistener]
                 DeleteListener: [1x1 event.listener]
            PreviousWindowState: []
                RegisteredModes: [1x1 matlab.uitools.internal.uimode]
 
>> struct(hManager.CurrentMode)
ans = 
    WindowButtonMotionFcnInterrupt: 0
                UIControlInterrupt: 0
                   ShowContextMenu: 1
                         IsOneShot: 0
                    UseContextMenu: 'on'
                          Blocking: 0
               WindowJavaListeners: []
                    DeleteListener: [1x1 event.listener]
              FigureDeleteListener: [1x1 event.listener]
                    BusyActivating: 0
                              Name: 'Exploration.Zoom'
                      FigureHandle: [1x1 Figure]
             WindowListenerHandles: [1x2 event.proplistener]
                   RegisteredModes: []
                       CurrentMode: []
               ModeListenerHandles: []
               WindowButtonDownFcn: {@localWindowButtonDownFcn  [1x1 matlab.uitools.internal.uimode]}
                 WindowButtonUpFcn: []
             WindowButtonMotionFcn: {@localMotionFcn  [1x1 matlab.uitools.internal.uimode]}
                 WindowKeyPressFcn: []
               WindowKeyReleaseFcn: []
              WindowScrollWheelFcn: {@localButtonWheelFcn  [1x1 matlab.uitools.internal.uimode]}
                     KeyReleaseFcn: []
                       KeyPressFcn: {@localKeyPressFcn  [1x1 matlab.uitools.internal.uimode]}
                      ModeStartFcn: {@localStartZoom  [1x1 matlab.uitools.internal.uimode]}
                       ModeStopFcn: {@localStopZoom  [1x1 matlab.uitools.internal.uimode]}
                  ButtonDownFilter: []
                     UIContextMenu: []
                     ModeStateData: [1x1 struct]
                WindowFocusLostFcn: []
          UIControlSuspendListener: [1x1 event.listener]
      UIControlSuspendJavaListener: [1x1 handle.listener]
                   UserButtonUpFcn: []
               PreviousWindowState: []
                 ActionPreCallback: []
                ActionPostCallback: []
           WindowMotionFcnListener: [1x1 event.listener]
                       FigureState: [1x1 struct]
                        ParentMode: []
                     DefaultUIMode: ''
             CanvasContainerHandle: []
                            Enable: 'on'

 
Related posts:
  1. Matlab callbacks for Java events Events raised in Java code can be caught and handled in Matlab callback functions - this article explains how...
  2. uisplittool & uitogglesplittool callbacks Matlab's undocumented uisplittool and uitogglesplittool are powerful toolbar controls - this article explains how to customize their behavior...
  3. Determining axes zoom state The information of whether or not an axes is zoomed or panned can easily be inferred from an internal undocumented object....
  4. Removing user preferences from deployed apps An unsupported MathWorks Technical Solution explains how to remove private information from deployed (compiled) matlab applications. ...
 

Figure keypress modifiers

$
0
0

Matlab figures have a documented property called SelectionType that returns information about keypress modifiers such as or that were pressed during mouse clicks. Using this property has several drawbacks IMHO:

  • The reported SelectionType value is 'extend' for shift-clicks and 'alt' for ctrl-clicks, not very intuitive.
  • There is no support for alt-clicks, which are reported as regular ('normal') mouse clicks. In fact, 'alt' is reported for ctrl-clicks rather than for alt-clicks, which is very confusing.
  • There is no support for modifier combinations such as ctrl+shift-click. These again are reported as regular ('normal') mouse clicks.
  • SelectionType is only updated for mouse clicks, not for keyboard clicks. This again is very confusing. To extract the keypress modifier for key-click events we need to get the Modifier property of the key-press event, and this returns a cell-array of strings (e.g., {'shift','control','alt'}). Note that in this case, unlike SelectionType, the modifier names are as expected, alt-clicks is recognised and so are modifier combinations.
% Documented: we need to get the modifier data in two different manners
set(gcf, 'WindowButtonDownFcn', @(h,e) disp(get(gcf,'SelectionType')));  % mouse clicks: displays a single string: 'normal','alt','extend' or 'open'
set(gcf, 'WindowKeyPressFcn',   @(h,e) disp(e.Modifier));  % keyboard clicks: displays a cell-array of strings, e.g. {'shift','control','alt'}

The inconsistency between the functionality for mouse and keyboard clicks, and the limitations of the SelectionType property, are striking and most annoying. Some might say that it’s been like this for the past 2 decades so Matlab users have probably gotten used to it by now. But I must admit that after over 2 decades with Matlab I still need to refer to the documentation to figure out the correct behavior. Maybe that’s because I’m getting old, or maybe it means that the behavior is indeed not as intuitive as one could hope for.

For this reason, I was very happy to discover several years ago that there was a much simpler, easier and consistent solution, although (alas) undocumented. The trick is to simply query the undocumented hidden figure property CurrentModifier: CurrentModifier is updated during both mouse and keyboard clicks, in the same consistent manner, in both cases returning the same cell-array of strings as the Modifier property of the standard key-press event:

% Undocumented: the following displays a cell-array of strings having a consistent format, e.g. {'shift','control','alt'}
set(gcf, 'WindowButtonDownFcn', @(h,e) disp(get(gcf,'CurrentModifier')));  % mouse clicks
set(gcf, 'WindowKeyPressFcn',   @(h,e) disp(get(gcf,'CurrentModifier')));  % keyboard clicks

Checking whether any modifier was pressed becomes trivial:

modifiers = get(gcf,'CurrentModifier');
wasShiftPressed = ismember('shift',   modifiers);  % true/false
wasCtrlPressed  = ismember('control', modifiers);  % true/false
wasAltPressed   = ismember('alt',     modifiers);  % true/false

Hurrah for simplicity and consistency!

Note that despite the fact that CurrentModifier is hidden and undocumented, it has existed as-is for many years, and even survived (unchanged) the major transition from HG1 to HG2 in R2014b. This has to mean that MathWorks recognized the importance of CurrentModifier and took the deliberate decision (and associate dev effort) to preserve it. So why wasn’t this useful property made documented ages ago, or at the very least at the HG2 transition point? I don’t have a good answer to this riddle.

 
Related posts:
  1. Minimize/maximize figure window Matlab figure windows can easily be maximized, minimized and restored using a bit of undocumented magic powder...
  2. Customizing figure toolbar background Setting the figure toolbar's background color can easily be done using just a tiny bit of Java magic powder. This article explains how. ...
  3. Blurred Matlab figure window Matlab figure windows can be blurred using a semi-transparent overlaid window - this article explains how...
  4. uicontrol side-effect: removing figure toolbar Matlab's built-in uicontrol function has a side-effect of removing the figure toolbar. This was undocumented until lately. This article describes the side-effect behavior and how to fix it....
 
Viewing all 219 articles
Browse latest View live