Customizing axes rulers

Over 4 years have passed since I’ve posted my scoop 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 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 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 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 = 
>> class(yruler)
ans =
>> 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 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 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

Tags: , , , ,

Bookmark and SharePrint Print

14 Responses to Customizing axes rulers

  1. nose holes says:

    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.

    • Adam says:

      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.

  2. the cyclist says:

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

    • Rob says:

      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
    • Have you tried to update your display drivers?

  3. 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 zoom in/out and reset scaling interactively with the mouse.

  4. Pingback: Customizing axes part 2 | Undocumented Matlab

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

    hAxes.YRuler.SecondaryLabel.Visible = 'on'
  6. Matthew Dzieciuch says:

    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.

    • Yair Altman says:

      @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 discussed this last week.

      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.

    • Yair Altman says:

      As an alternative, try to improve the performance of your scatter plot by either plotting a vector of 100+ points (as odd as it may sound, scatter-plotting 80 points is slower than plotting 2×80=160 points!), or use the low-level line function rather than scatter.

  7. Pingback: Customizing axes part 3 – Backdrop | Undocumented Matlab

  8. Leo Simon says:

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

Leave a Reply

Your email address will not be published. Required fields are marked *