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

Customizing contour plots

$
0
0

One of my clients asked me last week whether it is possible to access and customize individual contour lines and labels in HG2 (Matlab’s new graphics system, R2014+). Today’s post will discuss how this could indeed be done.

Matlab contour plot

Matlab contour plot

In HG1 (R2014a and earlier), contour handles were simple hggroup objects that incorporated text and patch child handles. The contour labels, lines and fill patches could easily be accessed via these child handles (contour lines and fills use the same patch object: the lines are simply the patch edges; fills are their faces). The lines could then be customized, the label strings changed, and the patch faces (fills) recolored:
[X,Y,Z] = peaks;
[C,hContour] = contour(X,Y,Z,20, 'ShowText','on');
hChildren = get(hContour, 'Children');
set(hChildren(1), 'String','Yair', 'Color','b');  % 1st text (contour label)
set(hChildren(end), 'EdgeColor',[0,1,1]);         % last patch (contour line)

The problem is that in HG2 (R2014b onward), contour (and its sibling functions, contourf etc.) return a graphic object that has no accessible children. In other words, hContour.Children returns an empty array:

>> hContour.Children
ans = 
  0x0 empty GraphicsPlaceholder array.
>> allchild(hContour)
ans = 
  0x0 empty GraphicsPlaceholder array.
>> isempty(hContour.Children)
ans =
     1

So how then can we access the internal contour patches and labels?

HG2′s contour object’s hidden properties

Skipping several fruitless dead-ends, it turns out that in HG2 the text labels, lines and fills are stored in undocumented hidden properties called TextPrims, EdgePrims and (surprise, surprise) FacePrims, which hold corresponding arrays of matlab.graphics.primitive.world.Text, matlab.graphics.primitive.world.LineStrip and matlab.graphics.primitive.world.TriangleStrip object handles (the drawnow part is also apparently very important, otherwise you might get errors due to the Prim objects not being ready by the time the code is reached):

>> drawnow;  % very important!
>> hContour.TextPrims  % row array of Text objects
ans = 
  1x41 Text array:
 
  Columns 1 through 14
    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text
  Columns 15 through 28
    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text
  Columns 29 through 41
    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text    Text
 
>> hContour.EdgePrims  % column array of LineStrip objects
ans = 
  20x1 LineStrip array:
 
  ineStrip
  LineStrip
  LineStrip
  ...
 
>> hContour.FacePrims  % column array of TriangleStrip objects (empty if no fill)
ans = 
  0x0 empty TriangleStrip array.

We can now access and customize the individual contour lines, labels and fills:

hContour.TextPrims(4).String = 'Dani';
hContour.TextPrims(7).Visible = 'off';
hContour.TextPrims(9).VertexData = single([-1.3; 0.5; 0]);  % Label location in data units
 
hContour.EdgePrims(2).ColorData = uint8([0;255;255;255]);  % opaque cyan
hContour.EdgePrims(5).Visible = 'off';

Note that the LineStrip objects here are the same as those used for the axes Axles, which I described a few months ago. Any customization that we could do to the axle LineStrips can also be applied to contour LineStrips, and vice versa.

For example, to achieve the appearance of a topographic map, we might want to modify some contour lines to use dotted LineStyle and other lines to appear bold by having larger LineWidth. Similarly, we may wish to hide some labels (by setting their Visible property to ‘off’) and make other labels bold (by setting their Font.Weight property to ‘bold’). There are really numerous customization possibilities here.

Here is a listing of the standard (non-hidden) properties exposed by these objects:

>> get(hContour.TextPrims(1))
        BackgroundColor: []
              ColorData: []
              EdgeColor: []
                   Font: [1x1 matlab.graphics.general.Font]
          FontSmoothing: 'on'
       HandleVisibility: 'on'
                HitTest: 'off'
    HorizontalAlignment: 'center'
            Interpreter: 'none'
                  Layer: 'middle'
              LineStyle: 'solid'
              LineWidth: 1
                 Margin: 1
                 Parent: [1x1 Contour]
          PickableParts: 'visible'
               Rotation: 7.24591082075548
                 String: '-5.1541'
          StringBinding: 'copy'
             VertexData: [3x1 single]
      VerticalAlignment: 'middle'
                Visible: 'on'
 
>> get(hContour.EdgePrims(1))
          AlignVertexCenters: 'off'
             AmbientStrength: 0.3
                ColorBinding: 'object'
                   ColorData: [4x1 uint8]
                   ColorType: 'truecolor'
             DiffuseStrength: 0.6
            HandleVisibility: 'on'
                     HitTest: 'off'
                       Layer: 'middle'
                     LineCap: 'none'
                    LineJoin: 'round'
                   LineStyle: 'solid'
                   LineWidth: 0.5
               NormalBinding: 'none'
                  NormalData: []
                      Parent: [1x1 Contour]
               PickableParts: 'visible'
    SpecularColorReflectance: 1
            SpecularExponent: 10
            SpecularStrength: 0.9
                   StripData: [1 18]
                     Texture: [0x0 GraphicsPlaceholder]
                  VertexData: [3x17 single]
               VertexIndices: []
                     Visible: 'on'
       WideLineRenderingHint: 'software'
 
>> get(hContour.FacePrims(1))
             AmbientStrength: 0.3
             BackFaceCulling: 'none'
                ColorBinding: 'object'
                   ColorData: [4x1 uint8]
                   ColorType: 'truecolor'
             DiffuseStrength: 0.6
            HandleVisibility: 'on'
                     HitTest: 'off'
                       Layer: 'middle'
               NormalBinding: 'none'
                  NormalData: []
                      Parent: [1x1 Contour]
               PickableParts: 'visible'
    SpecularColorReflectance: 1
            SpecularExponent: 10
            SpecularStrength: 0.9
                   StripData: [1 4 13 16 33 37 41 44 51 54 61 64 71 74 87 91 94 103]
                     Texture: [0x0 GraphicsPlaceholder]
            TwoSidedLighting: 'off'
                  VertexData: [3x102 single]
               VertexIndices: []
                     Visible: 'on'

But how did I know these properties existed? The easiest way in this case would be to use my getundoc utility, but we could also use my uiinspect utility or even the plain-ol’ struct function.

p.s. – there’s an alternative way, using the Java bean adapter that is associated with each Matlab graphics object: java(hContour). Specifically, this object apparent has the public method browseableChildren(java(hContour)) which returns the list of all children (in our case, 41 text labels [bean adapters], 20 lines, and a single object holding a ListOfPointsHighlight that corresponds to the regular hidden SelectionHandle property). However, I generally dislike working with the bean adapters, especially when there’s a much “cleaner” way to get these objects, in this case using the regular EdgePrims, FacePrims, TextPrims and SelectionHandle properties. Readers who are interested in Matlab internals can explore the bean adapters using a combination of my getundoc and uiinspect utilities.

So far for the easy part. Now for some more challenging questions:

Customizing the color

First, can we modify the contour fill to have a semi- (or fully-) transparent fill color? – indeed we can:

[~, hContour] = contourf(peaks(20), 10);
drawnow;  % this is important, to ensure that FacePrims is ready in the next line!
hFills = hContour.FacePrims;  % array of TriangleStrip objects
[hFills.ColorType] = deal('truecoloralpha');  % default = 'truecolor'
for idx = 1 : numel(hFills)
   hFills(idx).ColorData(4) = 150;   % default=255
end

Contour plot in HG2, with and without transparency

Contour plot in HG2, with and without transparency

Similar transparency effects can also be applied to the LineStrip and Text objects. A discussion of the various combinations of acceptable color properties can be found here.

Mouse clicks

Next, how can we set a custom context-menu for individual labels and contour lines?

Unfortunately, Text, LineStrip and TriangleStrip objects do not posses a ButtonDownFcn or UIContextMenu property, not even hidden. I tried searching in the internal/undocumented properties, but nothing came up.

Mouse click solution #1

So the next logical step would be to trap the mouse-click event at the contour object level. We cannot simply click the contour and check the clicked object because that would just give us the hContour object handle rather than the individual Text or LineStrip. So the idea would be to set hContour.HitTest='off', in the hope that the mouse click would be registered on the graphic object directly beneath the mouse cursor, namely the label or contour line. It turns out that the labels’ and lines’ HitTest property is ‘off’ by default, so, we also need to set them all to ‘on’:

hContour.HitTest = 'off';
[hContour.TextPrims.HitTest] = deal('on');
[hContour.EdgePrims.HitTest] = deal('on');
[hContour.FacePrims.HitTest] = deal('on');
hContour.ButtonDownFcn = @(h,e)disp(struct(e));

This seemed simple enough, but failed spectacularly: it turns out that because hContour.HitTest='off', mouse clicks are not registered on this objects, and on the other hand we cannot set the ButtonDownFcn on the primitive objects because they don’t have a ButtonDownFcn property!

Who said life is easy?

One workaround is to set the figure’s WindowButtonDownFcn property:

set(gcf, 'WindowButtonDownFcn', @myMouseClickCallback);

Now, inside your myMouseClickCallback function you can check the clicked object. We could use the undocumented builtin hittest(hFig) function to see which object was clicked. Alternatively, we could use the callback eventData‘s undocumented HitObject/HitPrimitive properties (this variant does not require the HitTest property modifications above):

function myMouseClickCallback(hFig, eventData)
   hitPrimitive = hittest(hFig);  % undocumented function
 
   hitObject    = eventData.HitObject;     % undocumented property => returns a Contour object (=hContour)
   hitPrimitive = eventData.HitPrimitive;  % undocumented property => returns a Text or LineStrip object
   hitPoint     = eventData.Point;         % undocumented property => returns [x,y] pixels from figure's bottom-left corner
 
   if strcmpi(hFig.SelectionType,'alt')  % right-click
      if isa(hitPrimitive, 'matlab.graphics.primitive.world.Text')  % label
         displayTextContextMenu(hitPrimitive, hitPoint)
      elseif isa(hitPrimitive, 'matlab.graphics.primitive.world.LineStrip')  % contour line
         displayLineContextMenu(hitPrimitive, hitPoint)
      elseif isa(hitPrimitive, 'matlab.graphics.primitive.world.TriangleStrip')  % contour fill
         displayFillContextMenu(hitPrimitive, hitPoint)
      else
         ...
      end
   end
end
Mouse click solution #2

A totally different solution is to keep the default hContour.HitTest='on' (and the primitives’ as ‘off’) and simply query the contour object’s ButtonDownFcn callback’s eventData‘s undocumented Primitive property:

hContour.ButtonDownFcn = @myMouseClickCallback;

And in the callback function:

function myMouseClickCallback(hContour, eventData)
   hitPrimitive = eventData.Primitive;  % undocumented property => returns a Text or LineStrip object
   hitPoint     = eventData.IntersectionPoint;  % [x,y,z] in data units
 
   hFig = ancestor(hContour, 'figure');
   if strcmpi(hFig.SelectionType,'alt')  % right-click
      if isa(hitPrimitive, 'matlab.graphics.primitive.world.Text')  % label
         displayTextContextMenu(hitPrimitive, hitPoint)
      elseif isa(hitPrimitive, 'matlab.graphics.primitive.world.LineStrip')  % contour line
         displayLineContextMenu(hitPrimitive, hitPoint)
      elseif isa(hitPrimitive, 'matlab.graphics.primitive.world.TriangleStrip')  % contour fill
         displayFillContextMenu(hitPrimitive, hitPoint)
      else
         ...
      end
   end
end

This article should be a good start in how to code the displayTextContextMenu etc. functions to display a context menu.

Customizations reset

Finally, there are apparently numerous things that cause our customized labels and lines to reset to their default appearance: resizing, updating contour properties etc. To update the labels in all these cases in one place, simply listen to the undocumented MarkedClean event:

addlistener(hContour, 'MarkedClean', @updateLabels);

Where updateLabels is a function were you set all the new labels.

Prediction about forward compatibility

I am marking this article as “High risk of breaking in future Matlab versions“, not because of the basic functionality (being important enough I don’t presume it will go away anytime soon) but because of the property names: TextPrims, EdgePrims and FacePrims don’t seem to be very user-friendly property names. So far MathWorks has been very diligent in making its object properties have meaningful names, and so I assume that when the time comes to expose these properties, they will be renamed (perhaps to TextHandles, EdgeHandles and FaceHandles, or perhaps LabelHandles, LineHandles and FillHandles). For this reason, even if you find out in some future Matlab release that TextPrims, EdgePrims and FacePrims don’t exist, perhaps they still exist and simply have different names.

 
Related posts:
  1. Customizing axes part 2 Matlab HG2 axes can be customized in many different ways. This article explains some of the undocumented aspects. ...
  2. Customizing axes rulers HG2 axes can be customized in numerous useful ways. This article explains how to customize the rulers. ...
  3. Customizing axes part 4 – additional properties Matlab HG2 axes can be customized in many different ways. This article explains some of the undocumented aspects. ...
  4. Customizing axes part 3 – Backdrop Matlab HG2 axes can be customized in many different ways. This article explains some of the undocumented aspects. ...
 

Solving a Matlab MCOS bug

$
0
0

A few days ago, one of my consulting clients asked me to help him with a very strange problem: he had a Matlab class having a constant property that holds a reference to some handle class object. The problem was that when he tried to modify the property’s inner values he got Matlab run-time errors because the inner value apparently remained unmodified!

Here is a distilled version of my client’s classes:

classdef (Abstract) MainClass
    properties (Constant)
        inner = InnerClass
    end
    methods (Static)
        function setInnerValue(newValue)
            MainClass.inner.value1 = newValue;
        end
    end
end
 
classdef InnerClass < handle
    properties
        value1
        value2
    end
end

And the strange run-time behavior:

>> MainClass.inner.value1 = 5
MainClass =
    inner: [1x1 struct]
 
>> MainClass.inner.value2  % causes a strange run-time error!
Reference to non-existent field 'value2'.
 
>> MainClass.inner.value1  % strange - value1 appears unmodified!
ans =
     []
 
>> MainClass.inner  % strange - value1 appears ok here, but where is value2 ?!
ans =
    value1: 5
 
>> MainClass.setInnerValue(7)  % another strange run-time error!
Reference to non-existent field 'setInnerValue'.
 
>> clear classes  % let's try it afresh...
>> MainClass.setInnerValue(7)  % looks ok, no error...
>> MainClass.inner   % strange - now we have both value1 & value2, but value1 is not updated!
ans =
  InnerClass with properties:
 
    value1: []
    value2: []
 
>> MainClass.inner.value1 = 9   % one last attempt, that also fails!
MainClass =
    inner: [1x1 struct]
 
>> MainClass.inner
ans =
  InnerClass with properties:
 
    value1: []
    value2: []
 
>> MainClass.inner.value1
ans =
     []

Understanding the buggy behavior

What the heck is going on here? did Matlab’s MCOS flip its lid somehow? Well, apparently not. It turns out that all these strange behaviors can be attributed to a single Matlab oddity (I call it a “bug”) in its class object system (MCOS) implementation. Understanding this oddity/bug then leads to a very simply workaround.

The underlying problem is that Matlab does not understand MainClass.inner.value1 to mean “the value1 property of the inner property of the MainClass class”. Matlab does understand MainClass.inner to mean “the inner property of the MainClass class”, but adding another dereferencing level (.value1) in the same Matlab expression is too complex for MCOS, and it does not properly understand it.

This being the case, Matlab’s internal interpreter reverts to the simplistic understanding that MainClass.inner.value1 means “the value1 field of the struct inner, which is itself a field of the outer struct named MainClass“. In fact, this creates a new struct variable named MainClass in our current workspace. Still, due to Matlab’s internal precedence rules, the MainClass class overshadows the new variable MainClass, and so when we try to read (as opposed to update) MainClass.inner we are actually referencing the inner reference handle of the MainClass class, rather than the corresponding field in the new struct. The reference handle’s value1 property remains unmodified because whenever we try to set MainClass.inner.value1 to any value, we’re just updating the struct variable in the local workspace.

Unfortunately, no run-time warning is issued to alert us of this. However, if we load MainClass.m in the Matlab editor, we get a somewhat-cryptic MLint warning that hints at this:

MLint warning about class object appearing as a struct

Confusing? indeed!

The workaround

Now that we understand the source of all the problems above, the solution is easy: help Matlab’s internal interpreter understand that we want to reference a property of the inner object reference. We do this by simply splitting the 3-element construct MainClass.inner.value1 into two parts, first storing innerObj = MainClass.inner in a temporary local variable (innerObj), then using it to access the internal innerObj.value1 property:

innerObj = MainClass.inner;
innerObj.value1 = 7;

Hopefully, in some future Matlab release, MCOS will be smarter than today and automatically handle multi-element MCOS constructs, as well as it currently does for 2-element ones (or multi-element Java/.Net/COM constructs).

Have you ever encountered any other Matlab bug that appears perplexing at first but has a very simple workaround as above? If so, then please share your findings in a comment below.

 
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. 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....
  3. Solving an mput (FTP) hang problem Matlab may hang when using passive FTP commands such as mput and dir. A simple workaround is available to fix this. ...
  4. Types of undocumented Matlab aspects This article lists the different types of undocumented/unsupported/hidden aspects in Matlab...
 

Programmatic shortcuts manipulation – part 1

$
0
0

User-defined shortcuts can interactively be added to the Matlab Desktop to enable easy access to often-used scripts (e.g., clearing the console, running a certain program, initializing data etc.). Similarly, we can place shortcuts in the help browser to quickly access often-used pages. Unfortunately, both of these shortcut functionalities, like many other functionalities of the Matlab Desktop and related tools (Editor, Browser, Profiler etc.), have no documented programmatic access.

Such programmatic access is often useful. For example, a large company for which I consult is using centralized updates to users’ shortcuts, in order to manage and expose new features for all Matlab users from a central location. It is easy to send updates and manage a few users, but when your organization has dozens of Matlab users, centralized management becomes a necessity. It’s a pity that companies need to resort to external consultants and undocumented hacks to achieve this, but I’m not complaining since it keeps me occupied…

Shortcuts in Matlab R2012a and earlier

Shortcuts in Matlab R2012a and earlier


Shortcuts in Matlab R2012b and newer

Shortcuts in Matlab R2012b and newer


Today’s post will describe “regular” shortcuts – those that are simple clickable buttons. Next week I will show how we can extend this to incorporate other types of shortcut controls, as well as some advanced customizations.

The shortcuts.xml file

It turns out that the shortcults toolbar (on R2012a and earlier) or toolstrip group (on R2012b onward) is a reflection of the contents of the [prefdir '\shortcuts.xml'] file (depending on your version, the file might be named somewhat differently, i.e. shortcuts_2.xml). This file can be edited in any text editor, Matlab’s editor included. So a very easy way to programmatically affect the shortcuts is to update this file. Here is a sample of this file:

<?xml version="1.0" encoding="utf-8"?>
<FAVORITESROOT version="2">
   <title>My Shortcuts</title>
   <FAVORITECATEGORY>
      <name>Help Browser Favorites</name>
      <FAVORITE>
         <label>Help Using the Desktop</label>
         <icon>Help icon</icon>
         <callback>helpview([docroot '/mapfiles/matlab_env.map'], 'matlabenvironment_desktop');</callback>
         <editable>true</editable>
      </FAVORITE>
   </FAVORITECATEGORY>
   <FAVORITE>
      <label>CSSM</label>
      <icon>Help icon</icon>
      <callback>disp('No callback specified for this shortcut')</callback>
      <editable>true</editable>
   </FAVORITE>
   <FAVORITE>
      <label>UndocML</label>
      <icon>MATLAB icon</icon>
      <callback>web('undocumentedMatlab.com')</callback>
      <editable>true</editable>
   </FAVORITE>
   <FAVORITE>
      <label>My favorite program</label>
      <icon>C:\Yair\program\icon.gif</icon>
      <callback>cd('C:\Yair\program'); myProgram(123);</callback>
      <editable>true</editable>
   </FAVORITE>
   ...
</FAVORITESROOT>

The file is only loaded once during Matlab startup, so any changes made to it will only take effect after Matlab restarts.

Updating the shortcuts in the current Matlab session

We can update the shortcuts directly, in the current Matlab session, using the builtin com.mathworks.mlwidgets.shortcuts.­ShortcutUtils class. This class has existed largely unchanged for numerous releases (at least as far back as R2008b).

For example, to add a new shortcut to the toolbar:

name = 'My New Shortcut';
cbstr = 'disp(''My New Shortcut'')';  % will be eval'ed when clicked
iconfile = 'c:\path\to\icon.gif';  % default icon if it is not found
isEditable = 'true';
scUtils = com.mathworks.mlwidgets.shortcuts.ShortcutUtils;
category = scUtils.getDefaultToolbarCategoryName;
scUtils.addShortcutToBottom(name,cbstr,iconfile,category,isEditable);

The shortcut’s icon can either be set to a specific icon filepath (e.g., ‘C:\Yair\program\icon.jpg’), or to one of the predefined names: ‘Help icon’, ‘Standard icon’, ‘MATLAB icon’ or ‘Simulink icon’. The editable parameter does not seem to have a visible effect that I could see.

The category name can either be set to the default name using scUtils.getDefaultToolbarCategoryName (‘Shortcuts’ on English-based Matlab R2012b onward), or it can be set to any other name (e.g., ‘My programs’). To add a shortcut to the Help Browser (also known as a “Favorite”), simply set the category to scUtils.getDefaultHelpCategoryName (=’Help Browser Favorites’ on English-based Matlab installations); to add the shortcut to the ‘Start’ button, set the category to ‘Shortcuts’. When you use a non-default category name on R2012a and earlier, you will only see the shortcuts via Matlab’s “Start” button (as seen in the screenshot below); on R2012b onward you will see it as a new category group within the Shortcuts toolstrip (as seen in the screenshot above). For example:

scUtils = com.mathworks.mlwidgets.shortcuts.ShortcutUtils;
scUtils.addShortcutToBottom('clear', 'clear; clc', 'Standard icon', 'Special commands', 'true');

Custom category in Matlab R2010a

Custom category in Matlab R2010a

To remove a shortcut, use the removeShortcut(category,shortcutName) method (note: this method does not complain if the specified shortcut does not exist):

scUtils.removeShortcut('Shortcuts', 'My New Shortcut');

The addShortcutToBottom() method does not override existing shortcuts. Therefore, to ensure that we don’t add duplicate shortcuts, we must first remove the possibly-existing shortcut using removeShortcut() before adding it. Since removeShortcut() does not complain if the specific shortcut is not found, we can safely use it without having to loop over all the existing shortcuts. Alternately, we could loop over all existing category shortcuts checking their label, and adding a new shortcut only if it is not already found, as follows:

scUtils = com.mathworks.mlwidgets.shortcuts.ShortcutUtils;
category = scUtils.getDefaultToolbarCategoryName; 
scVector = scUtils.getShortcutsByCategory(category);
scArray = scVector.toArray;  % Java array
foundFlag = 0;
for scIdx = 1:length(scArray)
   scName = char(scArray(scIdx));
   if strcmp(scName, 'My New Shortcut')
      foundFlag = 1; break;
      % alternatively: scUtils.removeShortcut(category, scName);
   end
end
if ~foundFlag
   scUtils.addShortcutToBottom(scName, callbackString, iconString, category, 'true');
end

As noted above, we can add categories by simply specifying a new category name in the call to scUtils.addShortcutToBottom(). We can also add and remove categories directly, as follows (beware: when removing a category, it is removed together with all its contents):

scUtils.addNewCategory('category name');
scUtils.removeShortcut('category name', []);  % entire category will be deleted

Shortcut tools on the Matlab File Exchange

Following my advice on StackOverflow back in 2010, Richie Cotton wrapped the code snippets above in a user-friendly utility (set of independent Matlab functions) that can now be found on the Matlab File Exchange and on his blog. Richie tested his toolbox on Matlab releases as old as R2008b, but the functionality may also work on even older releases.

Shortcuts panel embedded in Matlab GUI

Shortcuts are normally visible in the toolbar and the Matlab start menu (R2012a and earlier) or the Matlab Desktop’s toolstrip (R2012b onward). However, using com.mathworks.mlwidgets.shortcuts.ShortcutTreePanel, the schortcuts can also be displayed in any user GUI, complete with right-click context-menu:

jShortcuts = com.mathworks.mlwidgets.shortcuts.ShortcutTreePanel;
[jhShortcuts,hPanel] = javacomponent(jShortcuts, [10,10,300,200], gcf);

Shortcuts panel in Matlab figure GUI

Shortcuts panel in Matlab figure GUI

Stay tuned…

Next week I will expand the discussion of Matlab shortcuts with the following improvements:

  1. Displaying non-standard controls as shortcuts: checkboxes, drop-downs (combo-boxes) and toggle-buttons
  2. Customizing the shortcut tooltip (replacing the default tooltip that simply repeats the callback string)
  3. Customizing the shortcut callback (rather than using an eval-ed callback string)
  4. Enabling/disabling shortcuts in run-time

Merry Christmas everyone!

 
Related posts:
  1. Programmatic shortcuts manipulation – part 2 Non-standard shortcut controls and customizations can easily be added to the Matlab desktop. ...
  2. Customizing menu items part 3 Matlab menu items can easily display custom icons, using just a tiny bit of Java magic powder. ...
  3. JMI wrapper – local MatlabControl part 2 An example using matlabcontrol for calling Matlab from within a Java class is explained and discussed...
  4. JMI wrapper – local MatlabControl part 1 MatlabControl is an open-source wrapper of JMI that allows an easy and documented way to communicate from Java to Matlab. This article describes this wrapper....
 

Programmatic shortcuts manipulation – part 2

$
0
0

Today I will expand last week’s post on customizing Matlab Desktop’s shortcuts. I will show that we can incorporate non-standard controls, and add tooltips and user callbacks in undocumented ways that are not available using the interactive Desktop GUI.

Custom shortcut controls

Custom shortcut controls


Today’s article will focus on the new toolstrip interface of Matlab release R2012b and later; adaptation of the code to R2012a and earlier is relatively easy (in fact, simpler than the toolstrip-based code below).

Displaying the Shortcuts panel

Before we begin to modify shortcuts in the Toolstrip’s shortcuts menu, we need to ensure that the Shortcuts panel is visible and active (in current focus), otherwise our customizations will be ignored or cause an error. There is probably a more direct way of doing this, but a simple way that I found was to edit the current Desktop’s layout to include a directive to display the Shortcuts tab, and then load that layout:

jDesktop = com.mathworks.mde.desk.MLDesktop.getInstance;
hMainFrame = com.mathworks.mde.desk.MLDesktop.getInstance.getMainFrame;
jToolstrip = hMainFrame.getToolstrip;
isOk = jToolstrip.setCurrentTab('shortcuts');
if ~isOk  % i.e., Shortcuts tab is NOT displayed
    % Save the current Desktop layout
    jDesktop.saveLayout('Yair');  pause(0.15);
 
    % Update the layout file to display the Shortcuts tab
    filename = fullfile(prefdir, 'YairMATLABLayout.xml');
    fid = fopen(filename, 'rt');
    txt = fread(fid, '*char')';
    fclose(fid);
    txt = regexprep(txt,'(ShowShortcutsTab=)"[^"]*"','');
    txt = regexprep(txt,'(<Layout [^>]*)>','$1 ShowShortcutsTab="yes">');
    fid = fopen(filename, 'wt');
    fwrite(fid,txt);
    fclose(fid);
 
    % Load the modified layout
    jDesktop.restoreLayout('Yair');  pause(0.15);
 
    % The shortcuts tab should now be visible, so transfer focus to that tab
    jToolstrip.setCurrentTab('shortcuts');
end

Custom controls

As I explained in last week’s post, we can use scUtils.addShortcutToBottom to add a simple push-button shortcut to the relevant category panel within the Shortcuts toolstrip tab. To add custom controls, we can simply add the controls to the relevant shortcut category panel container (a com.mathworks.toolstrip.components.TSPanel object). The standard shortcuts are typically placed in the Shortcuts tab’s second TSPanel (“general”), and other categories have TSPanels of their own.

Now here’s the tricky part about TSPanels: we cannot directly add components to the sectino panel (that would be too easy…): the section panels are composed of an array of internal TSPanels, and we need to add the new controls to those internal panels. However, these panels only contain 3 empty slots. If we try to add more than 3 components, the 4th+ component(s) will simply not be displayed. In such cases, we need to create a new TSPanel to display the extra components.

Here then is some sample code to add a combo-box (drop-down) control:

% First, get the last internal TSPanel within the Shortcuts tab's "general" section panel
% Note: jToolstrip was defined in the previous section above
jShortcutsTab = jToolstrip.getModel.get('shortcuts').getComponent;
jSectionPanel = jShortcutsTab.getSectionComponent(1).getSection.getComponent;  % the TSPanel object "general"
jContainer = jSectionPanel.getComponent(jSectionPanel.getComponentCount-1);
 
% If the last internal TSPanel is full, then prepare a new internal TSPanel next to it
if jContainer.getComponentCount >= 3
    % Create a new empty TSPanel and add it to the right of the last internal TSPanel
    jContainer = com.mathworks.toolstrip.components.TSPanel;
    jContainer.setPreferredSize(java.awt.Dimension(100,72));
    jSectionPanel.add(jContainer);
    jSectionPanel.repaint();
    jSectionPanel.revalidate();
end
 
% Create the new control with a custom tooltip and callback function
optionStrings = {'Project A', 'Project B', 'Project C'};
jCombo = com.mathworks.toolstrip.components.TSComboBox(optionStrings);
jCombo = handle(javaObjectEDT(jCombo), 'callbackproperties'));
set(jCombo, 'ActionPerformedCallback', @myCallbackFunction);
jCombo.setToolTipText('Select the requested project');
 
% Now add the new control to the internal TSPanel
jContainer.add(jCombo);
jContainer.repaint();
jContainer.revalidate();

Custom shortcut controls

Custom shortcut controls

Matlab’s internal com.mathworks.toolstrip.components package contains many embeddable controls, including the following (I emphasized those that I think are most useful within the context of the Shortcuts panel): TSButton, TSCheckBox, TSComboBox, TSDropDownButton (a custom combo-box component), TSFormattedTextField, TSLabel, TSList, TSRadioButton, TSScrollPane, TSSlider, TSSpinner, TSSplitButton, TSTextArea, TSTextField, and TSToggleButton. These controls are in most cases simple wrappers of the corresponding Java Swing controls. For example, TSSpinner extends the standard Swing JSpinner control. In some cases, the controls are more complex: for example, the TSSplitButton is similar to Matlab’s uisplittool control.

Toolstrip controls

Toolstrip controls

In fact, these controls can be used even outside the toolstrip, embedded directly in our Matlab figure GUI, using the javacomponent function. For example:

dataModel = javax.swing.SpinnerNumberModel(125, 15, 225, 0.5);  % defaultValue, minValue, maxValue, stepSize
jSpinner = com.mathworks.toolstrip.components.TSSpinner(dataModel);
jSpinner = handle(javaObjectEDT(jSpinner), 'CallbackProperties');
[hjSpinner, hContainer] = javacomponent(jSpinner, [10,10,60,20], gcf);

You can find additional interesting components within the %matlabroot%/java/jar/toolstrip.jar file, which can be opened in any zip file utility or Java IDE. In fact, whatever controls that you see Matlab uses in its Desktop toolstrip (including galleries etc.) can be replicated in custom tabs, sections and panels of our own design.

Matlab Desktop’s interactive GUI only enables creating simple push-button shortcuts having string callbacks (that are eval‘ed in run-time). Using the undocumented programmatic interface that I just showed, we can include more sophisticated controls, as well as customize those controls in ways that are impossible via the programmatic GUI: add tooltips, set non-string (function-handle) callbacks, enable/disable controls, modify icons in run-time etc.

For example (intentionally showing two separate ways of setting the component properties):

% Toggle-button
jTB = handle(javaObjectEDT(com.mathworks.toolstrip.components.TSToggleButton('Toggle button')), 'CallbackProperties')
jTB.setSelected(true)
jTB.setToolTipText('toggle me!')
jTB.ActionPerformedCallback = @(h,e)doSomething();
jContainer.add(jTB);
 
% Check-box
jCB = handle(javaObjectEDT(com.mathworks.toolstrip.components.TSCheckBox('selected !')), 'CallbackProperties');
set(jCB, 'Selected', true, 'ToolTipText','Please select me!', 'ActionPerformedCallback',{@myCallbackFunction,extraData});
jContainer.add(jCB);

(resulting in the screenshot at the top of this post)

Important note: none of these customizations is saved to file. Therefore, they need to be redone programmatically for each separate Matlab session. You can easily do that by calling the relevant code in your startup.m file.

If you wish me to assist with any customization of the Desktop shortcuts, or any other Matlab aspect, then contact me for a short consultancy.

Happy New Year everybody!

 
Related posts:
  1. Programmatic shortcuts manipulation – part 1 Matlab Desktop shortcuts can be programmatically accessed and customized. ...
  2. JMI wrapper – local MatlabControl part 2 An example using matlabcontrol for calling Matlab from within a Java class is explained and discussed...
  3. JMI wrapper – local MatlabControl part 1 MatlabControl is an open-source wrapper of JMI that allows an easy and documented way to communicate from Java to Matlab. This article describes this wrapper....
  4. Customizing menu items part 2 Matlab menu items can be customized in a variety of useful ways using their underlying Java object. ...
 

Graphic sizing in Matlab R2015b

$
0
0

I would like to introduce Daniel Dolan of Sandia National Laboratories. Dan works on a variety of data analysis projects in Matlab, and is an active lurker on MATLAB Central. Dan has a habit of finding interesting bugs for the Mac version of Matlab. Today he will discuss graphic sizing in Matlab and important changes that occurred in release R2015b.

Matlab-generated graphics are often not displayed at their requested size. This problem has been known for some time and has a well-known solution: setting the root object’s ScreenPixelsPerInch property to the display’s actual DPI (dots per inch) value. Release R2015b no longer supports this solution, creating problems for publication graphics and general readability.

Physical sizing in R2015a vs. R2015b (click for full-size)

Physical sizing in R2015a vs. R2015b (click for full-size)


Physical sizing

Matlab supports graphic sizing in various physical units: inches, centimeters, and points. For example:

figure; axes('Box','on', 'Units','inches','Position',[0.3 0.3 4 4]);

requests to display an axes having square sizes measuring exactly 4″ (101.6 mm) each. It is evident, however, that the displayed axes is smaller than 4″. The mismatch between requested and physical size depends on the display and operating system — go ahead, try it on your system. The problem is particularly severe on Mac laptops, presumably even worse for those with Retina displays.

The problem is that Matlab cannot determine pixel size, which varies from one display to the other. Generating a figure spanning a particular number of pixels (e.g., 1024 x 768) is easy, but absolute physical units requires a conversion factor called ScreenPixelsPerInch, which is a root property (see related post on setting/getting default graphics property values):

DPI = 110;                             % dots per inch for my 27" Apple Cinema Display
set(0,    'ScreenPixelsPerInch',DPI);  % all releases prior to R2015b
set(groot,'ScreenPixelsPerInch',DPI);  % R2014b through R2015a

DPI values tend to be higher for laptops, usually in the 120-130 range. Retina displays are supposed to be >300 DPI, but I have not been able to test that myself.

There are several ways to determine the correct DPI setting for a particular display. It may be available in the hardware specifications, and it can be calculated from the diagonal size and the number of pixels. Unfortunately these methods are not always reliable. If you really care about physical sizing, the best approach is to actually calibrate your display. There are tools for doing this at Matlab Central, but it’s not hard to do manually:

  • Create a figure.
  • Manually resize the figure to match a convenient width. I often use a piece of US letter paper as 8.5″ guide on the display.
  • Determine the width of the figure in pixels:
    set(gcf,'Units','pixels');
    pos = get(gcf,'Position');
    width = 8.5; % inches
    DPI = pos(3) / width;

I usually apply the DPI settings in my startup file so that Matlab begins with a calibrated display.

What changed in 2015b?

ScreenPixelsPerInch is a read-only property in R2015b, so display calibration no longer works. The following sequence of commands:

figure('Units','inches', 'PaperPositionMode','auto', 'Position',[0 0 4 4]);
set(gcf, 'MenuBar','none', 'ToolBar','none', 'DockControls','off', 'NumberTitle','off');
axes('FontUnits','points', 'FontSize',10);
image

now renders differently in R2015b than does for a calibrated display in R2015a. Differences between the two outputs are shown in the screenshot at the top of this post. The grid behind the figures was rendered at 8.5″ x 8.5″ inches on my display; if your browser’s zoom level isn’t 100%, it may appear larger or smaller.

A side effect of improper graphic sizing is that text is difficult to read — the uncalibrated axes labels are clearly smaller than 10 points. These examples were rendered on ~110 DPI display. Matlab assumes that Macs use 72 DPI (96 DPI on Windows), so graphics appear at 65% of the request size.

The loss of ScreenPixelsPerInch as an adjustable setting strongly affects anyone using Matlab for publication graphics. Scientific and engineering journals are extremly strict about figure widths. With a calibrated screen, figure appear exactly as they will when printed to a file (usually EPS or PDF). Figures are often made as small as possible to and densely packed to save journal space, and accurate sized display helps the author determine legibility. Displaying accurately sized graphics is very difficult in R2015b, which is unfortunate given the many enhancements in this release.

Developers who create graphical interfaces for other users should also care about this change. A common complaint I get is that text and control labels is too small to easily read. Screen calibration deals with this problem, but this option is no longer available.

Where do we go from here?

I reported the above issues to the Mathworks several months ago. It does not appear as a formal bug, but technical support is aware of the problem. The change is part of the “DPI aware” nature of release R2015b. So far I have found no evidence this release is any more aware of pixel size than previous releases, but my experience is limited to non-Retina Macs. I welcome input from users on other operating systems, particularly those with high-resolution displays.

To be fair, correct physical sizing is not an easy across the many platforms that Matlab runs on. Display resolution is particularly tricky when it changes during a Matlab session, such as when computer is connector to projector/television or a laptop is connected to a docking station.

Thankfully, printed graphic sizes are rendered correctly when a figure’s PaperPositionMode property is 'auto'. Many users can (and will) ignore the display problem if they aren’t dealing with strict size requirements and text legibility isn’t too bad. Some users may be willing to periodically print publication figures to externally verify sizing, but this breaks the interactive nature of Matlab figures.

A potential work around is the creating of a new figure class that oversizes figures (as needed) to account for a particular display. I started working on such a class, but the problem is more complicated than one might think:

  • Child objects (axes, uicontrols, etc.) also must be resized if they are based on physical units.
  • Resized objects must be temporarily restored to their original size for printing, and new objects must be tracked whenever they are added.
  • Figure resolution may need to be changed when moving to different computer systems.

These capabilities are quite possible to implement, but this is a complicated solution to problem that was once easy to fix.

Physical accuracy may not be important for non-publication figures, but the issue of text legibility remains. Some text objects–such as axes and tick labels–can easily be resized because the parent axes automatically adjusts itself as needed. Free floating text objects and uincontrols are much more difficult to deal with. Controls are often sized around the extent of their text label, so changing font sizes may require changes to the control position; adjacent controls may overlap after resizing for text clarity. Normalized units partially solve this problem, but their effect on uicontrols is not always desirable: do you really want push buttons to get larger/smaller when the figure is resized?

Can you think of a better workaround to this problem? If so, then please post a comment below. I will be very happy to hear your ideas, as I’m sure others who have high resolution displays would as well.

(cross-reference: CSSM newsgroup post)

 
Related posts:
  1. Adding dynamic properties to graphic handles It is easy and very useful to attach dynamic properties to Matlab graphics objects in run-time. ...
  2. A couple of internal Matlab bugs and workarounds A couple of undocumented Matlab bugs have simple workarounds. ...
  3. 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....
  4. Blurred Matlab figure window Matlab figure windows can be blurred using a semi-transparent overlaid window - this article explains how...
 

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...
 

Graphic sizing in Matlab R2015b

$
0
0

I would like to introduce Daniel Dolan of Sandia National Laboratories. Dan works on a variety of data analysis projects in Matlab, and is an active lurker on MATLAB Central. Dan has a habit of finding interesting bugs for the Mac version of Matlab. Today he will discuss graphic sizing in Matlab and important changes that occurred in release R2015b.

Matlab-generated graphics are often not displayed at their requested size. This problem has been known for some time and has a well-known solution: setting the root object’s ScreenPixelsPerInch property to the display’s actual DPI (dots per inch) value. Release R2015b no longer supports this solution, creating problems for publication graphics and general readability.

Physical sizing in R2015a vs. R2015b (click for full-size)

Physical sizing in R2015a vs. R2015b (click for full-size)


Physical sizing

Matlab supports graphic sizing in various physical units: inches, centimeters, and points. For example:

figure; axes('Box','on', 'Units','inches','Position',[0.3 0.3 4 4]);

requests to display an axes having square sizes measuring exactly 4″ (101.6 mm) each. It is evident, however, that the displayed axes is smaller than 4″. The mismatch between requested and physical size depends on the display and operating system — go ahead, try it on your system. The problem is particularly severe on Mac laptops, presumably even worse for those with Retina displays.

The problem is that Matlab cannot determine pixel size, which varies from one display to the other. Generating a figure spanning a particular number of pixels (e.g., 1024 x 768) is easy, but absolute physical units requires a conversion factor called ScreenPixelsPerInch, which is a root property (see related post on setting/getting default graphics property values):

DPI = 110;                             % dots per inch for my 27" Apple Cinema Display
set(0,    'ScreenPixelsPerInch',DPI);  % all releases prior to R2015b
set(groot,'ScreenPixelsPerInch',DPI);  % R2014b through R2015a

DPI values tend to be higher for laptops, usually in the 120-130 range. Retina displays are supposed to be >300 DPI, but I have not been able to test that myself.

There are several ways to determine the correct DPI setting for a particular display. It may be available in the hardware specifications, and it can be calculated from the diagonal size and the number of pixels. Unfortunately these methods are not always reliable. If you really care about physical sizing, the best approach is to actually calibrate your display. There are tools for doing this at Matlab Central, but it’s not hard to do manually:

  • Create a figure.
  • Manually resize the figure to match a convenient width. I often use a piece of US letter paper as 8.5″ guide on the display.
  • Determine the width of the figure in pixels:
    set(gcf,'Units','pixels');
    pos = get(gcf,'Position');
    width = 8.5; % inches
    DPI = pos(3) / width;

I usually apply the DPI settings in my startup file so that Matlab begins with a calibrated display.

What changed in 2015b?

ScreenPixelsPerInch is a read-only property in R2015b, so display calibration no longer works. The following sequence of commands:

figure('Units','inches', 'PaperPositionMode','auto', 'Position',[0 0 4 4]);
set(gcf, 'MenuBar','none', 'ToolBar','none', 'DockControls','off', 'NumberTitle','off');
axes('FontUnits','points', 'FontSize',10);
image

now renders differently in R2015b than does for a calibrated display in R2015a. Differences between the two outputs are shown in the screenshot at the top of this post. The grid behind the figures was rendered at 8.5″ x 8.5″ inches on my display; if your browser’s zoom level isn’t 100%, it may appear larger or smaller.

A side effect of improper graphic sizing is that text is difficult to read — the uncalibrated axes labels are clearly smaller than 10 points. These examples were rendered on ~110 DPI display. Matlab assumes that Macs use 72 DPI (96 DPI on Windows), so graphics appear at 65% of the request size.

The loss of ScreenPixelsPerInch as an adjustable setting strongly affects anyone using Matlab for publication graphics. Scientific and engineering journals are extremly strict about figure widths. With a calibrated screen, figure appear exactly as they will when printed to a file (usually EPS or PDF). Figures are often made as small as possible to and densely packed to save journal space, and accurate sized display helps the author determine legibility. Displaying accurately sized graphics is very difficult in R2015b, which is unfortunate given the many enhancements in this release.

Developers who create graphical interfaces for other users should also care about this change. A common complaint I get is that text and control labels is too small to easily read. Screen calibration deals with this problem, but this option is no longer available.

Where do we go from here?

I reported the above issues to the Mathworks several months ago. It does not appear as a formal bug, but technical support is aware of the problem. The change is part of the “DPI aware” nature of release R2015b. So far I have found no evidence this release is any more aware of pixel size than previous releases, but my experience is limited to non-Retina Macs. I welcome input from users on other operating systems, particularly those with high-resolution displays.

To be fair, correct physical sizing is not an easy across the many platforms that Matlab runs on. Display resolution is particularly tricky when it changes during a Matlab session, such as when computer is connector to projector/television or a laptop is connected to a docking station.

Thankfully, printed graphic sizes are rendered correctly when a figure’s PaperPositionMode property is 'auto'. Many users can (and will) ignore the display problem if they aren’t dealing with strict size requirements and text legibility isn’t too bad. Some users may be willing to periodically print publication figures to externally verify sizing, but this breaks the interactive nature of Matlab figures.

A potential work around is the creating of a new figure class that oversizes figures (as needed) to account for a particular display. I started working on such a class, but the problem is more complicated than one might think:

  • Child objects (axes, uicontrols, etc.) also must be resized if they are based on physical units.
  • Resized objects must be temporarily restored to their original size for printing, and new objects must be tracked whenever they are added.
  • Figure resolution may need to be changed when moving to different computer systems.

These capabilities are quite possible to implement, but this is a complicated solution to problem that was once easy to fix.

Retina displays don’t suffer as badly as one might think from the DPI mismatch. Even though the display specification may be greater than 200 DPI, OS X and/or Matlab must perform some intermediate size transformations. The effective DPI in R2015a is 110-120 for 13-15″ MacBook Pro laptops (at the default resolution). Objected sized with physical units still appear smaller than they should (~72/110), but not as small as I expected (<72/200).Effect pixel size can also be changed by switching between different monitor scalings. This isn't entirely surprising, but it can lead to some interesting results because Matlab only reads these settings at startup. Changing the display scaling during a session can cause square figures to appear rectangular. Also, the effective DPI changes for setting: I could reach values of ~60-110 DPI on an Apple Cinema Display.So where does this leave us? Display calibration was always a finicky matter, but at least in principle one could make graphics appear exactly the same size on two different displays. Now it seems that sizing is completely variable between operation systems, displays, and display settings. For publication graphics, there will almost always be a disconnect between figure size on the screen and the printed output; some iteration may be needed to ensure everything looks right in the finished output. For graphical interfaces, font sizes may need to generated in normalized units and then converted to pixels (to avoid resizing).Physical accuracy may not be important for non-publication figures, but the issue of text legibility remains. Some text objects--such as axes and tick labels--can easily be resized because the parent axes automatically adjusts itself as needed. Free floating text objects and uincontrols are much more difficult to deal with. Controls are often sized around the extent of their text label, so changing font sizes may require changes to the control position; adjacent controls may overlap after resizing for text clarity. Normalized units partially solve this problem, but their effect on uicontrols is not always desirable: do you really want push buttons to get larger/smaller when the figure is resized?Can you think of a better workaround to this problem? If so, then please post a comment below. I will be very happy to hear your ideas, as I'm sure others who have high resolution displays would as well.(cross-reference: CSSM newsgroup post)

 
Related posts:
  1. Adding dynamic properties to graphic handles It is easy and very useful to attach dynamic properties to Matlab graphics objects in run-time. ...
  2. A couple of internal Matlab bugs and workarounds A couple of undocumented Matlab bugs have simple workarounds. ...
  3. 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....
  4. Blurred Matlab figure window Matlab figure windows can be blurred using a semi-transparent overlaid window - this article explains how...
 

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...
 

Graphic sizing in Matlab R2015b

$
0
0

I would like to introduce Daniel Dolan of Sandia National Laboratories. Dan works on a variety of data analysis projects in Matlab, and is an active lurker on MATLAB Central. Dan has a habit of finding interesting bugs for the Mac version of Matlab. Today he will discuss graphic sizing in Matlab and important changes that occurred in release R2015b.

Matlab-generated graphics are often not displayed at their requested size. This problem has been known for some time and has a well-known solution: setting the root object’s ScreenPixelsPerInch property to the display’s actual DPI (dots per inch) value. Release R2015b no longer supports this solution, creating problems for publication graphics and general readability.

Physical sizing in R2015a vs. R2015b (click for full-size)

Physical sizing in R2015a vs. R2015b (click for full-size)


Physical sizing

Matlab supports graphic sizing in various physical units: inches, centimeters, and points. For example:

figure; axes('Box','on', 'Units','inches','Position',[0.3 0.3 4 4]);

requests to display an axes having square sizes measuring exactly 4″ (101.6 mm) each. It is evident, however, that the displayed axes is smaller than 4″. The mismatch between requested and physical size depends on the display and operating system — go ahead, try it on your system. The problem is particularly severe on Mac laptops, presumably even worse for those with Retina displays.

The problem is that Matlab cannot determine pixel size, which varies from one display to the other. Generating a figure spanning a particular number of pixels (e.g., 1024 x 768) is easy, but absolute physical units requires a conversion factor called ScreenPixelsPerInch, which is a root property (see related post on setting/getting default graphics property values):

DPI = 110;                             % dots per inch for my 27" Apple Cinema Display
set(0,    'ScreenPixelsPerInch',DPI);  % all releases prior to R2015b
set(groot,'ScreenPixelsPerInch',DPI);  % R2014b through R2015a

DPI values tend to be higher for laptops, usually in the 120-130 range. Retina displays are supposed to be >300 DPI, but I have not been able to test that myself.

There are several ways to determine the correct DPI setting for a particular display. It may be available in the hardware specifications, and it can be calculated from the diagonal size and the number of pixels. Unfortunately these methods are not always reliable. If you really care about physical sizing, the best approach is to actually calibrate your display. There are tools for doing this at Matlab Central, but it’s not hard to do manually:

  • Create a figure.
  • Manually resize the figure to match a convenient width. I often use a piece of US letter paper as 8.5″ guide on the display.
  • Determine the width of the figure in pixels:
    set(gcf,'Units','pixels');
    pos = get(gcf,'Position');
    width = 8.5; % inches
    DPI = pos(3) / width;

I usually apply the DPI settings in my startup file so that Matlab begins with a calibrated display.

What changed in 2015b?

ScreenPixelsPerInch is a read-only property in R2015b, so display calibration no longer works. The following sequence of commands:

figure('Units','inches', 'PaperPositionMode','auto', 'Position',[0 0 4 4]);
set(gcf, 'MenuBar','none', 'ToolBar','none', 'DockControls','off', 'NumberTitle','off');
axes('FontUnits','points', 'FontSize',10);
image

now renders differently in R2015b than does for a calibrated display in R2015a. Differences between the two outputs are shown in the screenshot at the top of this post. The grid behind the figures was rendered at 8.5″ x 8.5″ inches on my display; if your browser’s zoom level isn’t 100%, it may appear larger or smaller.

A side effect of improper graphic sizing is that text is difficult to read — the uncalibrated axes labels are clearly smaller than 10 points. These examples were rendered on ~110 DPI display. Matlab assumes that Macs use 72 DPI (96 DPI on Windows), so graphics appear at 65% of the request size.

The loss of ScreenPixelsPerInch as an adjustable setting strongly affects anyone using Matlab for publication graphics. Scientific and engineering journals are extremly strict about figure widths. With a calibrated screen, figure appear exactly as they will when printed to a file (usually EPS or PDF). Figures are often made as small as possible to and densely packed to save journal space, and accurate sized display helps the author determine legibility. Displaying accurately sized graphics is very difficult in R2015b, which is unfortunate given the many enhancements in this release.

Developers who create graphical interfaces for other users should also care about this change. A common complaint I get is that text and control labels is too small to easily read. Screen calibration deals with this problem, but this option is no longer available.

Where do we go from here?

I reported the above issues to the Mathworks several months ago. It does not appear as a formal bug, but technical support is aware of the problem. The change is part of the “DPI aware” nature of release R2015b. So far I have found no evidence this release is any more aware of pixel size than previous releases, but my experience is limited to non-Retina Macs. I welcome input from users on other operating systems, particularly those with high-resolution displays.

To be fair, correct physical sizing is not an easy across the many platforms that Matlab runs on. Display resolution is particularly tricky when it changes during a Matlab session, such as when computer is connector to projector/television or a laptop is connected to a docking station.

Thankfully, printed graphic sizes are rendered correctly when a figure’s PaperPositionMode property is 'auto'. Many users can (and will) ignore the display problem if they aren’t dealing with strict size requirements and text legibility isn’t too bad. Some users may be willing to periodically print publication figures to externally verify sizing, but this breaks the interactive nature of Matlab figures.

A potential work around is the creating of a new figure class that oversizes figures (as needed) to account for a particular display. I started working on such a class, but the problem is more complicated than one might think:

  • Child objects (axes, uicontrols, etc.) also must be resized if they are based on physical units.
  • Resized objects must be temporarily restored to their original size for printing, and new objects must be tracked whenever they are added.
  • Figure resolution may need to be changed when moving to different computer systems.

These capabilities are quite possible to implement, but this is a complicated solution to problem that was once easy to fix.

Retina displays don’t suffer as badly as one might think from the DPI mismatch. Even though the display specification may be greater than 200 DPI, OS X and/or Matlab must perform some intermediate size transformations. The effective DPI in R2015a is 110-120 for 13-15″ MacBook Pro laptops (at the default resolution). Objected sized with physical units still appear smaller than they should (~72/110), but not as small as I expected (<72/200).Effect pixel size can also be changed by switching between different monitor scalings. This isn't entirely surprising, but it can lead to some interesting results because Matlab only reads these settings at startup. Changing the display scaling during a session can cause square figures to appear rectangular. Also, the effective DPI changes for setting: I could reach values of ~60-110 DPI on an Apple Cinema Display.So where does this leave us? Display calibration was always a finicky matter, but at least in principle one could make graphics appear exactly the same size on two different displays. Now it seems that sizing is completely variable between operation systems, displays, and display settings. For publication graphics, there will almost always be a disconnect between figure size on the screen and the printed output; some iteration may be needed to ensure everything looks right in the finished output. For graphical interfaces, font sizes may need to generated in normalized units and then converted to pixels (to avoid resizing).Physical accuracy may not be important for non-publication figures, but the issue of text legibility remains. Some text objects--such as axes and tick labels--can easily be resized because the parent axes automatically adjusts itself as needed. Free floating text objects and uincontrols are much more difficult to deal with. Controls are often sized around the extent of their text label, so changing font sizes may require changes to the control position; adjacent controls may overlap after resizing for text clarity. Normalized units partially solve this problem, but their effect on uicontrols is not always desirable: do you really want push buttons to get larger/smaller when the figure is resized?Can you think of a better workaround to this problem? If so, then please post a comment below. I will be very happy to hear your ideas, as I'm sure others who have high resolution displays would as well.(cross-reference: CSSM newsgroup post)

I am hiring a Matlab programmer (Tel Aviv)

$
0
0

I am hiring a Matlab programmer for work in the Tel Aviv area, under my supervision. Flexible workhours, suitable for part-time job seekers and students. The work will be interesting and the compensation good. I am not looking for a Matlab expert, but after some time working with me you will become one. If you live in the area and are interested, or if you know someone who could be a good fit, please email me: altmany at gmail.

אני מגייס מתכנת/ת מטלב לעבודה באזור פתח תקוה / בקעת אונו. המשרה בהיקף ובימים/שעות גמישים, מתאים לסטודנטים ולמשרה חלקית. העבודה מעניינת והשכר טוב. אני לא מחפש מומחי מטלב, אבל כעבור זמן מסויים של עבודה איתי אתם תהפכו לכאלו. לפרטים נא לפנות בדוא”ל ל
altmany at gmail

Convolution performance

$
0
0

MathWorks’ latest MATLAB Digest (January 2016) featured my book “Accelerating MATLAB Performance“. I am deeply honored and appreciative of MathWorks for this.

Accelerating MATLAB Performance bookI would like to dedicate today’s post to a not-well-known performance trick from my book, that could significantly improve the speed when computing the convolution of two data arrays. Matlab’s internal implementation of convolution (conv, conv2 and convn) appears to rely on a sliding window approach, using implicit (internal) multithreading for speed.

However, this can often be sped up significantly if we use the Convolution Theorem, which states in essence that conv(a,b) = ifft(fft(a,N) .* fft(b,N)), an idea proposed by Bruno Luong. In the following usage example we need to remember to zero-pad the data to get comparable results:

% Prepare the input vectors (1M elements each)
x = rand(1e6,1);
y = rand(1e6,1);
 
% Compute the convolution using the builtin conv()
tic, z1 = conv(x,y); toc
 => Elapsed time is 360.521187 seconds.
 
% Now compute the convolution using fft/ifft: 780x faster!
n = length(x) + length(y) - 1;  % we need to zero-pad
tic, z2 = ifft(fft(x,n) .* fft(y,n)); toc
 => Elapsed time is 0.463169 seconds.
 
% Compare the relative accuracy (the results are nearly identical)
disp(max(abs(z1-z2)./abs(z1)))
 => 2.75200348450538e-10

This latest result shows that the results are nearly identical, up to a a very minute difference, which is certainly acceptable in most cases when considering the enormous performance speedup (780x in this specific case). Bruno’s implementation (convnfft) is made even more efficient by using MEX in-place data multiplications, power-of-2 FFTs, and use of GPU/Jacket where available.

It should be noted that the builtin Matlab functions can still be faster for relatively small data arrays, or if your machine has a large number of CPU cores and free memory that Matlab’s builtin conv* functions can utilize, and of course also depending on the Matlab release. So, your mileage might well vary. But given the significant speedup potential, I contend that you should give it a try and see how well it performs on your specific system and data.

If you have read my book, please be kind enough to post your feedback about it on Amazon (link), for the benefit of others. Thanks in advance!

Quirks with compiled Matlab DLLs

$
0
0

I would like to introduce guest blogger Hanan Kavitz of Applied Materials. Today Hanan will discuss several quirks that they have encountered with compiled Matlab DLLs.

I work for Applied Materials Israel (PDC) in the algorithm development department. My group provides Matlab software solutions across all of our products. I am a big fan of Yair’s blog and was happy to receive an invitation to be a guest blogger.

In PDC we are using Matlab compiler and Java Builder to deploy our algorithmic products at the customer sites. The software we produce includes binaries of three sorts: exe, C++ dlls, and jar files, all compiled using Matlab deployment tools.

C++ dlls are not as common and are a relatively new kind of binary in production so there’s not as much experience using them in PDC and from time to time we discover weird behaviors that might be interesting to the readers. Here are three of the latest quirks that we encountered:

Leftover tmp files

Recently I faced a problem that googling revealed that I might be the first to encounter it (outside MathWorks development team) as there was no mention of this anywhere. It all started when I got a mail from a fellow developer with content of the type: “Hi Hanan, what are these dump files for ???” and a screenshot of tempdir showing multiple tmp files that all had a naming convention of ‘mathworks_tmp_XXX_YYY’ (xxx and yyy being some numbers, presumably process ids):

multiple leftover tmp files in tmpdir (click for details)

multiple leftover tmp files in tmpdir (click for details)

Each file was about 43MB in size, and combined they consumed the entire free space in the hard-disk, preventing applications from lunching.

At first I looked in our code for the code that will produce files with this naming convention and once I was sure there is no such code I was comfortable to assume that they are MathWorks internal-use files (indeed – who other than MathWorkers would call their files mathworks_tmp_…).

Compiling and running a small ‘hello world’ C++ dll showed that every time that a Matlab-compiled C++ dll executed and ran, a temp file is created and then deleted in the %tmp% dir (tempdir). If the process that runs this dll is ‘killed’ during the run, the temp file is not deleted and remains in the %tmp% folder, accumulating over time until the hard disk becomes completely full.

On another machine I found a whole bunch of different temp files with different extensions. Opening them in editor didn’t reveal their purpose. They all had two things in common:

  1. All had a naming convention mathworks_tmp_XXX__YYY, whatever the extension of the file may be.
  2. They are all useless when the Matlab application is done running.

Once this was clear, the solution was very simple:

  • When lunching the process that runs Matlab compiled dll, change the %tmp% directory to a new one.
  • Delete this directory once done running or on the next process start.

mclInitializeApplication

As a separate discussion, our compiled algorithm is embarrassingly parallel in nature so our C++ team is running it in parallel processes across several machines and many cores.

As with all Matlab-compiled C++ DLLs, it needs to be initialized with a call to mclInitializeApplication per running process. This worked well when we had a relatively small number of processes running concurrently but lately we encountered a problem that out of dozens of calls to this function from time to time a call is stuck (not failed – exactly that: stuck) and the process needs to be killed.

We don’t know why this happens and the solution we are currently using is pretty “shaky” at best – we retry the call to this function several times until it eventually works (and it does work after several tries).

I have a suspicion that something is not entirely parallel with this function and there exists some hidden internal shared resource among different processes but no way to know exactly as this is an internal MathWorks function.

Implicit multithreading

This is relatively old issue we encountered at the beginning when we just started using Matlab-compiled DLLs, so this might not surprise some readers. While Matlab’s builtin (automatic) multithreading is great when used in the MATLAB IDE (non-compiled), it creates a problem when running compiled DLLs in parallel across multiple processes: this multithreading ‘starves’ for cores because they are busy at running other processes.

The solution is simple and well documented – when calling mclInitializeApplication before launching the DLL, pass it the singleCompThread flag to prevent implicit multithreading. We found this single threaded DLL to run faster because it reduced CPU ‘starvation’ drastically in a multi process environment.

Addendum (by Yair again):

I am delighted to announce that a few days ago I received an apparently-automated email from MathWorks telling me that 4 of the issues that I have reported early last year were fixed in R2015b. IMHO, this marks a very important step of closing the loop with the original issue reporter, something that I have suggested publicly back in December 2014 (and also privately over the years). I believe that such automated feedbacks increase user motivation to report misbehaving or missing features, which will ultimately make Matlab better for the benefit of us all. I also believe that this proves once again my claim that beneath the corporate jargon, MathWorks is indeed a company run by engineers like us, who cares about its users and the interaction with them more than typical in the corporate world. I can only praise this email and hope that it is now part of the ongoing development release process, rather than being an isolated case. If I may suggest a followup improvement, it would be nice to receive such emails before the new release is out (i.e., during the beta phase) so that the original reporter could have a chance to test it on the beta before it actually goes live. But in any case, thanks MathWorks for listening and making yet another improvement :-)

Happy New Year of the Monkey everybody!

Simple GUI Tabs for Advanced Matlab Trading App

$
0
0

I’d like to introduce guest blogger Alex Boykov, one of the developers of the Walk-Forward Analysis Toolbox for Matlab (WFAToolbox), which enables accelerated trading strategies development using Matlab. Today, Alex will explain how they used tabs in a way that can be replicated by any other Matlab GUI, not necessarily having the latest Matlab release.

In this post, we want to tell you about how we solved the problem of tab creation for WFAToolbox. We required the following criteria:

  • The tabs need to be attractive and look like tabs, not like buttons with panels
  • The tabs need to have been drawn using the editor GUIDE so that the contents of the tab panel can be easily edited
  • The tabs can be easily added and removed without significant code additions. They must be simple to use in different projects and tasks

The sophisticated user of Matlab might think that this is a trivial objective, seeing as there are numerous solutions for this problem in the Matlab Exchange and since Matlab R2014b, it supports creating native tabs with the help of uitab and uitabgroup functions. Also, with the addition of App Designer, it might appear that this issue will be solved with the new interface for GUI creation; tabs can be created right in the editor. However, in this post, we will attempt to explain why none of the methods above fit the three criteria stated and we will present our own solution for the tabs.

Regardless of the fact that we only took on the problem in 2013, when we first started creating our WFAToolbox, at the moment of writing this article (January 2016), this problem is still a relevant issue for many Matlab users. After the release of R2016a, it is doubtful the problem will be entirely solved. This is why we created our own example of a code which we have released on the Matlab File Exchange (see below).


Tab-enabled WFAToolbox (Matlab app for algorithmic trading)

Tab-enabled WFAToolbox (Matlab app for algorithmic trading)

1. The tabs have to look like tabs

When we created WFAToolbox, our goal was to create an application which would allow everyone interested to create a strategy for trading on the financial markets to be able to do so, along with having the opportunity to use the full potential of Matlab and its progressive tools, including genetic algorithms, parallel computing, econometrics, neural networks, and much, much more (basically, any data analysis that can be done in Matlab). At the same time, we do not want our users to spend time on developing an advanced software environment for testing, analysis, and strategy execution, but rather to do it from an easy-to use GUI. Thus, in WFAToolbox, you can create, test, and, finally, launch your own trading strategy or test a hypothesis within minutes, even with little prior knowledge of Matlab programming.

Of course, in order to fit these features into a single application, guarantee that it would be easy to understand even by beginners, and that it would be simple to operate, it was necessary to pay special attention to the graphic interface. In our opinion, perhaps the most intelligent solution for placing the many controls and functions necessary for sophisticated applications is by creating tabs. Because we knew that we were not the only ones who thought this way, we started looking for examples of codes that were previously created in the Matlab Exchange. We were very surprised when we found only a few solutions, most of which did not even match our first criteria of tab attractiveness! Unfortunately, a majority of them were old and quite unattractive (they looked more like buttons with panels). Even the new App Designer has tabs that in our eyes look more like buttons than tabs.

Having tried a lot of these utilities in our test versions, we came to the conclusion that Tab Panel Constructor v.2.8 would be the best option for us. It fits all three criteria above. In 2013, we used it quite successfully in our first versions of WFAToolbox. Everything looked great, but, unfortunately, it later turned out that the problem was far from being solved.


Tab-enabled WFAToolbox (Matlab app for algorithmic trading)

Tab-enabled WFAToolbox (Matlab app for algorithmic trading)

2. The tabs need to be created through GUIDE

Unfortunately, with time, it turned out that with the newer version of Matlab it didn’t work smoothly and the code we wanted to use as our solution practically fell apart in front of us. After adding a couple of elements in GUI, partial formatting was lost and we had to redo everything. The process of adding the tags created a lot of bugs which needed to be solved immediately.

In 2014, we already had more than 500 clients using our application. We started hearing, more and more often, that it would be great if the colors and locations of the tabs could be changed. It turned out that, depending on the operating system and Matlab version, the tab format changes. So, we made the decision to change our tabs.

By that time, a new version of Matlab was released, R2014b. It allowed us to build tabs with the help of the uitabgroup and uitab functions. The results looked exactly how we wanted: attractive, pleasant, and appeared like real tabs: UI With Tab Panel in Matlab R2014b. However, we were discouraged that they could not be created in GUIDE!

During that time, we were developing a module for WFAToolbox which would allow users to download data from Google Finance: 10,000+ free daily and intraday quotes from 20+ exchanges. Tabs were the easiest to use when switching between downloading free data from Google Finance and downloading custom user data from the Matlab Workspace. But entering so many elements through code and not through an editor? What will happen when we add 100,000+ free historical data from Yahoo Finance for futures, bonds, currency, stocks and others? We didn’t want to create all of this without the GUIDE editor! This is why we came to the conclusion that it is necessary for us to create a code of tabs, starting from scratch, so that they would correspond with all three of our criteria.


Tab-enabled WFAToolbox (Matlab app for algorithmic trading)

Tab-enabled WFAToolbox (Matlab app for algorithmic trading)

3. The tabs should be easy to add and edit

We chose the Simple Tab Panel, which has existed in the Matlab File Exchange since 2007, as a base for our new code because we considered it to be the most elegant and attractive example of GUIDE tabs. This solution fit our first two criteria, but we really wanted it to be universal and easy to use. We also wanted to have a simplified process of tab addition and deletion so that instead of having to copy and rewrite a large amount of code and other details, we could just add a single line of code. We wanted to save on labor costs, because we often add new features to WFAToolbox and this includes having to constantly add new elements to existing tabs, as well as adding new tabs.

So, we rewrote the code and created our own universal example so that everyone could use it to their advantage. We uploaded the code to the Matlab File Exchange, where it can be freely downloaded: Simple Optimized GUI Tab.

Next, we will describe how to use this code for tab addition and how to use the process for the implementation of tasks.

So, in order to add a new tab, you need to:

  1. Open GUIDE and apply uipanel and uitext in a way that will make uipanel easier to work with in the future, and place uitext in a place where the tab switch will be located.
  2. Rename the Tag of the uitext to [‘tab’,N,’text’], where N is the tab index. In our example, we are creating the 3rd tab, so our tag would be ‘tab3text’. Using this same principle, [‘tab’,N,’Panel’] needs to be renamed to tag of uipanel in the ‘tab3Panel’.
  3. Add the name of the new tab to the TabNames variable. In our example, we use ‘Tab3’ (but you can use any name).
TabNames = {'Tab 1','Tab 2','Tab3'};

How the code was created

The primary principle of how our code works is that we create the uipanel and uitext objects in GUIDE, then we take the uitext coordinates and replace the objects to the axes and text objects. We assign a callback function to them which works when the object is clicked on. The function makes the uipanels visible/invisible and changes the colors of tab.

Let’s look at the function code SimpleOptimizedTabs2.m, which is part of the Simple Optimized GUI Tab submission.

1. Tab settings

% Settings
TabFontSize = 10;
TabNames = {'Tab 1','Tab 2'};
FigWidth = 0.265;

If we change the parameters under Settings, we can control the appearance of our GUI and tabs. So, the parameter of TabFontSize changes the font size on the tab switch, and, with the help of TabNames we can rename or add tab names, and with FigWidth, we can determine the normalized width of the GUI.

2. Changing the figure width

% Figure resize
set(handles.SimpleOptimizedTab,'Units','normalized')
pos = get(handles. SimpleOptimizedTab, 'Position');
set(handles. SimpleOptimizedTab, 'Position', [pos(1) pos(2) FigWidth pos(4)])

The GUI width changes in the code because it isn’t comfortable to manually stretch and narrow the figure. It is more beneficial to see the contents of all tabs and work with them without having to change the width every time you make a small change. If you want to make your uipanels bigger than in the example, then do this with the GUIDE editor. However, don’t forget to change the FigWidth parameter.

Please note that, due to the peculiarities of the editor, you cannot narrow a figure by height without shifting tab locations. You can only do this if you are changing the width, so we only recommend adding tabs by increasing the width of the figure and not the length.

3. Creating tabs

Do the following for each tab: obtain the uitext coordinates, which we entered into the GUI panel, and position the axes and text using these coordinates (using the necessary settings of external apparel). Using the ButtonDownFcn parameter, we can link the callback function, called ClickOnTab, in order to switch tabs when clicking on the text or axes.

% Tabs Execution
handles = TabsFun(handles,TabFontSize,TabNames);
 
% --- TabsFun creates axes and text objects for tabs
function handles = TabsFun(handles,TabFontSize,TabNames)
 
% Set the colors indicating a selected/unselected tab
handles.selectedTabColor=get(handles.tab1Panel,'BackgroundColor');
handles.unselectedTabColor=handles.selectedTabColor-0.1;
 
% Create Tabs
TabsNumber = length(TabNames);
handles.TabsNumber = TabsNumber;
TabColor = handles.selectedTabColor;
for i = 1:TabsNumber
    n = num2str(i);
 
    % Get text objects position
    set(handles.(['tab',n,'text']),'Units','normalized')
    pos=get(handles.(['tab',n,'text']),'Position');
 
    % Create axes with callback function
    handles.(['a',n]) = axes('Units','normalized',...
                    'Box','on',...
                    'XTick',[],...
                    'YTick',[],...
                    'Color',TabColor,...
                    'Position',[pos(1) pos(2) pos(3) pos(4)+0.01],...
                    'Tag',n,...
                    'ButtonDownFcn',[mfilename,'(''ClickOnTab'',gcbo,[],guidata(gcbo))']);
 
    % Create text with callback function
    handles.(['t',n]) = text('String',TabNames{i},...
                    'Units','normalized',...
                    'Position',[pos(3),pos(2)/2+pos(4)],...
                    'HorizontalAlignment','left',...
                    'VerticalAlignment','middle',...
                    'Margin',0.001,...
                    'FontSize',TabFontSize,...
                    'Backgroundcolor',TabColor,...
                    'Tag',n,...
                    'ButtonDownFcn',[mfilename,'(''ClickOnTab'',gcbo,[],guidata(gcbo))']);
 
    TabColor = handles.unselectedTabColor;
end
 
% Manage panels (place them in the correct position and manage visibilities)
set(handles.tab1Panel,'Units','normalized')
pan1pos=get(handles.tab1Panel,'Position');
set(handles.tab1text,'Visible','off')
for i = 2:TabsNumber
    n = num2str(i);
    set(handles.(['tab',n,'Panel']),'Units','normalized')
    set(handles.(['tab',n,'Panel']),'Position',pan1pos)
    set(handles.(['tab',n,'Panel']),'Visible','off')
    set(handles.(['tab',n,'text']),'Visible','off')
end

Actually, if you have long tab names and you want to change the switch size, then it you may possibly need to correct the Position parameter for the text object by adding the correcting coefficients to it. Unfortunately, this is also a feature of GUIDE. If someone can solve this problem so that the text would always be shown in the middle of the switch tab regardless of the width, we would be happy to read any suggestions in the comments to this post.

4. The callback function ClickOnTab

The callback function ClickOnTab is used every time when clicking on the tab switch and the result of the switches are visible/invisible in the uipanels and in changes to the colors of the switches.

% --- Callback function for clicking on tab
function ClickOnTab(hObject,~,handles)
m = str2double(get(hObject,'Tag'));
 
for i = 1:handles.TabsNumber;
    n = num2str(i);
    if i == m
        set(handles.(['a',n]),'Color',handles.selectedTabColor)
        set(handles.(['t',n]),'BackgroundColor',handles.selectedTabColor)
        set(handles.(['tab',n,'Panel']),'Visible','on')
    else
        set(handles.(['a',n]),'Color',handles.unselectedTabColor)
        set(handles.(['t',n]),'BackgroundColor',handles.unselectedTabColor)
        set(handles.(['tab',n,'Panel']),'Visible','off')
    end
end

More information about our Walk-Forward Analysis Toolbox for Algorithmic Trading (WFAToolbox) can be found at wfatoolbox.com.

Better MEX error messages

$
0
0

I would like to introduce guest blogger Pavel Holoborodko, the developer of the Advanpix Multiprecision Computing Toolbox for MATLAB. Pavel has already posted here in the past as a guest blogger about undocumented Matlab MEX functions. Today he will discuss another little-known aspect of advanced MEX programming with Matlab.

MEX API provides two functions for proper handling of erroneous situations: the legacy mexErrMsgTxt and the newer mexErrMsgIdAndTxt. Both show error message, interrupt execution of a MEX module and return control to Matlab immediately.

Under the hood, these functions are implemented through C++ exceptions. The reason for this design choice is unclear. Throwing C++ exceptions across module boundary (e.g. from dynamic library to host process) is unsafe and generally considered as bad practice in software design. Exceptions are part of C++ run-time library and different versions of it might have incompatible implementations.

This restricts MEX to use only the same version of C++ run-time and GCC which were used to build that particular version of Matlab itself. This is one of the reasons why TMW distributes its own version of GCC/libstdc++ along with every release of Matlab and pushes developers to use it for MEX compilation.

Such unfortunate design decision have two unpleasant consequences:

  1. developers must use some old version of GCC (forget all the fancy stuff from C++11, C++14, etc.)
  2. compiled MEX modules most likely will not work on older/newer versions of MATLAB (re-compilation is required).

The good news is that both issues are solvable and I will write more about this in the future (it is actually possible to create single binary MEX module, which will work on any GNU Linux flavor regardless of the versions of libc/libstc++/gcc installed in the system or used in Matlab).

Here I propose just first step towards freedom – avoid direct usage of mexErrMsg** functions. Use a simple wrapper instead:

void mxShowCriticalErrorMessage(const char *msg)
{
    mxArray *arg;
    arg = mxCreateString(msg);
    mexCallMATLAB(0,0,1,&arg,"error");
}

The mxShowCriticalErrorMessage function calls Matlab’s built-in error function via the interpreter, with the error message as input parameter.

In addition to being safe, this approach potentially gives us better control over what additional information is shown together with error messages. Instead of a string, we can use an errorStruct as input argument to Matlab’s error function, with its fields tuned to our requirements (not shown here as I want to keep the example simple).

Even without tuning, output of mxShowCriticalErrorMessage is much more informative and user-friendly:

  • Error message from Matlab’s built-in functionality:
    >> A = magic(3);
    >> A(0)
    Subscript indices must either be real positive integers or logicals.

    Nice one-line message without any distracting information.
     

  • Error message from MEX using mexErrMsgTxt/mexErrMsgIdAndTxt:
    >> A = mp(magic(3));   % convert matrix to arbitrary precision type, provided by our toolbox
    >> A(0)                % subsref is called from toolbox, it is implemented in mpimpl.mex
    Error using mpimpl
    Subscript indices must either be real positive integers or logicals.
    Error in mp/subsref (line 860)
            [varargout{1:nargout}] = mpimpl(170, varargin{:});

    Intimidating four lines with actual error message lost in the middle. All the additional information is meaningless for end-user and actually misleading.

    The worst thing is that such error message is very different from what user get used to (see above one-liner), which leads to confusion if MEX plugin is properly working at all.
     

  • Error message from MEX using mxShowCriticalErrorMessage:
    >> A = magic(3);
    >> A(0)
    Error using mp/subsref (line 860)
    Subscript indices must either be real positive integers or logicals.

    Now the message is clear and short, with error description in the last line where the user focus is.
     

Munich Germany visit, 9-11 May 2016

$
0
0

Munich Germany visit, 9-11 May 2016I will be visiting clients in Munich, Germany between 9-11 May 2016, for advanced Matlab training and consulting. During this visit I will also attend the annual MATLAB Expo on May 10.

If you are in the München area and wish to meet me to discuss how I could bring value to your work, then please email me (altmany at gmail). We could meet either at the Expo, or in a dedicated (private) meeting.


Customizing contour plots part 2

$
0
0

A few months ago I discussed various undocumented manners by which we can customize Matlab contour plots. A short while ago I receive an email from a blog reader (thanks Frank!) alerting me to another interesting way by which we can customize such plots, using the contour handle’s hidden ContourZLevel property. In today’s post I will explain how we can use this property and expand the discussion with some visualization interactivity.

The ContourZLevel property

The contour handle’s ContourZLevel property is a hidden property. This means that, just like all other hidden properties, it is accessible if we just happen to know its name (which is easy using my getundoc utility). This property sets the Z level at which the contour lines are drawn.

For example, by default the meshc function sets ContourZLevel‘s value to the bottom of the 3D display (in other words, to the axes’ ZLim(1) value). This is done within the mesh.m function:

Standard Matlab meshc output (contour at bottom)

Standard Matlab meshc output (contour at bottom)

We can, however, modify the contour’s level value to any other Z location:

% create a mesh and contour plot
handles = meshc(peaks);
 
% handles is a 2-element array of handles: the surface plot and the contours
hContour = handles(2); % get the handle to the contour lines
hContour.ContourZLevel = 4.5; % set the contour's Z position (default: hAxes.ZLim(1)=-10)
 
% We can also customize other aspects of the contour lines, for example:
hContour.LineWidth = 2; % set the contour lines' width (default: 0.5)

Customized Matlab meshc output

Customized Matlab meshc output

Adding some visualization interactivity

Now let’s add some fun interactivity using a vertical slider to control the contour’s height (Z level). Matlab’s slider uicontrol is really just an ugly scrollbar, so we’ll use a Java JSlider instead:

% Add a controlling slider to the figure
jSlider = javaObjectEDT(javax.swing.JSlider);
jSlider.setOrientation(jSlider.VERTICAL);
jSlider.setPaintTicks(true);
jSlider.setMajorTickSpacing(20);
jSlider.setMinorTickSpacing(5);
jSlider.setBackground(java.awt.Color.white);
[hjSlider, hContainer] = javacomponent(jSlider, [10,10,30,120], gcf);
 
% Set the slider's action callback
hAxes = hContour.Parent;  % handle to containing axes
zmin = hAxes.ZLim(1);
zmax = hAxes.ZLim(2);
zrange = zmax - zmin;
cbFunc = @(hSlider,evtData) set(hContour,'ContourZLevel',hSlider.getValue/100*zrange+zmin);
hjSlider.StateChangedCallback = cbFunc;  % set the callback for slider action events
cbFunc(hjSlider,[]);  % evaluate the callback to synchronize the initial display

Interactive contour height

Interactive contour height

Secure SSL connection between Matlab and PostgreSQL

$
0
0

I’d like to introduce guest blogger Jeff Mandel of the Perelman School of Medicine at the University of Pennsylvania. Today Jeff will discuss a how-to guide for setting up an SSL connection between Matlab and a PostgreSQL database. While this specific topic may be of interest to only a few readers, it involves hard-to-trace problems that are not well documented anywhere. The techniques discussed below may also be applicable, with necessary modifications, to other SSL targets and may thus be of use to a wider group of Matlab users.

PostgreSQL database
I’m developing software for pharmacokinetic control, and needed secure access to a central database from users at remote sites. The client software is written in Matlab, and while I have targeted MacOS, this could be adapted to Windows fairly easily. Hopefully, this will save someone the week it took me to figure all this out.

My environment:

  • PostgreSQL 9.4 installed on the server (Windows 7 PC, but Linux would be equally good)
  • DynDNS CNAME pointing at the server (diseserver.mydomain.org)
  • CACert.org registration for domain mydomain.org
  • Matlab 2015b running on El Capitan

Here are the neccesary steps:

  1. First, we need a certificate for the server. We can generate this with OpenSSL:
    $openssl req -out diseserver.csr -new -newkey rsa:2048 -nodes -keyout diseserver.key

    Specify any information you want on the key, but ensure CN=diseserver.mydomain.org.

  2. Paste the resulting diseserver.csr file into a new key request at CACert.org. Save the resulting certificate as diseserver.crt on your machine.
  3. While still at CACert.org, grab the Class 1 root certificate and save it as root.crt.
  4. Put the files diseserver.key, diseserver.crt, and root.crt in the PostgreSQL data directory.
  5. Edit your postgresql.conf file:
    ssl = on
    ssl_cert_file = 'diseserver.crt'  # (change requires restart)
    ssl_key_file  = 'diseserver.key'  # (change requires restart)
    ssl_ca_file   = 'root.crt'        # (change requires restart)
  6. Restart the PostgreSQL server. The server will now permit SSL connections, a necessary pre-condition for certificate authentication.
  7. We now add 2 lines to pg_hba.conf:
    hostnossl  all    all   0.0.0.0/0   reject
    hostssl	 mytable  all   0.0.0.0/0   cert map=ssl clientcert=1

    The first line causes all non-SSL connections to be rejected. The second allows certificate logins for mytable using the map ssl that is defined in pg_ident.conf:

    ssl  /^(.*).mydomain\.org$ \1

    this line extracts the username prefix from CN=username.mydomain.org.

  8. Now we need to generate client certificates. PostgreSQL expects these to be in ~/.postgresql (Windows %appdata%\postgresql\):
    $mkdir ~/.postgresql
    $cd ~/.postgresql
    $openssl req -out postgresql.csr -new -newkey rsa:2048 -nodes -keyout postgresql.key

    for this key, make CN=username.mydomain.org.

  9. Again, paste the resulting postgresql.csr file into CACert.org, saving the certificate as postgresql.crt.
  10. Test this:
    $psql "sslmode=verify-full host=diseserver.mydomain.org dbname=effect user=username"

    The server should respond:

    psql (9.4.6, server 9.4.1)
    SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
  11. Next we need to convert our key into pkcs8 format so that Java can read it:
    $openssl pkcs8 -topk8 -inform PEM -outform DER -in postgresql.key -out postgresql.pk8 -nocrypt
  12. Next, ensure that we have the correct version of the JDBC driver (Java-to-database connector). From the Mac command line:
    $java -version
    java version "1.8.0_05"

    and in Matlab:

    >> version -java
    ans =
    Java 1.7.0_75-b13 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode

    This shows that although we have Java 8 installed on El Capitan (at the OS level), Matlab uses a private Java 7 version. So we need the correct version of the jdbc on our static java classpath that is used by Matlab:

    ~/Matlab/postgresql-9.4.1208.jre7.jar
  13. The next part is very poorly documented in both the MathWorks and the PostgreSQL documentation, but I found it in Russel Gray’s Basildon Coder blog: We need to use the jdbc postgresql driver to check the client certificate. To do this, we need a custom SSLSocketFactory – LibPQFactory. This will grab our certificate and key from ~/.postgresql and present them to the server. The url is (note the trailing &):
    jdbc:postgresql://diseserver.mydomain.org/mytable?ssl=true&sslfactory=org.postgresql.ssl.jdbc4.LibPQFactory&sslmode=verify-full&
  14. Next we need the username. Rather than hard-coding this in the source code, we get the system username:
    >> username = java.lang.System.getProperty('user.name');
  15. Bundle this all up in a Matlab function, stripping the trailing CR from the username:
    function dbtest
       driver = 'org.postgresql.Driver';
       [~,username] = system('whoami');
       url = 'jdbc:postgresql://diseserver.mydomain.org/mytable?ssl=true&sslfactory=org.postgresql.ssl.jdbc4.LibPQFactory&sslmode=verify-full&';
       myconn = database('mytable', username, '', driver, url);
       if ~isempty(myconn.Message)
          fprintf(2,'%s\n', myconn.Message);
       else
          fprintf(1, 'Connected!\n');
       end
    end

Now we can connect from the Matlab command line or a Matlab program.

What if we’re deployed? We also need to add the contents of our .postgresql directory, plus the jdbc jar file to our deployed app:

>> mcc -m dbtest.m -a ~/.postgresql -a ~/Matlab/postgresql-9.4.1208.jre7.jar

Let’s test the compiled program from the OS command line:

$./run_dbtest.sh /Applications/Matlab/Matlab_Runtime/v90
Connected!

Note that the key and certificates are part of the encrypted bundle produced by Matlab’s mcc compiler.

I hope this helps someone!

Yair’s note: the Matlab code above uses Matlab’s Database Toolbox (specifically, the database function) to connect to the database. In future posts I plan to show how we can connect Matlab directly to a database via JDBC. This topic is covered in detail in chapter 2 of my Matlab-Java programming secrets book.

p.s. – this blog celebrates a 7-year anniversary tomorrow: I published my very first post here on March 19, 2009, showing how to change Matlab’s command-window colors (a post that later led to the now-famous cprintf utility). It’s been a long and very interesting ride indeed, but I have no plans to retire anytime soon :-)

Upcoming public Matlab presentations

$
0
0

I will be presenting in two upcoming Matlab conferences:

In both cases I will present a professional pairs-trading and analysis application developed for a New York hedge fund. This application analyzes large amounts of data relatively quickly, and presents the results in a professional-grade GUI. My aim is to use this example to show that contrary to a widespread mis-conception, professional Matlab programs can be created without sacrificing performance (speed) or appearance. Coupled with Matlab’s recognized benefits (rapid app development and off-the-shelf functionality), Matlab is certainly relevant for serious user-facing applications, not just for prototyping and internal organizational use.

My presentations will be focused on the technical Matlab aspects, not the specific financial functionality of the program. I am targeting the presentations at anyone who designs and creates Matlab programs, not just in the financial fields. I will discuss some of the technical challenges encountered during the development, and a few simple techniques that can be very effective for improving run-time performance and visualization quality.

If you are in the area and wish to meet me to discuss how I could bring value to your work, then please email me (altmany at gmail) to coordinate a meeting. We could meet either at the conferences, or in a dedicated (private) meeting.


Matlab-based pairs-trading and analysis application



Matlab-based pairs-trading and analysis application

Adding a search box to figure toolbar

$
0
0

Last week I wrote about my upcoming presentations in Tel Aviv and Munich, where I will discuss a Matlab-based financial application that uses some advanced GUI concepts. In today’s post I will review one of these concepts that could be useful in a wide range of Matlab applications – adding an interactive search box to the toolbar of Matlab figures.

The basic idea is simple: whenever the user types in the search box, a Matlab callback function checks the data for the search term. If one or more matches are found then the searchbox’s background remains white, otherwise it is colored yellow to highlight the term. When the user presses <Enter>, the search action is triggered to highlight the term in the data, and any subsequent press of <Enter> will highlight the next match (cycling back at the top as needed). Very simple and intuitive:

Interactive search-box in Matlab figure toolbar

Interactive search-box in Matlab figure toolbar


In my specific case, the search action (highlighting the search term in the data) involved doing a lot of work: updating multiple charts and synchronizing row selection in several connected uitables. For this reason, I chose not to do this action interactively (upon each keypress in the search box) but rather only upon clicking <Enter>. In your implementation, if the search action is simpler and faster, you could do it interactively for an even more intuitive effect.

Technical components

The pieces of today’s post were already discussed separately on this website, but never shown together as I will do today:

Adding a search-box to the figure toolbar

As a first step, let’s create the search-box component and add it to our figure’s toolbar:

% First, create the search-box component on the EDT, complete with invokable Matlab callbacks:
jSearch = com.mathworks.widgets.SearchTextField('Symbol');  % 'Symbol' is my default search prompt
jSearchPanel = javaObjectEDT(jSearch.getComponent);  % this is a com.mathworks.mwswing.MJPanel object
jSearchPanel = handle(jSearchPanel, 'CallbackProperties');  % enable Matlab callbacks
 
% Now, set a fixed size for this component so that it does not resize when the figure resizes:
jSize = java.awt.Dimension(100,25);  % 100px wide, 25px tall
jSearchPanel.setMaximumSize(jSize)
jSearchPanel.setMinimumSize(jSize)
jSearchPanel.setPreferredSize(jSize)
jSearchPanel.setSize(jSize)
 
% Now, attach the Matlab callback function to search box events (key-clicks, Enter, and icon clicks):
jSearchBox = handle(javaObjectEDT(jSearchPanel.getComponent(0)), 'CallbackProperties');
set(jSearchBox, 'ActionPerformedCallback', {@searchSymbol,hFig,jSearchBox})
set(jSearchBox, 'KeyPressedCallback',      {@searchSymbol,hFig,jSearchBox})
 
jClearButton = handle(javaObjectEDT(jSearchPanel.getComponent(1)), 'CallbackProperties');
set(jClearButton, 'ActionPerformedCallback', {@searchSymbol,hFig,jSearchBox})
 
% Now, get the handle for the figure's toolbar:
hToolbar = findall(hFig,'tag','FigureToolBar');
jToolbar = get(get(hToolbar,'JavaContainer'),'ComponentPeer');  % or: hToolbar.JavaContainer.getComponentPeer
 
% Now, justify the search-box to the right of the toolbar using an invisible filler control
% (first add the filler control to the toolbar, then the search-box control):
jFiller = javax.swing.Box.createHorizontalGlue;  % this is a javax.swing.Box$Filler object
jToolbar.add(jFiller,      jToolbar.getComponentCount);
jToolbar.add(jSearchPanel, jToolbar.getComponentCount);
 
% Finally, refresh the toolbar so that the new control is displayed:
jToolbar.revalidate
jToolbar.repaint

Now that the control is displayed in the toolbar, let’s define what our Matlab callback function searchSymbol() does. Remember that this callback function is invoked whenever any of the possible events occur: keypress, <Enter>, or clicking the search-box’s icon (typically the “x” icon, to clear the search term).

We first reset the search-box appearance (foreground/background colors), then we check the search term (if non-empty). Based on the selected tab, we search the corresponding data table’s symbol column(s) for the search term. If no match is found, we highlight the search term by setting the search-box’s text to be red over yellow. Otherwise, we change the table’s selected row to the next match’s row index (i.e., the row following the table’s currently-selected row, cycling back at the top of the table if no match is found lower in the table).

Reading and updating the table’s selected row requires using my findjobj utility – for performance considerations the jTable handle should be cached (perhaps in the hTable’s UserData or ApplicationData):

% Callback function to search for a symbol
function searchSymbol(hObject, eventData, hFig, jSearchBox)
    try
        % Clear search-box formatting
        jSearchBox.setBackground(java.awt.Color.white)
        jSearchBox.setForeground(java.awt.Color.black)
        jSearchBox.setSelectedTextColor(java.awt.Color.black)
        jSearchBox.repaint
 
        % Search for the specified symbol in the data table
        symbol = char(jSearchBox.getText);
        if ~isempty(symbol)
            handles = guidata(hFig);
            hTab = handles.hTabGroup.SelectedTab;
            colOffset = 0;
            forceCol0 = false;
            switch hTab.Title
                case 'Scanning'
                    hTable = handles.tbScanResults;
                    symbols = cell(hTable.Data(:,1));
                case 'Correlation'
                    hTable = handles.tbCorrResults;
                    symbols = cell(hTable.Data(:,1:2));
                case 'Backtesting'
                    hTab = handles.hBacktestTabGroup.SelectedTab;
                    hTable = findobj(hTab, 'Type','uitable', 'Tag','results');
                    pairs = cell(hTable.Data(:,1));
                    symbols = cellfun(@(c)strsplit(c,'/'), pairs, 'uniform',false);
                    symbols = reshape([symbols{:}],2,[])';
                    forceCol0 = true;
                case 'Trading'
                    hTable = handles.tbTrading;
                    symbols = cell(hTable.Data(:,2:3));
                    colOffset = 1;
                otherwise  % ignore
                    return
            end
            if isempty(symbols)
                return
            end
            [rows,cols] = ind2sub(size(symbols), find(strcmpi(symbol,symbols)));
            if isempty(rows)
                % Not found - highlight the search term
                jSearchBox.setBackground(java.awt.Color.yellow)
                jSearchBox.setForeground(java.awt.Color.red)
                jSearchBox.setSelectedTextColor(java.awt.Color.red)
                jSearchBox.repaint
            elseif isa(eventData, 'java.awt.event.KeyEvent') && isequal(eventData.getKeyCode,10)
                % Found with <Enter> event - highlight the relevant data row
                jTable = findjobj(hTable);
                try jTable = jTable.getViewport.getView; catch, end  % in case findjobj returns the containing scrollpane rather than the jTable
                [rows, sortedIdx] = sort(rows);
                cols = cols(sortedIdx);
                currentRow = jTable.getSelectedRow + 1;
                idx = find(rows>currentRow,1);
                if isempty(idx),  idx = 1;  end
                if forceCol0
                    jTable.changeSelection(rows(idx)-1, 0, false, false)
                else
                    jTable.changeSelection(rows(idx)-1, cols(idx)-1+colOffset, false, false)
                end
                jTable.repaint
                jTable.getTableHeader.repaint
                jTable.getParent.getParent.repaint
                drawnow
            end
        end
    catch
        % never mind - ignore
    end
end

That’s all there is to it. In my specific case, changing the table’s selected row cased an immediate trigger that updated the associated charts, synchronized the other data tables and did several other background tasks.

What about the new web-based uifigure?

The discussion above refers only to traditional Matlab figures (both HG1 and HG2), not to the new web-based (AppDesigner) uifigures that were officially introduced in R2016a (I wrote about it last year).

AppDesigner uifigures are basically webpages rather than desktop windows (JFrames). They use an entirely different UI mechanism, based on HTML webpages served from a localhost webserver, using the DOJO Javascript toolkit for visualization and interaction, rather than Java Swing as in the existing JFrame figures. The existing figures still work without change, and are expected to continue working alongside the new uifigures for the foreseeable future. I’ll discuss the new uifigures in separate future posts (in the meantime you can read a bit about them in my post from last year).

I suspect that the new uifigures will replace the old figures at some point in the future, to enable a fully web-based (online) Matlab. Will this happen in 2017 or 2027 ? – your guess is as good as mine, but my personal guesstimate is around 2018-2020.

Faster findjobj

$
0
0

My findjobj utility, created in 2007 and updated over the years, has received wide recognition and is employed by numerous Matlab programs, including a few dozen utilities in the Matlab File Exchange. I am quite proud of this utility and find it extremely useful for customizing Matlab controls in many ways that are impossible using standard Matlab properties. I have shown many examples of this in this blog over the past years.

I am happy to announce that I have just uploaded a new version of findjobj to the Matlab File Exchange, which significantly improves the utility’s performance for the most common use-case of a single input and a single output, namely finding the handle of the underlying Java component (peer) of a certain Matlab control:

>> hButton = uicontrol('String','click me!');
 
>> tic, jButton = findjobj(hButton); toc  % old findjobj
Elapsed time is 1.513217 seconds.
 
>> tic, jButton = findjobj(hButton); toc  % new findjobj
Elapsed time is 0.029348 seconds.

The new findjobj is backward-compatible with the old findjobj and with all prior Matlab releases. It is a drop-in replacement that will significantly improve your program’s speed.

The new version relies on several techniques:

First, as I showed last year, in HG2 (R2014 onward), Matlab uipanels have finally become full-featured Java JPanels, that can be accessed and customized in many interesting manners. More to the point here, we can now directly access the underlying JPanel component handle using the uipanel‘s hidden JavaFrame property (thanks to MathWorks for supplying this useful hook!). The new findjobj version detects this and immediately returns this handle if the user specified a uipanel input.

I still do not know of any direct way to retrieve the underlying Java component’s handle for Matlab uicontrols, this has been a major frustration of mine for quite a few years. So, we need to find the containing Java container in which we will recursively search for the control’s underlying Java handle. In the old version of finjobj, we retrieve the containing figure’s JFrame reference and from it the ContentPane handle, and use this handle as the Java container that is recursively searched. This is quite slow when the figure window is heavily-laden with multiple controls. In the new version, we try to use the specified Matlab uicontrol‘s direct parent, which is very often a uipanel. In this case, we can directly retrieve the panel’s JPanel reference as explained above. This results in a must smaller and faster search since we need to recursively search far fewer controls within the container, compared to the figure’s ContentPane.

In addition, I used a suggestion by blog reader Hannes for a faster recursive search that uses the control’s tooltip rather than its size, position and class. Finally, the search order is reversed to search backward from the last child component, since this is the component that will most often contain the requested control peer.

Feel free to download and use the new findjobj version. The code for the fast variant can be found in lines #190-205 and #3375-3415.

Enjoy!

p.s. – as I explained last week, today’s discussion, and in general anything that has to do with Java peers of GUI controls, only relates to the existing JFrame-based figure windows, not to the new web-based uifigure.

Viewing all 219 articles
Browse latest View live