- Undocumented Matlab - https://undocumentedmatlab.com -

Customizing axes rulers

Posted By Yair Altman On October 8, 2014 | 20 Comments

Over 4 years have passed since I’ve posted my scoop [1] on Matlab’s upcoming new graphics system (a.k.a. HG2, Handle Graphics version 2). At that time HG2 was still far from usable, but that has changed when I posted my HG2 update [2] last year. Numerous user feedbacks, by email and blog comments, were reported and the MathWorks developers have listened and improved the code. HG2 was finally released with Matlab R2014b last Friday, and it seems at first glance to be a beauty. I hope my posts and the feedbacks have contributed, but in any case the MathWorks dev group deserves big kudos for releasing a totally new system that provides important usability and aesthetic improvements [almost] without sacrificing performance or backward-compatibility. Trust me, it’s not an easy achievement.

Customized HG2 plot
Customized HG2 plot

One of the nice things that I like about HG2 is that it provides numerous new ways to customize the objects in ways that were impossible (or nearly so) in the old HG1. In R2014b, the leap was large enough that MathWorks wisely chose to limit the official new properties to a bare minimum, for maximal HG1 compatibility. I assume that this will remain also in R2015a, which I expect to be a release devoted to bug fixing and stabilization rather than to new features. I expect the new features to start becoming official in R2015b onward. Such a measured roadmap is to be expected from a responsible engineering company such as MathWorks. So in fact there is no need at all to be disappointed at the relative lack of new functional features. They are all there already, just not yet official, and this is just as it should be.
That being said, if we are aware of the risk that these features might change in the upcoming years until they become official (if ever), then we can start using them today. Experience with this blog has shown that the vast majority of such undocumented features remain working unchanged for years, and some of them eventually become documented. For example, uitab/uitabgroup, on which I posted [3] over 4 years ago, and which has existed almost unchanged since 2005, finally became official in R2014b after many years of running in unofficial form.
In the next few weeks I intend to present a series of posts that highlight some of the undocumented customizations in HG2. I’ll start with some new axes features, followed by plotting aspects.

By the way, “HG2” is an internal name, that you will find scattered throughout the code but never in the official documentation. Apparently for marketing reasons, MathWorks chose to call it the “New Graphics Engine/System”. I’ll keep using the term HG2, as I think it sounds better than “NGE/NGS”. And besides, old habits die hard…

Axes Rulers

“Rulers” are the X, Y and Z axes lines and all their related aspects, including ticks, tick labels, and secondary label (see below). Some of the important aspects (e.g., ticks and tick labels) have mirror properties in the axes object, for convenience. The ruler objects can be accessed via the hidden properties (XRuler, YRuler and ZRuler, which can be seen using the getundoc [4] utility):

>> x = -10:0.1:10;
>> y = 1e7*sin(x)./x;
>> hLine = plot(x,y);
>> hAxes = gca;
>> yruler = hAxes.YRuler  % or: get(hAxes,'YRuler')
yruler =
    NumericRuler
>> class(yruler)
ans =
matlab.graphics.axis.decorator.NumericRuler
>> get(yruler)
                               Axle: [1x1 LineStrip]
                           Children: []
                              Color: [0.15 0.15 0.15]
                           Exponent: 6
                 FirstCrossoverAxis: 0
                FirstCrossoverValue: -Inf
                          FontAngle: 'normal'
                           FontName: 'Helvetica'
                           FontSize: 10
                      FontSmoothing: 'on'
                         FontWeight: 'normal'
                   HandleVisibility: 'off'
                              Label: [1x1 Text]
                          LineWidth: 0.5
                         MajorTicks: [1x1 LineStrip]
                          MinorTick: [1x7 double]
                         MinorTicks: []
                             Parent: [1x1 DecorationContainer]
    PlaceSecondaryLabelAtLowerLimit: 'off'
                              Scale: 'linear'
               SecondCrossoverValue: -Inf
                     SecondaryLabel: [1x1 Text]
                               Tick: [1x8 double]
                            TickDir: 'in'
                          TickLabel: {8x1 cell}
               TickLabelInterpreter: 'tex'
                  TickLabelRotation: 0
                         TickLabels: [1x1 Text]
                         TickLength: 3.255
                            Visible: 'on'

The ruler object itself has plenty of very useful hidden properties (getundoc again…). In R2014b the number of hidden properties for *ALL* objects has multiplied – many standard properties now have hidden internal mirror properties having the “_I” suffix. For example, Tick is a visible property, and Tick_I is hidden. But there are of course other properties that are hidden and are not such internal mirrors. Today I’ll focus on the ruler’s visible properties only.

Axle property

The Axle property controls the axis line, which is a solid black line by default:

>> get(yruler.Axle)
          AlignVertexCenters: 'on'
             AmbientStrength: 0.3
                ColorBinding: 'object'
                   ColorData: [4x1 uint8]
                   ColorType: 'truecolor'
             DiffuseStrength: 0.6
            HandleVisibility: 'off'
                     HitTest: 'off'
                       Layer: 'back'
                   LineStyle: 'solid'
                   LineWidth: 0.5
               NormalBinding: 'none'
                  NormalData: []
                      Parent: [1x1 NumericRuler]
               PickableParts: 'none'
    SpecularColorReflectance: 1
            SpecularExponent: 10
            SpecularStrength: 0.9
                   StripData: [1 3 5]
                     Texture: []
                  VertexData: [3x4 single]
               VertexIndices: []
                     Visible: 'on'
       WideLineRenderingHint: 'software'

As you can see, there are many ways by which we can customize the Axle. For example, let’s use a dotted green line instead of the default solid black line:

hAxes.YRuler.Axle.LineStyle = 'dotted';  % default: 'solid', also possible: dashdot, dashed, none
hAxes.YRuler.Axle.ColorData = uint8([0,100,0,255])';  %=dark green; default: [51 51 51 255], corresponding to [0.2 0.2 0.2 1]

The result can be seen in the screenshot above.
ColorData is closely related to ColorType, which is ‘truecolor’ by default. There are also the alternative ‘colormapped’, ‘texturemapped’, and ‘truecoloralpha’. We can see the various possible combinations if we try to issue an illegal ColorData value:

>> yruler.Axle.ColorData = [.1,.2,.3];
While setting the 'ColorData' property of LineStrip:
Value must be one of the following:
Truecolor  - a 4xN array of type uint8
Colormapped - a 1xN vector of type single
Texturemapped - a 2xN array of type single

For Truecoloralpha, the fourth color value (255 in the example above) signifies the relative transparency: 0=transparent, 255=opaque, and values between 0-255 indicate the degree of translucency.
Note that the default Axle.ColorData sometimes changes between [51 51 51 255] and [38 38 38 255], I’m not sure exactly when this happens. In some cases the YRuler may use ColorData=51 while XRuler uses 38 (which is slightly darker).
We can make interesting effects by specifying non-default VertexData endpoints (array of 3xN singles that should correspond to a 1xN uint32 StripData). For example, an axle that spans only part of the axis line… – have fun 🙂

Exponent and SecondaryLabel properties

The Exponent controls the computation of the tick label format. For example, in the example above Exponent=6 which means that SecondaryLabel.String=’\times10^{6}’. The exponent is automatically calculated by default, but we can override it to whatever integer we want (non-integer exponent values are rounded to the nearest integer):

hAxes.YRuler.Exponent = -3;

This way we can force the exponent to always have a certain value, or to always display engineering values (multiples of 3). We can do this by attaching a listener [5] to the corresponding axes’ limits, e.g. YLim for the Y-axes.
In addition to forcing the Exponent value, we can also specify a non-numeric SecondaryLabel. For example:

hAxes.YRuler.SecondaryLabel.String = 'millions';  % original: 'x10^{6}'
hAxes.YRuler.SecondaryLabel.FontAngle = 'italic';  % default: 'normal'
hAxes.YRuler.SecondaryLabel.Visible = 'on';  % default: 'off'
% Alternative:
set(hAxes.YRuler.SecondaryLabel, 'String','millions', 'FontAngle','italic', 'Visible','on');

The result can be seen in the screenshot above.

Call for action

Go ahead – play around with the new HG2. It’s a lot of fun and quite painless with the new object.property notation. If you have any feedback on the features above or any other, please do share them in a comment below. I’m quite sure that MathWorks will read these comments and this may be a way for you to influence the features that may someday become officially supported. More to the point, make your graphics become even more stunning then they have already become with out-of-the-box HG2!
The HG2 customization series will continue next week with a discussion of additional new axes properties, including Baseline, BoxFrame and GridHandle.

Categories: Handle graphics, Low risk of breaking in future versions, Stock Matlab function, Undocumented feature


20 Comments (Open | Close)

20 Comments To "Customizing axes rulers"

#1 Comment By nose holes On October 8, 2014 @ 08:00

Hi Yair,

At least on my system plotting huge data sets (scatter) is very slow.
The plot comes up fairly quick, however the control is not returned to the command line.
Afterwards is zooming also very slow.

Of course, one should check the amount of data, before plotting it, however in HG1 this could be done rather quickly.

#2 Comment By Adam On October 8, 2014 @ 16:02

Try updating your graphics drivers, the new graphics system uses hardware acceleration more so I think it’s more sensitive to such things than the old system. I updated mine and the graphics speed noticeably improved.

#3 Comment By the cyclist On October 8, 2014 @ 10:46

Perhaps related: Saving figures to disk (via the print command) also seems significantly slower.

#4 Comment By Rob On October 9, 2014 @ 10:35

I too find the printing of figures to be very very slow; just posted the question to Mathworks, especially if you use -painters

2013b >> tic;print('-dpng','-r300','-painters','test');toc
Elapsed time is 0.476110 seconds.

2014b >> tic;print('-dpng','-r300','-painters','test');toc
Elapsed time is 6.714240 seconds

#5 Comment By Yair Altman On October 9, 2014 @ 10:46

Have you tried to update your display drivers?

#6 Comment By Robert Cumming On October 8, 2014 @ 13:18

One change I noticed is that the area where the ButtonDownFcn is active has changed. In previous versions it was active where the axes was active and where the x and y tick labels are (and in the white space inbetween), where as now it is not active in the white space inbetween the tick marks.

To see what I mean type:

axes ( 'ButtonDownFcn', @(a,b)disp ( 'Callback activated' ) )

Then click (callback will run) where the x/y tick labels are (e.g on top of 0, 0.1, 0.2 …. 1.0) and then click in the space between them (callback will not run), in previous version (all the way back to at R13) clicking in between the labels also activated the ButtonDownFcn callback.
I have used this callback for many years to [12] with the mouse.

#7 Pingback By Customizing axes part 2 | Undocumented Matlab On October 15, 2014 @ 07:11

[…] Customizing axes rulers […]

#8 Comment By Oleg Komarov On October 16, 2014 @ 16:33

After setting the secondary label to ‘millions’, you forgot to put:

hAxes.YRuler.SecondaryLabel.Visible = 'on'

#9 Comment By Yair Altman On October 16, 2014 @ 23:14

Thanks Oleg – fixed.

#10 Comment By Matthew Dzieciuch On October 20, 2014 @ 12:31

I would like to add my voice to the disappointment with HG2. Although it may be great from a programming perspective, it is significantly slower for me. Specifically, the scatter plot function performance is awful: it went from a 1.4 second elapsed time to a 22.6 elapsed time. My interactive program has become unusable. I have expressed my displeasure to the Mathworks, and although I found a sympathetic support engineer (who was able to reproduce the problem), all he could offer for help was the fact that he had informed the development team.

If an upgrade destroys performance, it can hardly be called an improvement.
Matt

#11 Comment By Yair Altman On October 20, 2014 @ 12:41

@Matthew – is your 14b using hardware OpenGL? some HG2 performance issues are due to the fact that it uses more advanced OpenGL features than HG1, so what used to run at hardware-acceleration speed on 14a (HG1) may now run at much slower software speed in 14b (HG2). Upgrading the display driver sometimes helps. I [13].

Of course, upgrading the driver is not an all-encompassing panacea. Performance issues have been an ongoing issue with HG2. I know for a fact that MathWorks are investing a lot of effort to improve this, but it might take another release or two for things to really settle down.

#12 Comment By Yair Altman On October 20, 2014 @ 12:47

As an alternative, try to improve the performance of your scatter plot by either [14] (as odd as it may sound, scatter-plotting 80 points is slower than plotting 2×80=160 points!), or [15].

#13 Pingback By Customizing axes part 3 – Backdrop | Undocumented Matlab On October 22, 2014 @ 23:38

[…] In the past two weeks I explained how HG2 (in R2014b) enables us to customize the axes rulers, baselines, box and grid-lines in ways that were previously impossible in HG1 (R2014a or earlier). […]

#14 Comment By Leo Simon On April 10, 2016 @ 20:35

YRuler is great, but it would be lots better if one could customize individual elements of arrays like YTickLabel, etc. For example, I often draw a horizontal line, add the height of the line to YTick, and give the tick a custom label. What I’d then like to do is highlight my added label with a different color, font, etc. But it doesn’t appear possible with the current setup. It seems like this would be a simple thing for matlab to add. Or is there some other undocumented way that I can do that already??

#15 Comment By vaishta On July 25, 2018 @ 12:07

I have a GUI which has few pushbuttons using which I generate plots
1. In one of the pushbutton callback I use the ax = gca and set its position to make plots in at three different positions
2. In second pushbutton callback I use the ax = gca and set its position to make only one plot i.e at only one position.

However, when I press pushbutton next time, it still retains the old Axis values although it replaces data from plot. It appears very cluttered. This happens every time I use the pushbutton.
How can I clear the axes and set it fresh so that old axes and its values disappear ?

I have already tried these options below but no use … it still shows the old axes labels/tick labels etc.

ax = gca
delete(ax.Children)
ax.YRuler.Axle.LineStyle = 'none';
ax.XRuler.Axle.LineStyle = 'none';
ax.YRuler.HandleVisibility = 'off';
ax.XRuler.HandleVisibility = 'off';

#16 Comment By Yair Altman On July 25, 2018 @ 12:14

@Vaishta – gca (=”get current axes”) only gets updated when you click or create an axes. If you want your button’s callback to refer to a specific axes, which may or may not be the currently-active axes, you should use not gca but the actual axes handle (the output of the axes function). Read the Matlab documentation for more information.

#17 Comment By vaishta On July 25, 2018 @ 12:40

Thank you for information. Can you tell how to implement it in pushbutton callback ?
Because when I use following code

ax = ax1; ax = ax2; ax= ax3;
delete(ax1);delete(ax2);delete(ax3) 
...
...
ax1 = axes(...,'Position',[...])
plot(ax1,...)
ax2 = axes(...,'Position',[...])
plot(ax2,...)
ax3 = axes(...,'Position',[...])
plot(ax3,...)

at beginning of callback to delete axes handle
it throws error undefined function or variable ax1, ax2, … ax3

#18 Comment By vaishta On July 25, 2018 @ 13:51

I have also tried the

set(ax1,'NextPlot','replaceall')
set(ax2,'NextPlot','replaceall')
set(ax3,'NextPlot','replaceall')

in the callback after the plot() function but its of no use … it still shows the old axes line, ticks and labels.
including the @axes1_DeleteFcn option in the callback but no use …

#19 Comment By Yair Altman On July 25, 2018 @ 14:06

@Vaishta – you have to read the Matlab documentation about how to create GUI callbacks and how to share data between GUI components/callbacks ( [16]). In general, you need to store the axes handles in a location that is accessible to the callback function (for example, in the button’s UserData property). It looks like you’re using GUIDE to create your GUI, and in this case you could also access the axes handles via the handles structure.

I’m afraid that all this is pretty basic Matlab GUI stuff, which is not the subject of this blog – this blog specializes on advanced aspects, I leave the basics to the Matlab documentation and other forums/blogs. If you’re still having problems with this, you could either post a question on the [17] forum, or contact me offline for a private consulting session.

#20 Comment By James P. Herman On July 9, 2019 @ 06:18

Any thoughts on how to preserve axis offset in an exported PDF? Using export_fig or print both seem to restore the full size of the ruler:

clear
close all

% make figure window
fh = figure('Color', [1 1 1]);

% make axes
ax = axes;

% plot some data
p = plot(randn(100,1));

% make sure objects have been created
drawnow;

% set axis properties
ax.Box     = 'Off';
ax.XLim    = [-10 110];
ax.XTick   = 0:25:100;
ax.YLim    = 4 * [-1 1];
ax.YTick   = -3:3;
ax.TickDir = 'Out';

% offset
ax.XAxis.Axle.VertexData = single([0 100; -4 -4; -1 1]);
ax.YAxis.Axle.VertexData = single([-10 -10; -3 3; -1 1]);

% print
print('-bestfit','-dpdf','-opengl','test');

Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/customizing-axes-rulers

URLs in this post:

[1] scoop: http://undocumentedmatlab.com/blog/matlab-hg2

[2] HG2 update: http://undocumentedmatlab.com/blog/hg2-update

[3] posted: http://undocumentedmatlab.com/blog/tab-panels-uitab-and-relatives

[4] getundoc: http://undocumentedmatlab.com/blog/getundoc-get-undocumented-object-properties

[5] attaching a listener: http://undocumentedmatlab.com/blog/property-value-change-listeners

[6] Customizing axes part 2 : https://undocumentedmatlab.com/articles/customizing-axes-part-2

[7] Customizing axes part 5 – origin crossover and labels : https://undocumentedmatlab.com/articles/customizing-axes-part-5-origin-crossover-and-labels

[8] Customizing axes part 3 – Backdrop : https://undocumentedmatlab.com/articles/customizing-axes-part-3-backdrop

[9] Customizing axes part 4 – additional properties : https://undocumentedmatlab.com/articles/customizing-axes-part-4-additional-properties

[10] Customizing axes tick labels : https://undocumentedmatlab.com/articles/customizing-axes-tick-labels

[11] Axes LooseInset property : https://undocumentedmatlab.com/articles/axes-looseinset-property

[12] : https://sites.google.com/site/matpihome/matlab-gui-framework/iaxes

[13] : https://undocumentedmatlab.com/blog/customizing-axes-part-2#performance

[14] : https://undocumentedmatlab.com/blog/undocumented-scatter-plot-behavior

[15] : https://undocumentedmatlab.com/blog/performance-scatter-vs-line

[16] : https://www.mathworks.com/help/matlab/creating_guis/share-data-among-callbacks.html

[17] : https://www.mathworks.com/matlabcentral/answers/

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.