Undocumented Matlab
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT
  • SERVICES
    • Consulting
    • Development
    • Training
    • Gallery
    • Testimonials
  • PRODUCTS
    • IQML: IQFeed-Matlab connector
    • IB-Matlab: InteractiveBrokers-Matlab connector
    • EODML: EODHistoricalData-Matlab connector
    • Webinars
  • BOOKS
    • Secrets of MATLAB-Java Programming
    • Accelerating MATLAB Performance
    • MATLAB Succinctly
  • ARTICLES
  • ABOUT
    • Policies
  • CONTACT

Improving graphics interactivity

April 22, 2019 2 Comments

Matlab release R2018b added the concept of axes-specific toolbars and default axes mouse interactivity. Accelerating MATLAB Performance Plain 2D plot axes have the following default interactions enabled by default: PanInteraction, ZoomInteraction, DataTipInteraction and RulerPanInteraction.

Unfortunately, I find that while the default interactions set is much more useful than the non-interactive default axes behavior in R2018a and earlier, it could still be improved in two important ways:

  1. Performance – Matlab’s builtin Interaction objects are very inefficient. In cases of multiple overlapping axes (which is very common in multi-tab GUIs or cases of various types of axes), instead of processing events for just the top visible axes, they process all the enabled interactions for *all* axes (including non-visible ones!). This is particularly problematic with the default DataTipInteraction – it includes a Linger object whose apparent purpose is to detect when the mouse lingers for enough time on top of a chart object, and displays a data-tip in such cases. Its internal code is both inefficient and processed multiple times (for each of the axes), as can be seen via a profiling session.
  2. Usability – In my experience, RegionZoomInteraction (which enables defining a region zoom-box via click-&-drag) is usually much more useful than PanInteraction for most plot types. ZoomInteraction, which is enabled by default only enables zooming-in and -out using the mouse-wheel, which is much less useful and more cumbersome to use than RegionZoomInteraction. The panning functionality can still be accessed interactively with the mouse by dragging the X and Y rulers (ticks) to each side.

For these reasons, I typically use the following function whenever I create new axes, to replace the default sluggish DataTipInteraction and PanInteraction with RegionZoomInteraction:

function axDefaultCreateFcn(hAxes, ~)
    try
        hAxes.Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction];
        hAxes.Toolbar = [];
    catch
        % ignore - old Matlab release
    end
end

function axDefaultCreateFcn(hAxes, ~) try hAxes.Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction]; hAxes.Toolbar = []; catch % ignore - old Matlab release end end

The purpose of these two axes property changes shall become apparent below.
This function can either be called directly (axDefaultCreateFcn(hAxes), or as part of the containing figure’s creation script to ensure than any axes created in this figure has this fix applied:

set(hFig,'defaultAxesCreateFcn',@axDefaultCreateFcn);

set(hFig,'defaultAxesCreateFcn',@axDefaultCreateFcn);

Test setup

Figure with default axes toolbar and interactivity
Figure with default axes toolbar and interactivity
To test the changes, let’s prepare a figure with 10 tabs, with 10 overlapping panels and a single axes in each tab:

hFig = figure('Pos',[10,10,400,300]);
hTabGroup = uitabgroup(hFig);
for iTab = 1 : 10
    hTab = uitab(hTabGroup, 'title',num2str(iTab));
    hPanel = uipanel(hTab);
    for iPanel = 1 : 10
        hPanel = uipanel(hPanel);
    end
    hAxes(iTab) = axes(hPanel); %see MLint note below
    plot(hAxes(iTab),1:5,'-ob');
end
drawnow

hFig = figure('Pos',[10,10,400,300]); hTabGroup = uitabgroup(hFig); for iTab = 1 : 10 hTab = uitab(hTabGroup, 'title',num2str(iTab)); hPanel = uipanel(hTab); for iPanel = 1 : 10 hPanel = uipanel(hPanel); end hAxes(iTab) = axes(hPanel); %see MLint note below plot(hAxes(iTab),1:5,'-ob'); end drawnow

p.s. – there’s a incorrect MLint (Code Analyzer) warning in line 9 about the call to axes(hPanel) being inefficient in a loop. Apparently, MLint incorrectly parses this function call as a request to make the axes in-focus, rather than as a request to create the axes in the specified hPanel parent container. We can safely ignore this warning.

Now let’s create a run-time test script that simulates 2000 mouse movements using java.awt.Robot:

tic
monitorPos = get(0,'MonitorPositions');
y0 = monitorPos(1,4) - 200;
robot = java.awt.Robot;
for iEvent = 1 : 2000
    robot.mouseMove(150, y0+mod(iEvent,100));
    drawnow
end
toc

tic monitorPos = get(0,'MonitorPositions'); y0 = monitorPos(1,4) - 200; robot = java.awt.Robot; for iEvent = 1 : 2000 robot.mouseMove(150, y0+mod(iEvent,100)); drawnow end toc

This takes ~45 seconds to run on my laptop: ~23ms per mouse movement on average, with noticeable “linger” when the mouse pointer is near the plotted data line. Note that this figure is extremely simplistic – In a real-life program, the mouse events processing lag the mouse movements, making the GUI far more sluggish than the same GUI on R2018a or earlier. In fact, in one of my more complex GUIs, the entire GUI and Matlab itself came to a standstill that required killing the Matlab process, just by moving the mouse for several seconds.

Notice that at any time, only a single axes is actually visible in our test setup. The other 9 axes are not visible although their Visible property is 'on'. Despite this, when the mouse moves within the figure, these other axes unnecessarily process the mouse events.

Changing the default interactions

Let’s modify the axes creation script as I mentioned above, by changing the default interactions (note the highlighted code addition):

hFig = figure('Pos',[10,10,400,300]);
hTabGroup = uitabgroup(hFig);
for iTab = 1 : 10
    hTab = uitab(hTabGroup, 'title',num2str(iTab));
    hPanel = uipanel(hTab);
    for iPanel = 1 : 10
        hPanel = uipanel(hPanel);
    end
    hAxes(iTab) = axes(hPanel);
    plot(hAxes(iTab),1:5,'-ob');
    hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction];end
drawnow

hFig = figure('Pos',[10,10,400,300]); hTabGroup = uitabgroup(hFig); for iTab = 1 : 10 hTab = uitab(hTabGroup, 'title',num2str(iTab)); hPanel = uipanel(hTab); for iPanel = 1 : 10 hPanel = uipanel(hPanel); end hAxes(iTab) = axes(hPanel); plot(hAxes(iTab),1:5,'-ob'); hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction]; end drawnow

The test script now takes only 12 seconds to run – 4x faster than the default and yet IMHO with better interactivity (using RegionZoomInteraction).

Effects of the axes toolbar

The axes-specific toolbar, another innovation of R2018b, does not just have interactivity aspects, which are by themselves much-contested. A much less discussed aspect of the axes toolbar is that it degrades the overall performance of axes. The reason is that the axes toolbar’s transparency, visibility, background color and contents continuously update whenever the mouse moves within the axes area.

Since we have set up the default interactivity to a more-usable set above, and since we can replace the axes toolbar with figure-level toolbar controls, we can simply delete the axes-level toolbars for even more-improved performance:

hFig = figure('Pos',[10,10,400,300]);
hTabGroup = uitabgroup(hFig);
for iTab = 1 : 10
    hTab = uitab(hTabGroup, 'title',num2str(iTab));
    hPanel = uipanel(hTab);
    for iPanel = 1 : 10
        hPanel = uipanel(hPanel);
    end
    hAxes(iTab) = axes(hPanel);
    plot(hAxes(iTab),1:5,'-ob');
    hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction];
    hAxes(iTab).Toolbar = [];end
drawnow

hFig = figure('Pos',[10,10,400,300]); hTabGroup = uitabgroup(hFig); for iTab = 1 : 10 hTab = uitab(hTabGroup, 'title',num2str(iTab)); hPanel = uipanel(hTab); for iPanel = 1 : 10 hPanel = uipanel(hPanel); end hAxes(iTab) = axes(hPanel); plot(hAxes(iTab),1:5,'-ob'); hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction]; hAxes(iTab).Toolbar = []; end drawnow

This brings the test script’s run-time down to 6 seconds – 7x faster than the default run-time. At ~3ms per mouse event, the GUI is now as performant and snippy as in R2018a, even with the new interactive mouse actions of R2018b active.

Conclusions

MathWorks definitely did not intend for this slow-down aspect, but it is an unfortunate by-product of the choice to auto-enable DataTipInteraction and of its sub-optimal implementation. Perhaps this side-effect was never noticed by MathWorks because the testing scripts probably had only a few axes in a very simple figure – in such a case the performance lags are very small and might have slipped under the radar. But I assume that many real-life complex GUIs will display significant lags in R2018b and newer Matlab releases, compared to R2018a and earlier releases. I assume that such users will be surprised/dismayed to discover that in R2018b their GUI not only interacts differently but also runs slower, although the program code has not changed.

One of the common claims that I often hear against using undocumented Matlab features is that the program might break in some future Matlab release that would not support some of these features. But users certainly do not expect that their programs might break in new Matlab releases when they only use documented features, as in this case. IMHO, this case (and others over the years) demonstrates that using undocumented features is usually not much riskier than using the standard documented features with regards to future compatibility, making the risk/reward ratio more favorable. In fact, of the ~400 posts that I have published in the past decade (this blog is already 10 years old, time flies…), very few tips no longer work in the latest Matlab release. When such forward compatibility issues do arise, whether with fully-documented or undocumented features, we can often find workarounds as I have shown above.

If your Matlab program could use a performance boost, I would be happy to assist making your program faster and more responsive. Don’t hesitate to reach out to me for a consulting quote.

Related posts:

  1. Undocumented HG2 graphics events – Matlab's new HG2 graphics engine includes many new undocumented events that could be used in various ways. ...
  2. Handle Graphics Behavior – HG behaviors are an important aspect of Matlab graphics that enable custom control of handle functionality. ...
  3. Improving save performance – There are many different ways of improving Matlab's standard save function performance. ...
  4. Waterloo graphics – Waterloo is an open-source library that can significantly improve Matlab GUI. ...
  5. Improving fwrite performance – Standard file writing performance can be improved in Matlab in surprising ways. ...
  6. Waterloo graphics examples – Some Matlab usage examples for the open-source Waterloo graphics package. ...
GUI Handle graphics Performance Pure Matlab Toolbar
Print Print
« Previous
Next »
2 Responses
  1. Andreas May 21, 2019 at 10:23 Reply

    Great article.

    Do you know if something changed with R2019a? Is MathWorks working on this new “feature” and improving it?

    • Yair Altman May 21, 2019 at 11:07 Reply

      @Andreas – as far as I could see there is no change in R2019a.

  2. Doug May 24, 2019 at 15:26 Reply

    I’d love to be able to customize the appearance of the axes toolbar rather than replacing it. Frustratingly my attempts have led to not very much success, I can move it from it’s current location fairly easily and resize it once it’s visible, but the size is reset every time the menu appears. I wonder if anyone else has had any success?

  3. Jeremiah July 5, 2019 at 18:26 Reply

    I tried to run your function during a figure(…) creation and it removes the axes toolbar but it does not change the interactions. Those only work once the axes is already created and then I change them. But I’d like to have this automated, even in the startup.m script. Can you think of why the toolbar portion works but the interactions don’t while used as a defaultAxesCreationFcn ?

    • Yair Altman July 5, 2019 at 19:00 Reply

      @Jeremiah – perhaps the default interactions are implemented only as the last step in the axes creation sequence, after the user-specified AxesCreationFcn callback has already executed.

  4. Komutan Logar September 29, 2019 at 15:49 Reply

    Thank you very much. I’m using dynamic plotting, moving particles, only one figure created as a digraph. The performance has slightly improved and I also didn’t need the toolbox and interactions(I removed them all) anyway. I would like to ask if it makes any difference if I remove the toolbox and interactions in the AxesCreationFcn or after the figure is created by using ax = gca; ax.Interactions = []; ?

  5. Collin October 1, 2019 at 03:35 Reply

    A potential lightweight alternative to the standard axes toolbar is the FloatingPalette

    hFTB = controllib.plot.internal.FloatingPalette(FigureHandle, ButtonList)

    hFTB = controllib.plot.internal.FloatingPalette(FigureHandle, ButtonList)

    It’s not as pretty as the standard axes toolbar and has less button options but does not fade, works best for single axes figures.

    You need to set the standard toolbar invisible or set it to empty before creating the floating palette.

    hAxes.Toolbar.Visible = 'off';  % or:
    hAxes.Toolbar = [];

    hAxes.Toolbar.Visible = 'off'; % or: hAxes.Toolbar = [];

  6. Mike March 16, 2020 at 17:47 Reply

    When I use the suggestion above to set the ‘defaultAxesCreateFcn’, it works as expected in that the axes toolbar is gone and the default behavior is to zoom. However, double-click does not reset the axes as it does when i manually select the zooming tool. Is there an easy way around this?

  7. Alessandro Beda May 5, 2023 at 09:21 Reply

    I found what I think is a bug related to this (tested in R2022 and R2023a). If I add a “ButtonDownFcn” to the plots (see example below), then the modified interaction stops working completely.

    hFig = figure('Pos',[10,10,400,300]);
    hTabGroup = uitabgroup(hFig);
    for iTab = 1 : 10
        hTab = uitab(hTabGroup, 'title',num2str(iTab));
        hPanel = uipanel(hTab);
        for iPanel = 1 : 10
            hPanel = uipanel(hPanel);
        end
        hAxes(iTab) = axes(hPanel); %see MLint note below
        plot(hAxes(iTab),1:5,'-ob','ButtonDownFcn','disp("hello")');
        hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction];
        hAxes(iTab).Toolbar = [];
    end
    drawnow

    hFig = figure('Pos',[10,10,400,300]); hTabGroup = uitabgroup(hFig); for iTab = 1 : 10 hTab = uitab(hTabGroup, 'title',num2str(iTab)); hPanel = uipanel(hTab); for iPanel = 1 : 10 hPanel = uipanel(hPanel); end hAxes(iTab) = axes(hPanel); %see MLint note below plot(hAxes(iTab),1:5,'-ob','ButtonDownFcn','disp("hello")'); hAxes(iTab).Interactions = [zoomInteraction regionZoomInteraction rulerPanInteraction]; hAxes(iTab).Toolbar = []; end drawnow

    Is this an expected behaviour?

Leave a Reply
HTML tags such as <b> or <i> are accepted.
Wrap code fragments inside <pre lang="matlab"> tags, like this:
<pre lang="matlab">
a = magic(3);
disp(sum(a))
</pre>
I reserve the right to edit/delete comments (read the site policies).
Not all comments will be answered. You can always email me (altmany at gmail) for private consulting.

Click here to cancel reply.

Useful links
  •  Email Yair Altman
  •  Subscribe to new posts (feed)
  •  Subscribe to new posts (reader)
  •  Subscribe to comments (feed)
 
Accelerating MATLAB Performance book
Recent Posts

Speeding-up builtin Matlab functions – part 3

Improving graphics interactivity

Interesting Matlab puzzle – analysis

Interesting Matlab puzzle

Undocumented plot marker types

Matlab toolstrip – part 9 (popup figures)

Matlab toolstrip – part 8 (galleries)

Matlab toolstrip – part 7 (selection controls)

Matlab toolstrip – part 6 (complex controls)

Matlab toolstrip – part 5 (icons)

Matlab toolstrip – part 4 (control customization)

Reverting axes controls in figure toolbar

Matlab toolstrip – part 3 (basic customization)

Matlab toolstrip – part 2 (ToolGroup App)

Matlab toolstrip – part 1

Categories
  • Desktop (45)
  • Figure window (59)
  • Guest bloggers (65)
  • GUI (165)
  • Handle graphics (84)
  • Hidden property (42)
  • Icons (15)
  • Java (174)
  • Listeners (22)
  • Memory (16)
  • Mex (13)
  • Presumed future risk (394)
    • High risk of breaking in future versions (100)
    • Low risk of breaking in future versions (160)
    • Medium risk of breaking in future versions (136)
  • Public presentation (6)
  • Semi-documented feature (10)
  • Semi-documented function (35)
  • Stock Matlab function (140)
  • Toolbox (10)
  • UI controls (52)
  • Uncategorized (13)
  • Undocumented feature (217)
  • Undocumented function (37)
Tags
AppDesigner (9) Callbacks (31) Compiler (10) Desktop (38) Donn Shull (10) Editor (8) Figure (19) FindJObj (27) GUI (141) GUIDE (8) Handle graphics (78) HG2 (34) Hidden property (51) HTML (26) Icons (9) Internal component (39) Java (178) JavaFrame (20) JIDE (19) JMI (8) Listener (17) Malcolm Lidierth (8) MCOS (11) Memory (13) Menubar (9) Mex (14) Optical illusion (11) Performance (78) Profiler (9) Pure Matlab (187) schema (7) schema.class (8) schema.prop (18) Semi-documented feature (6) Semi-documented function (33) Toolbar (14) Toolstrip (13) uicontrol (37) uifigure (8) UIInspect (12) uitable (6) uitools (20) Undocumented feature (187) Undocumented function (37) Undocumented property (20)
Recent Comments
Contact us
Captcha image for Custom Contact Forms plugin. You must type the numbers shown in the image
Undocumented Matlab © 2009 - Yair Altman
This website and Octahedron Ltd. are not affiliated with The MathWorks Inc.; MATLAB® is a registered trademark of The MathWorks Inc.
Scroll to top