Posts Tagged ‘Hidden property’

Matlab’s HG2 mechanism

Friday, May 7th, 2010

A few days ago I posted a lengthy article about Matlab’s undocumented feature function. In it, I mentioned a feature called HG2, that I believe merits a dedicated article, due to its potential high impact on future Matlab releases.

HG2, which presumably stands for “Handle Graphics 2nd generation”, was already reported in the past as an undocumented hidden figure property (UseHG2). In normal Matlab usage, this boolean property is ‘off’:

>> get(gcf,'usehg2')
ans =
off

HG2 is mentioned in quite a few Matlab files:

  • clf.m, hgload.m, ishg2figure.m, datetick.m, linkdata.m, linkplotfunc.m, cameratoolbar, /bin/registry/handle_graphics.xml, /ja/xlate and many more
  • uimodemanager.m (and others) temporarily disables a ‘MATLAB:handle:hg2′ warning
  • defaulterrorcallback.m mentions ‘MATLAB:HG2:SceneNode’ and ‘MATLAB:HG2:Property’
  • getplotbrowserproptable.m mentions several special HG2 types (hg2.Line, hg2.Lineseries, hg2.Patch etc.)
  • There’s even a dedicated /toolbox/matlab/graphics/private/ishg2figure.m function that determines whether a figure contains any HG2 graphics based on the existence of ‘hg2peer’ appdata (getappdata(fig,’hg2peer’)).
  • /toolbox/matlab/plottools/@objutil/@eventmanager/schema.m (and a few others) has the following comment:
     % may contain either UDD or MCOS listeners during the hg2 migration.

Obviously, much effort was invested in HG2 functionality. The fact that HG2 has been under development at least since 2007 (when I first discovered and reported it) seems to indicate a major upheaval in Matlab’s Handle Graphics mechanism. This hunch is reinforced by cryptic comments made by MathWorks personnel over the past few years that they are indeed looking at the HG system, which in their opinion is nearing its limitations. Perhaps I’m mixing unrelated stuff here, but it does make sense in light of Matlab’s push of its OOP class system over the past few releases.

To preview this HG2 system, we need to turn it on. Unfortunately, when we set the figure’s UseHG2 to ‘on’ there doesn’t seem to be any visible effect. However, this changes after we use the corresponding ‘UseHG2′ feature using the feature function (this caused lots of nasty-looking errors in past releases but works ok in R2010a):

>> feature('usehg2',1)

The /ja/xlate file (which is used in conjunction with the undocumented xlate function to translates Matlab messages from English to Japanese) has another key to unlocking HG2: This file contains the following message: “feature(‘useGBT2′) is only available when Matlab is started with -hgVersion 2 option.“. So let’s do as the xlate message advises and start a new Matlab session with the undocumented “-hgVersion 2″ command-line option. Now feature(‘usehg2′) is true by default and we can test the HG2 system.

Matlab looks basically the same in HG2 as in HG1. All the regular graphic functions behave just as we would expect from the existing (HG1) implementation. There are two major differences though:

  • the figure toolbars/menubars are missing and cannot be shown, even when the relevant figure properties are set. Without a menubar and toobar, Matlab figures are extremely less useful than their HG1 counterparts. This problem does not occur in HG2-enabled figures in the regular Matlab session (i.e., without using the “-hgVersion 2″ command-line option)
  • all the HG handles are now Matlab class handles rather than numeric values (These class handles are similar to those returned today (in HG1) using the undocumented handle function). There’s an exception to this rule: in regular Matlab sessions (i.e., without using the “-hgVersion 2″ command-line option), after setting the ‘UseHG2′ feature on, the returned figure handle is numeric rather than a class handle (but if you now plot within this figure you get the class object handles). Here’s the output from the “-hgVersion 2″ Matlab session:
    >> hFig = figure
    hFig = 
    	ui.Figure
     
    >> hLine = plot(1:5)
    hLine = 
    	hg2.Lineseries
     
    >> get(hLine,'Parent')
    ans = 
    	hg2.Axes
     
    >> findprop(gcf,'Tag')
    ans = 
      meta.property handle
      Package: meta
     
      Properties:
                       Name: 'Tag'
                Description: 'Tag PropInfo'
        DetailedDescription: ''
                  GetAccess: 'public'
                  SetAccess: 'public'
                  Dependent: 1
                   Constant: 0
                   Abstract: 0
                  Transient: 0
                     Hidden: 0
              GetObservable: 1
              SetObservable: 1
                   AbortSet: 0
                  GetMethod: []
                  SetMethod: []
                 HasDefault: 0
              DefiningClass: [1x1 meta.class]
      Methods, Events, Superclasses
     
    >> methods(gcf)
     
    Methods for class ui.Figure:
     
    Figure                  disp                    get                     horzcat                 lt                      subsasgn                
    addlistener             double                  getParentImpl           ishghandlewithargs      ne                      vertcat                 
    addprop                 eq                      getSceneViewer          ishghandlewoargs        notify                  
    applydefaultproperties  findobj                 getdisp                 isvalid                 reset                   
    cat                     findprop                gt                      java                    set                     
    delete                  ge                      hgclose                 le                      setdisp                 
     
    Static methods:
     
    getDefaultObject        
     
    >> methods(gcf,'-full')
     
    Methods for class ui.Figure:
     
    ui.Figure lhs1 Figure(rhs0)
    event.listener L addlistener(handle sources, char vector eventname, function_handle scalar callback)  % Inherited from hg2utils.HGHandle
    event.proplistener L addlistener(handle sources, meta.property propertyname, char vector eventname, function_handle scalar callback)  % Inherited from hg2utils.HGHandle
    event.proplistener L addlistener(handle sources, string propertyname, char vector eventname, function_handle scalar callback)  % Inherited from hg2utils.HGHandle
    event.proplistener L addlistener(handle sources, cell propertyname, char vector eventname, function_handle scalar callback)  % Inherited from hg2utils.HGHandle
    meta.property prop addprop(handle scalar object, string propname)  % Inherited from dynamicprops
    applydefaultproperties(HGHandle object, rhs1)  % Inherited from hg2utils.HGHandle
    HeterogeneousHandle lhs3 cat(double rhs0, rhs1, rhs2)  % Inherited from HeterogeneousHandle
    delete(handle obj)  % Inherited from handle
    disp(object)  % Inherited from hg2utils.HGHandle
    lhs1 double(handle object)  % Inherited from hg2utils.HGHandle
    logical TF eq(A, B)  % Inherited from hg2utils.HGHandle
    handle output findobj(handle object, varargin)  % Inherited from hg2utils.HGHandle
    meta.property prop findprop(handle scalar object, string propname)  % Inherited from handle
    logical TF ge(A, B)  % Inherited from handle
    varargout get(hgsetget object, rhs1)  % Inherited from hg2utils.HGHandle
    Static HeterogeneousHandle lhs0 getDefaultObject  % Inherited from hg2utils.HGHandle
    lhs2 getParentImpl(handle scalar object, rhs1)  % Inherited from hg2utils.HGObject
    lhs2 getSceneViewer(handle scalar object, rhs1)  % Inherited from ui.UISceneViewerParent
    getdisp(hgsetget rhs0)  % Inherited from hgsetget
    logical TF gt(A, B)  % Inherited from handle
    hgclose(handle scalar object)
    HeterogeneousHandle lhs2 horzcat(rhs0, rhs1)  % Inherited from HeterogeneousHandle
    lhs2 ishghandlewithargs(handle scalar object, rhs1)  % Inherited from hg2utils.HGObject
    lhs1 ishghandlewoargs(handle scalar object)  % Inherited from hg2utils.HGObject
    logical validity isvalid(handle obj)  % Inherited from handle
    j java(JavaVisible scalar h)  % Inherited from JavaVisible
    logical TF le(A, B)  % Inherited from handle
    logical TF lt(A, B)  % Inherited from handle
    logical TF ne(A, B)  % Inherited from hg2utils.HGHandle
    notify(handle sources, string eventname, event.EventData scalar eventdata)  % Inherited from handle
    notify(handle sources, string eventname)  % Inherited from handle
    reset(handle scalar object)  % Inherited from hg2utils.HGHandle
    varargout set(hgsetget object, rhs1)  % Inherited from hg2utils.HGHandle
    setdisp(hgsetget rhs0)  % Inherited from hgsetget
    varargout subsasgn(rhs0, rhs1, rhs2, rhs3)  % Inherited from HeterogeneousHandle
    HeterogeneousHandle lhs2 vertcat(rhs0, rhs1)  % Inherited from HeterogeneousHandle

The latest Matlab releases have shown how the Matlab handle class can be extended using user-created derived classes. It stands to reason that so do all the new HG2 objects. This would theoretically enable Matlab programmers to customize graphic objects appearance to suit their needs in a more intuitive manner than possible using HG1.

Many mysteries remain:

  • is it possible to mix HG1 and HG2 objects in the same figure?
  • can we switch between HG1 and HG2 in the same Matlab session (I got some crashes…)?
  • why is there a need for the separate feature options ‘UseHG2′, ‘UseGBT2′ and ‘HGUsingMatlabClasses’?
  • why is there a need for “-hgVersion 2″ Matlab sessions if we can simply use feature(‘UseHG2′)?
  • is it possible to restore the figure menubar and toolbar in “-hgVersion 2″ Matlab sessions?
  • is it indeed possible to extend HG2 objects using user-defined classes? and if so, can we modify the appearance/behavior beyond what is available in the existing list of HG2 properties?
  • beyond changing numeric handles into class handles, are there any actual benefits to the HG2 system over HG1?
  • what is the difference between HG2, GBT2 and GBT1.5 (which are mentioned together as separate entities in cameratoolbar.m)?

HG2 is still buggy, which explains why it is still not officially released. For example, the inspect(gca) function crashes Matlab, figure toolbars/menubars are missing, and some properties that are available in HG1 are missing in HG2. Also, we can add Java components to a Matlab figure using javacomponent as in HG1 (the returned container handles is a ui.HGJavaComponent class handle), but we get an error when we close the figure…

Still, with all this effort invested into HG2 I believe that it is only a matter of time before HG2 becomes officially released. This could happen perhaps even as soon as the upcoming R2010b release, but with the current state as seen above I suspect it will not happen before 2011. Also, my gut feeling is that Matlab will define any release that includes HG2 as a major release and we will finally have Matlab 8.0.

I would dearly love to hear any further information anyone discovers about HG2 and related issues. Please share your findings by email or in the comments section below.

Plot LimInclude properties

Wednesday, March 31st, 2010

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

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

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

Regular plot (YLimInclude on)

Regular plot (YLimInclude on)

This situation is quickly fixed using the YLimInclude property:

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

YLimInclude off

YLimInclude off

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

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

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

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

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

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

Axes LooseInset property

Wednesday, March 24th, 2010

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

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

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

Axes with default LooseInset values (note the excessive margins)

Axes with default LooseInset values
(note the excessive margins)

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

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

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

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

Axes with empty LooseInset values

Axes with empty LooseInset values

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

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

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

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

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

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

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

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

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

Plot LineSmoothing property

Wednesday, March 17th, 2010

I have already written about several undocumented hidden properties in the past. Today, I would like to introduce one of my favorites: the plot-line’s LineSmoothing property. Compare the following two outputs:

% Standard (non-smoothed) plot-line
plot(1:5,2:6,'o-', 'LineWidth',1);

Standard plot line (not anti-aliased)

Standard plot line (not anti-aliased)

% Smoothed (anti-aliased) plot line
plot(1:5,2:6,'o-', 'LineWidth',1, 'LineSmoothing','on');

Anti-aliased (smoothed) plot line

Anti-aliased (smoothed) plot line

Line smoothing (aka anti-aliasing) works by inserting semi-transparent pixels at the edges of the actual plot line, thereby giving an optical illusion of a smooth line without pixelization effects. In Matlab, antialiasing is done automatically for fonts, but unfortunately not for plot lines that have non-default line-widths.

Line-smoothing has been around for a long time. It was even mentioned in a user comment on the official MathWorks Pick-of-the-Week article that introduced the excellent Myaa utility (Myaa uses applicative Matlab code to create anti-aliased plot effects).

However, to this day (R2010a), the LineSmoothing property remains hidden, undocumented and not officially supported.

Perhaps the reason for this is the following bug: text objects that cross a smoothed line are obscured by it. Depending on the text size and the line width, the text might be completely hidden, although its handle indicates that it is visible and despite it being created after the plot line!

plot(1:5,2:6,'.-', 'LineWidth',5, 'LineSmoothing','on');
text(2.2,3.5, 'abcd','Color','r');

Smoothed line obscuring text

Smoothed line obscuring text

Note that this does not happen for standard (non-smoothed) lines:

plot(1:5,2:6,'.-', 'LineWidth',5);
text(2.2,3.5, 'abcd','Color','r');

Non-smoothed line does NOT obscure text

Non-smoothed line does NOT obscure text

Luckily, there’s a very simple workaround for this, that allows both line-smoothing and non-obstruction: simply set the text’s z-position to a higher value than the plot line’s. In our example, we used a simple 2D plot line (i.e., z-position = 0), so let’s set z-position=1 for our text label:

plot(1:5,2:6,'.-', 'LineWidth',5, 'LineSmoothing','on');
text(2.2,3.5,1, 'abcd','Color','r');

Smoothed line not obscuring text

Smoothed line not obscuring text

One final note: the LineSmoothing property also exists for line, patch, surf, mesh and other similar objects.

Do you use have any other favorite undocumented/hidden property? If so, please share it in a comment below.

Inactive Control Tooltips & Event Chaining

Wednesday, February 24th, 2010

Once again, I welcome guest blogger Matt Whitaker, who continues his series of articles.

In my last post I explored some tips on tooltips. One of these tips involved displaying tooltips on disabled uicontrols. I explained that displaying tooltips on inactive controls is problematic since Matlab appears to intercept mouse events to these inactive controls, so even setting the tooltip on the underlying Java object will not work: The java object appears not to receive the mouse-hover event and therefore does not “know” that it’s time to display the tooltip.

When Yair and I deliberated this issue, he pointed me to his comment on a previous article showing an undocumented Java technique (Java also has some…) for forcing a tooltip to appear using the ActionMap of the uicontrol’s underlying Java object to get at a postTip action. We discussed using a WindowButtonMotionFcn callback to see if the mouse was above the inactive control, then triggering the forced tooltip display. Yair then went on to remind me and I quote: “you’ll need to chain existing WindowButtonMotionFcn callbacks and take into account ModeManagers that override them.”

Frankly, having written code previously that handles callback chaining, I would rather poke myself in the eye with a fork!

The Image Processing Toolbox has the nice pair of iptaddcallback and iptremovecallback functions that largely handle these issues. But for general Matlab, there seemed to be no alternative until I remembered that events trigger callbacks. I decided to use a listener for the WindowButtonMotion event to detect the mouse motion. Event listeners were briefly explained two weeks ago and deserve a dedicated future article. The advantage of using an event listener is that we don’t disturb any existing WindowButtonMotionFcn callback. We still need to be somewhat careful that our listeners don’t do conflicting things, but it’s a lot easier than trying to manage everything through the single WindowButtonMotionFcn.

A demonstration of this appears below with some comments following (note that this code uses the FindJObj utility):

function inactiveBtnToolTip
  %Illustrates how to make a tooltip appear on an inactive control
  h = figure('WindowButtonMotionFcn',@windowMotion,'Pos',[400,400,200,200]);
  col = get(h,'color');
  lbl = uicontrol('Style','text', 'Pos',[10,160,120,20], ...
                  'Background',col, 'HorizontalAlignment','left');
  btn = uicontrol('Parent',h, 'String','Button', ...
                  'Enable','inactive', 'Pos',[10,40,60,20]);
  uicontrol('Style','check', 'Parent',h, 'String','Enable button tooltip', ...
            'Callback',@chkTooltipEnable, 'Value',1, ...
            'Pos',[10,80,180,20], 'Background',col);
  drawnow;
 
  %create the tooltip and postTip action
  jBtn = findjobj(btn);
  import java.awt.event.ActionEvent;
  javaMethodEDT('setToolTipText',jBtn,'This button is inactive');
  actionMap = javaMethodEDT('getActionMap',jBtn);
  action = javaMethodEDT('get',actionMap,'postTip');
  actionEvent = ActionEvent(jBtn, ActionEvent.ACTION_PERFORMED, 'postTip');
 
  %get the extents plus 2 pixels of the control to compare to the mouse position
  btnPos = getpixelposition(btn)+[-2,-2,4,4]; %give a little band around the control
  left = btnPos(1);
  right = sum(btnPos([1,3]));
  btm = btnPos(2);
  top =  sum(btnPos([2,4]));
 
  % add a listener on mouse movement events
  tm = javax.swing.ToolTipManager.sharedInstance; %tooltip manager
  pointListener = handle.listener(h,'WindowButtonMotionEvent',@figMouseMove);
 
  %inControl is a flag to prevent multiple triggers of the postTip action
  %while mouse remains in the button
  inControl = false;
 
  function figMouseMove(src,evtData) %#ok
    %get the current point
    cPoint = evtData.CurrentPoint;
 
    if cPoint(1) >= left && cPoint(1) <= right &&...
       cPoint(2) >= btm  && cPoint(2) <= top
 
      if ~inControl %we just entered
        inControl = true;
        action.actionPerformed(actionEvent); %show the tooltip
      end %if
    else
      if inControl %we just existed
        inControl = false;
        %toggle to make it disappear when leaving button
        javaMethodEDT('setEnabled',tm,false);
        javaMethodEDT('setEnabled',tm,true);
      end %if
    end %if
  end %gpMouseMove
 
  function windowMotion(varargin)
    %illustrate that we can still do a regular window button motion callback
    set(lbl,'String',sprintf('Mouse position: %d, %d',get(h,'CurrentPoint')));
    drawnow;
  end %windowMotion
 
  function chkTooltipEnable(src,varargin)
    if get(src,'Value')
      set(pointListener,'Enable','on');
    else
      set(pointListener,'Enable','off');
    end %if
  end %chkTooltipEnable
end %inactiveBtnToolTip

Tooltip on an inactive button

Tooltip on an inactive button

Comments on the code:

  1. The code illustrates that we can successfully add an additional listener to listen for mouse motion events while still carrying out the original WindowButtonMotionFcn callback. This makes chaining callbacks much easier.
  2. The handle.listener object has an Enable property that we can use to temporarily turn the listener on and off. This can be seen in the chkTooltipEnable() callback for the check box in the code above. If we wanted to permanently remove the listener we would simply use delete(pointListener). Note that addlistener adds a hidden property to the object being listened to, so that the listener is tied to the object’s lifecycle. If you create a listener directly using handle.listener you are responsible for it’s disposition. Unfortunately, addlistener fails for HG handles on pre-R2009 Matlab releases, so we use handle.listener directly.
  3. The code illustrates a good practice when tracking rapidly firing events like mouse movement of handling reentry into the callback while it is still processing a previous callback. Here we use a flag called inControl to prevent the postTip action being continuously fired while the mouse remains in the control.
  4. I was unable to determine if there is any corresponding action for the postTip to dismiss tips so I resorted to using the ToolTipManager to toggle its own Enable property to cleanly hide the tooltip as the mouse leaves the control.

Each Matlab callback has an associated event with it. Some of the ones that might be immediately useful at the figure-level are WindowButtonDown, WindowButtonUp, WindowKeyPress, and WindowKeyRelease. They can all be accessed through handle.listener or addlistener as in the code above.

Unfortunately, events do not always have names that directly correspond to the callback names. In order to see the list of available events for a particular Matlab object, use the following code, which relies on another undocumented function – classhandle. Here we list the events for gcf:

>> get(get(classhandle(handle(gcf)),'Events'),'Name')
ans = 
    'SerializeEvent'
    'FigureUpdateEvent'
    'ResizeEvent'
    'WindowKeyReleaseEvent'
    'WindowKeyPressEvent'
    'WindowButtonUpEvent'
    'WindowButtonDownEvent'
    'WindowButtonMotionEvent'
    'WindowPostChangeEvent'
    'WindowPreChangeEvent'

Note that I have made extensive use of the javaMethodEDT function to execute Java methods that affect swing components on Swing’s Event Dispatch Thread. I plan to write about this and related functions in my next article.

Customizing print setup

Wednesday, November 25th, 2009

Last week, while consulting a client, I watched him use a Matlab application that processed data and presented the results in a figure window. I saw that he constantly needed to go to File/Print-Preview menu option to customize the figure’s print setup before being able to print. He would constantly click the “Fill Page” button, then go to the Color tab and set RGB rather than Black-and-White, and finally go to the Advanced tab to prevent printing UI controls. Only then would he actually print the figure using the menu (File/Print) or the toolbar Print button.

Print Preview window

Print Preview window

This is absurd, I thought to myself – there must be a better way. Unfortunately, Matlab only supports two documented ways to modify the print setup:

  • the print function enables setting print settings when actually printing the figure. It accepts a long list of optional parameters that specify a wide range of printing options. But if I want to allow users to print at their own time, using the default figure menu/toolbar, I need to separate the actions of (1) setting the print setup and (2) doing the actual printout action. Since print does both of these together, we can’t use it. Moreover, if we don’t call print, the setup remains at the default settings and the menu/toolbar printouts use this default setup.
  • the printopt.m file stores the user’s default print setup. This file can be modified (use the printopt function). However, it affects all Matlab printouts, and cannot be configured on a figure-by-figure basis.

Of course, lack of a documented method never stopped us before. Sure enough, after a short search I discovered the hidden potential of the undocumented/unsupported setprinttemplate function. This function, called internally by Matlab’s print-related functions, is responsible for setting the figure’s initial print setup. Once I had this key, unlocking the problem was easy. Here is the bottom line:

The figure’s default print setup is stored in the figure’s hidden ApplicationData property, accessible via the getappdata and setappdata functions or directly via get/set, as explained in a previous post. More importantly, the figure-specific setup is stored in another hidden property, PrintTemplate. Both of these setup data are stored in structure format, which is not available when a figure is first created, but only after printing or print-preview. Note that printtemplate.m contains detailed explanations about the meaning of some fields – to see them, simply display the file:

>> type printtemplate.m  % or: edit printtemplate.m

Unless we set PrintTemplate ourselves (or call print or printpreview to do this), printing the figure will use the default print setup. To set a non-standard setup, we just need to create the PrintTemplate structure with our non-default setup options. Matlab will then automatically use them when printing the figure. Here is a checklist for doing so:

  1. First, create a figure and get its default print setup data. Since this data is unavailable in newly-created figures, simply open the figure’s Print-Preview window without changing anything – this will create the missing print setup structure that we can retrieve:

    % Create a simple figure
    >> hFig = figure;  surf(peaks);
     
    % Open the print-preview window to create setup data
    >> printpreview(hFig);
     
    % Retrieve the original (default) print setup data
    >> oldSetup = get(hFig,'PrintTemplate')
    oldSetup = 
           VersionNumber: 2
                    Name: ''
               FrameName: ''
             DriverColor: 1
         AxesFreezeTicks: 0
               tickState: {}
        AxesFreezeLimits: 0
                limState: {}
                   Loose: 0
                    CMYK: 0
                  Append: 0
               Adobecset: 0
                 PrintUI: 1
                Renderer: 'auto'
          ResolutionMode: 'auto'
                     DPI: 0
                FileName: 'untitled'
             Destination: 'printer'
             PrintDriver: ''
               DebugMode: 0
              StyleSheet: 'default'
                FontName: ''
                FontSize: 0
            FontSizeType: 'screen'
               FontAngle: ''
              FontWeight: ''
               FontColor: ''
               LineWidth: 0
           LineWidthType: 'screen'
            LineMinWidth: 0
               LineStyle: ''
               LineColor: ''
            PrintActiveX: 0
               GrayScale: 0
                 BkColor: 'white'
                 FigSize: [14.8054083333333 11.10405625]
  2. Next, go to the File/Print-Preview menu option and modify the setup according to your specific needs, and retrieve the new (modified setup):
    >> newSetup = get(hFig,'PrintTemplate');
  3. Now compare the two structures and retrieve only the modified setup options. This can be done in several ways – I personally use the objdiff utility. In our case, we modified the DriverColor (B&W => color), FigSize (for “Fill page”), and PrintUI (for hiding UI controls) fields:
    >> objdiff(oldSetup,newSetup)
    ans = 
        DriverColor: {[0]  [1]}
            FigSize: {[14.8054083333333 11.10405625]  [2x1 double]}
            PrintUI: {[1]  [0]}
         StyleSheet: {'default'  'modified'}
           limState: {{}  ''}
          tickState: {{}  ''}
  4. Finally, use the undocumented printtemplate and setprinttemplate functions to prepare the default setup sub-structure, and override with the modified options that you have just discovered. Place this in the figure’s _OpeningFcn function (for GUIDE-generated figures) or in your figure’s initialization function (for non-GUIDE figures). For example, if we have a GUIDE-generated figure called “MyFig”, then place this code in the MyFig_OpeningFcn function in MyFig.m:
    function MyFig_OpeningFcn(hObject, eventdata, handles, varargin)
      ...
      % This was adapted from initprintexporttemplate.m
      pt = printtemplate;
      pt.StyleSheet = 'modified';
      pt.VersionNumber = 2;   % important (Note #1 below)
      pt.FigSize = [38.1, 21.0];
      pt.DriverColor = 1;
      pt.PrintUI = 0;
      % we must set the paper size *before* setprinttemplate
      set(hObject, 'PaperPositionMode','manual', ...
                   'PaperPosition',[0 0.5 29.5 20], ...
                   'PaperSize',[29.68 20.98], ...
                   'PaperType','A4');
      setprinttemplate(hObject, pt);
     
      % Choose default command line output for MyFig
      handles.output = hObject;
     
      % Update handles structure
      guidata(hObject, handles);

That’s all there is to it. So easy once we know how, isn’t it? The most annoying pain-in-the-so-and-so sometimes have simple solutions…

Note #1: it is very important to set pt.VersionNumber to 2, otherwise some modifications will not take effect.

Note #2: the internal implementation of printtemplate as well as the internal setup fields have changed between Matlab releases. These were often minor backward-compatible changes, but at least once this was a major change (VersionNumber 1=>2, I think around Matlab 7.2, but I’m not sure). Therefore, carefully test your code on the oldest release which is supposed to run it. Also, if you plan the code to run in future Matlab releases, you should note that the entire setup functionality might break without prior notice, since it is an internal unsupported implementation.

Customizing Matlab labels

Wednesday, November 11th, 2009

As I was deliberating the topic of my weekly article, a new CSSM newsreader thread arrived today to immediately conclude the debate: The CSSM poster asked how Matlab labels can be modified to display non-ASCII characters such as the ∀ or β math symbols.

As you may recall, unlike axes text labels that support Tex/Latex, and unlike other uicontrols like buttons or listboxes that support HTML, text labels (uicontrol(‘Style’,'text’,…)) do not support text formatting or special symbols.

In the above-mentioned thread, Matt Whitaker, a longstanding CSSM contributor and a Matlab-Java veteran gave a solution that shows how seemingly difficult questions sometimes have simple solutions right beneath our noses. His solution was to simply replace the uicontrol label with a Java JLabel:

%show the 'for all' and 'beta' symbols
labelStr = '<html>&#8704;&#946; <b>bold</b> <i><font color="red">label</html>';
jLabel = javaObjectEDT('javax.swing.JLabel',labelStr);
[hcomponent,hcontainer] = javacomponent(jLabel,[100,100,40,20],gcf);

Math symbols and HTML support in a Java JLabel

Math symbols and HTML support in a Java JLabel

Note that the standard Matlab text uicontrol itself is very limited in the amount of customization it supports, even when accessing its underlying Java object using the FindJObj utility. This underlying Java object is a com.mathworks.hg.peer.utils.MultilineLabel extension of Swing’s bland javax.swing.JComponent. In fact, aside from some font and color customizations (also available via the Matlab HG properties), the most useful properties that are accessible only via the Java object are few. These include Border, HorizontalAlignment, VerticalAlignment and LineWrap. This is a very short list compared to the long list of corresponding undocumented properties in the other uicontrols.

Customizing uiundo

Wednesday, November 4th, 2009

Last week I discussed uiundo – Matlab’s undocumented undo/redo manager. Today, I will show how this object can be customized for some specific needs. However, we first need to understand a little more about how uiundo works beneath the hood.

Matlab stores all of a figure’s undo/redo data in a hidden figure object, referenced by getappdata(hFig,’uitools_FigureToolManager’). This means that by default uiundo works at the figure level, rather than the application level or the GUI component level. If we wish to modify this default behavior, we need to programmatically inspect and filter the undo/redo actions stack based on the action source. Read below to see how this can be done.

The hidden uitools_FigureToolManager object, defined in %MATLABROOT%\toolbox\matlab\uitools\@uiundo\, uses a stack to store instances of the undo/redo cmd data structure introduced in last week’s post:

% Retrieve redo/undo object
undoObj = getappdata(hFig,'uitools_FigureToolManager');
if isempty(undoObj)
   undoObj = uitools.FigureToolManager(hFig);
   setappdata(hFig,'uitools_FigureToolManager',undoObj);
end
 
>> get(undoObj)
    CommandManager: [1x1 uiundo.CommandManager]
            Figure: [1x1 figure]
        UndoUIMenu: [1x1 uimenu]
        RedoUIMenu: [1x1 uimenu]

There are several interesting things we can do with this undoObj. First, let’s modify the main-menu items (I will discuss menu customization in more detail in another post):

% Modify the main menu item (similarly for redo/undo)
if ~isempty(undoObj.RedoUIMenu)
   undoObj.RedoUIMenu.Position =1; %default=2 (undo above redo)
   undoObj.RedoUIMenu.Enable = 'off';     % default='on'
   undoObj.RedoUIMenu.Checked = 'on';     % default='off'
   undoObj.RedoUIMenu.ForegroundColor = [1,0,0];  % =red
end
if ~isempty(undoObj.UndoUIMenu)
   undoObj.UndoUIMenu.Label = '<html><b><i>Undo action';
   % Note: &Undo underlines 'U' and adds a keyboard accelerator
   % but unfortunately only if the label is non-HTML ...
   undoObj.UndoUIMenu.Separator = 'on';   % default='off'
   undoObj.UndoUIMenu.Checked = 'on';     % default='off'
   undoObj.UndoUIMenu.ForegroundColor = 'blue'; % default=black
end

Menu before customization

Menu after customization

Figure menu before and after customization

Now, let’s take a look at undoObj’s CommandManager child (the Figure child object is simply handle(hFig), and so is not very interesting):

>> undoObj.CommandManager.get
             UndoStack: [13x1 uiundo.FunctionCommand]
             RedoStack: [1x1 uiundo.FunctionCommand]
    MaxUndoStackLength: []
               Verbose: []
 
>> undoObj.CommandManager.UndoStack(end).get
             Parent: []
       MCodeComment: []
               Name: 'slider update (0.48 to 0.38)'
           Function: @internal_update
           Varargin: {[53.0037841796875]  [0.38]  [1x1 double]}
    InverseFunction: @internal_update
    InverseVarargin: {[53.0037841796875]  [0.48]  [1x1 double]}

This looks familiar: In fact, it is exactly the cmd data structure being passed to the uiundo function, with the additional (apparently unused) properties Parent and MCodeComment. CommandManager’s UndoStack and RedoStack child objects contain all stored undo/redo actions such that the latest action is at the end of these arrays. In the snippet above, there are 13 undo-able actions, with the latest action in UndoStack(end). UndoStack and RedoStack have the same structure:

  • Name contains the action description (presented in the figure’s menu)
  • Function is the function handle that will be invoked if the action is redone
  • Varargin are the arguments passed to Function during redo
  • InverseFunction is the function handle that will be invoked if the action is undone
  • InverseVarargin are the arguments passed to InverseFunction during undo
  • Parent and MCodeComment – I could not determine what these are used for

We can inspect the latest undo/redo actions, without activating them, by using CommandManager’s peekundo() and peekredo() methods (which return empty [] if no undo/redo action is available):

>> undoObj.CommandManager.peekredo.get % first check if isempty
             Parent: []
       MCodeComment: []
               Name: 'slider update (0.38 to 0.28)'
           Function: @internal_update
           Varargin: {[53.0037841796875]  [0.28]  [1x1 double]}
    InverseFunction: @internal_update
    InverseVarargin: {[53.0037841796875]  [0.38]  [1x1 double]}
 
>> undoObj.CommandManager.peekundo.get
             Parent: []
       MCodeComment: []
               Name: 'slider update (0.48 to 0.38)'
           Function: @internal_update
           Varargin: {[53.0037841796875]  [0.38]  [1x1 double]}
    InverseFunction: @internal_update
    InverseVarargin: {[53.0037841796875]  [0.48]  [1x1 double]}
 
>> undoObj.CommandManager.peekundo.Name
ans =
slider update (0.48 to 0.38)

We can undo/redo the latest action (last element of the UndoStack/RedoStack) by invoking CommandManager’s undo()/redo() methods. This is actually what uiundo is doing behind the scenes when it is called with the ‘execUndo’ and ‘execRedo’ arguments:

undoObj.CommandManager.undo;
undoObj.CommandManager.redo;

We can clear the entire actions stack by using CommandManager’s empty() method. This can be useful, for example, after a ‘Save’ or ‘Apply’ operation in our GUI:

undoObj.CommandManager.empty;

If we set CommandManager’s Verbose property to any non-empty value, debug information is spilled onto the Command Window when new uiundo actions are added:

>> undoObj.CommandManager.Verbose = 1;
 
% now move the slider and see the debug info below:
internal_update(h_uicontrol, [0.48,], h_uicontrol); % Called by slider update (0.28 to 0.48)
internal_update(h_uicontrol, [0.58,], h_uicontrol); % Called by slider update (0.48 to 0.58)

Finally, CommandManager uses its MaxUndoStackLength property to limit the size of the undo/redo stacks. This property is defined as read-only in %matlabroot%\toolbox\matlab\uitools\@uiundo\@CommandManager\schema.m line #12, so if you wish to programmatically modify this property from its default value of empty (=unlimited), you will need to comment out that line.

Detecting window focus events

Wednesday, September 9th, 2009

A CSSM reader recently asked whether it is possible to detect window focus events (specifically, the focus-gain event) asynchronously, so that such events can trigger a callback without necessitating a polling thread to constantly monitor the windows state.

The user correctly mentioned the fact that although mouse-clicks within the window frame can be detected using the documented figure callback WindowButtonDownFcn, there are other methods by which a window can gain focus: keyboard (<Alt>-<Tab> on Windows, for example), clicking the window frame edge etc. These methods are all undetected by WindowButtonDownFcn.

This problem is, to the best of my knowledge, insoluble using standard documented Matlab. However, there is indeed a simple solution using undocumented/unsupported Matlab features. The solution relies on the fact that all Matlab windows are basically Java Swing objects, and these objects have dozens of standard callback hooks that can be utilized (Matlab only exposes a few callbacks). The list of standard Swing callbacks was detailed in my earlier article about uicontrol callbacks, which is also relevant for Java window frames.

In this specific case, we are interested in FocusGainedCallback. This callback is invoked for the figure Frame’s AxisComponent (a part of the Frame that will be explained in another article). For each of our monitored figure windows, we set this callback to a predefined Matlab function. We may also wish to set its companion FocusLostCallback.

Here’s the resulting code snippet (hFig is our Matlab figure handle):

% Prepare the figure
hFig = figure;  % etc. - prepare the figure
 
% Get the underlying Java reference
warning off MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame
jFig = get(hFig, 'JavaFrame');
jAxis = jFig.getAxisComponent;
 
% Set the focus event callback
set(jAxis,'FocusGainedCallback',{@myMatlabFunc,hFig});
% perhaps also set the FocusLostCallback here

Whenever any of the monitored figures now gets focus, by whichever means, the user-defined Matlab function myMatlabFunc() will be invoked. This function should be defined as follows:

function myMatlabFunc(jAxis, jEventData, hFig)
   % do whatever you wish with the event/hFig information
end

Extra input parameters can be added during callback setup and definition, as follows:

set(jAxis,'FocusLostCallback',{@myMatlabFunc,hFig,data1,data2})
...
function myMatlabFunc(jAxis, jEventData, hFig, data1, data2)
   % do whatever you wish with the event/hFig/data information
end

A very similar technique can detect other windowing events (maximization/minimization/movement etc.). Depending on the case, you may need to use jFig.fFigureClient.getWindow instead of jFig.getAxisComponent. The list of available callbacks for each of these objects can be seen using a simple set(jFig.getAxisComponent) command, or via my UIInspect or FindJObj utilities on the Matlab File Exchange.

Note that all this relies on the undocumented hidden figure property JavaFrame, which issues a standing warning (since Matlab release R2008a) of becoming obsolete in some future Matlab release. Since it worked so far, I have turned off this warning in the code above, but note that this code may well fail in some future Matlab version. If and when JavaFrame does become obsolete, be sure to look in this blog for workarounds…

Context-Sensitive Help

Wednesday, August 5th, 2009

A recent CSSM thread about implementing a system-wide GUI help system got me working on a post to present Matlab’s built-in hidden/unsupported mechanism for context-sensitive help. There are many different ways in which such a system can be implemented (read that thread for some ideas), so Matlab users are by no means limited to Matlab’s built-in implementation. However, the built-in system certainly merits consideration for its simplicity and usefulness.

We start with Matlab’s cshelp function (%matlabroot%\toolbox\matlab\uitools\cshelp.m). cshelp is semi-documented, meaning that it has a help section but no doc, online help or official support. This useful function was grandfathered (made obsolete) in Matlab 7.4 (R2007a) for an unknown reason and to my knowledge without any replacement. cshelp is entirely based on m-code (no hidden internal or Java code) and is surprisingly compact and readable.

cshelp basically attaches two new properties (CSHelpMode and CSHelpData) to the specified figure (this is done using the schema.prop mechanism which will be described in a separate post), temporarily disables all active uicontrols, modifies the figure’s WindowButtonDownFcn callback and sets the mouse cursor (using setptr – another semi-documented function) to an arrow with a question mark.

Clicking any object in the figure’s main area (beneath the toolbar), causes the modified WindowButtonDownFcn callback to run whatever is stored in the figure’s HelpFcn property (string, @function_handle or {@function_handle, params, …} format). Here is a simple example taken from CSSM (thanks Jérôme):

Hfcn = 'str=get(gco,''type''); title([''Type :'' str])';
set(gcf,'HelpFcn',Hfcn);
th = 0:0.314:2*pi;
plot(th,sin(th),'r-','linewidth',4);
uicontrol('units','normalized', 'position',[.45 .02 .1 .05]);
cshelp(gcf);
set(gcf,'CSHelpMode','on');

Simple context-sensitive help system

Simple context-sensitive help system

In order to exit CSHelp mode, the figure’s CSHelpMode property must be set to ‘off’. However, remember that all the figure’s uicontrols are disabled in CSHelp mode. Therefore, the user may use one or more of the following methods (other tactics are also possible, but the ones below seem intuitive):

  • Set the figure’s KeyPressFcn callback property to catch events (e.g., <ESC> key presses) and reset the CSHelpMode property from within the callback
  • Reset the CSHelpMode property at the end of the HelpFcn callback
  • Add a CS Help entry/exit option to the figure’s Help main menu
  • Add a CS Help entry/exit button to the figure toolbar

The following code sample implements all of these suggested tactics (the code to synchronize the states of the menu item and toolbar button is not presented):

% Set the <ESC> key press to exit CSHelp mode
keyFcn = ['if strcmp(get(gcbf,''CurrentKey''),''escape''), ' ...
             'set(gcbf,''CSHelpMode'',''off''); ' ...
          'end'];
set(gcf,'keyPressFcn',keyFcn);
 
% Exit CSHelp mode at the end of the CSHelp callback
helpFcn = 'title([''Type :'' get(gco,''type'')]); set(gcbf,''CSHelpMode'',''off'');';
set(gcf,'HelpFcn',helpFcn);
 
% Add a CSHelp button to the figure toolbar
% Note: retrieve the button icon from the CSHelp cursor icon
hToolbar = findall(allchild(gcf),'flat','type','uitoolbar');
oldPtr = getptr(gcf);
ptrData = setptr('help');
set(gcf, oldPtr{:});
icon(:,:,1) = ptrData{4}/2;  % Convert into RGB TrueColor icon
icon(:,:,2) = ptrData{4}/2;
icon(:,:,3) = ptrData{4}/2;
cbFcn = 'set(gcbf,''CSHelpMode'',get(gcbo,''state''))';
csName = 'Context-sensitive help';
uitoggletool(hToolbar,'CData',icon, 'ClickedCallback',cbFcn, 'TooltipString',csName);
 
% Add a CSHelp menu option to the Help main menu
% Note: unlike other main menus, the Help menu tag is empty, so
% ^^^^  findall(gcf,'tag','figMenuHelp') is empty... Therefore,
%       we find this menu by accessing the Help/About menu item
helpAbout = findall(gcf,'tag','figMenuHelpAbout');
helpMenu = get(helpAbout,'parent');
cbFcn = ['if strcmp(get(gcbo,''Checked''),''on''), ' ...
             'set(gcbo,''Checked'',''off''); ' ...
         'else, ' ...
             'set(gcbo,''Checked'',''on''); ' ...
         'end; ' ...
         'set(gcbf,''CSHelpMode'',get(gcbo,''checked''))'];
uimenu(helpMenu,'Label',csName,'Callback',cbFcn,'Separator','on');

Figure with context-sensitive help action in the main toolbar & menu

Figure with context-sensitive help action in the main toolbar & menu

cshelp has an additional optional argument, accepting another figure handle. This handle, if specified and valid, indicates a parent figure whose CSHelpMode, HelpFcn and HelpTopicMap properties should be shared with this figure (this is done using the handle.listener mechanism which will be described in a separate post). This option is useful when creating a multi-window GUI-wide context-sensitive help system. The user may then activate context-sensitive help in figure A and select the requested context object in figure B.

cshelp would normally be coupled with Matlab’s help system for non-trivial GUI implementations. The undocumented and hidden properties HelpTopicKey (of all handles) and HelpTopicMap (of figures), enable easy tie-in to the CSHelp system. A simplified sample is presented below:

Hfcn=['helpview(get(gco,''HelpTopicKey''),''CSHelpWindow'');'...
      'set(gcbf,''CSHelpMode'',''off'');' ];
set(gcf,'HelpFcn',Hfcn);
th = 0:0.314:2*pi;
hLine = plot(th,sin(th),'r-','linewidth',4);
set(hLine,'HelpTopicKey','MyCSHelpFile.html#Line');
set(gca,  'HelpTopicKey','MyCSHelpFile.html#Axes');

cshelp is by no way limited to presenting Matlab documentation: Refer to helpview’s help section for an in-depth description of help maps and help topics. In a nutshell, helpview accepts any HTML webpage filepath (or webpage internal (#) reference), followed by optional parameter ‘CSHelpWindow’ (that indicates that the specified help page should be displayed in a stand-alone popup window rather than in the desktop’s standard Help tab), and optional extra parameters specifying the popup window’s figure handle and position. The webpage filepath parameter may be replaced by two string parameters, HelpTopicMap filepath and HelpTopicKey. Note that helpview itself is another semi-documented function.