When HG2 graphics was finally released in R2014b, I posted a series of articles about various undocumented ways by which we can customize Matlab’s new graphic axes: rulers (axles), baseline, box-frame, grid, back-drop, and other aspects. Today I extend this series by showing how we can customize the axes rulers’ crossover location.
The documented/supported stuff
Until R2015b, we could only specify the axes’ YAxisLocation as 'left'
(default) or 'right'
, and XAxisLocation as 'bottom'
(default) or 'top'
. For example:
x = -2*pi : .01 : 2*pi; plot(x, sin(x)); hAxis = gca; hAxis.YAxisLocation = 'left'; % 'left' (default) or 'right' hAxis.XAxisLocation = 'bottom'; % 'bottom' (default) or 'top' |
The crossover location is non-fixed in the sense that if we zoom or pan the plot, the axes crossover will remain at the bottom-left corner, which changes its coordinates depending on the X and Y axes limits.
Since R2016a, we can also specify
'origin'
for either of these properties, such that the X and/or Y axes pass through the chart origin (0,0) location. For example, move the YAxisLocation to the origin:
hAxis.YAxisLocation = 'origin'; |
And similarly also for XAxisLocation:
hAxis.XAxisLocation = 'origin'; |
The axes crossover location is now fixed at the origin (0,0), so as we move or pan the plot, the crossover location changes its position in the chart area, without changing its coordinates. This functionality has existed in other graphic packages (outside Matlab) for a long time and until now required quite a bit of coding to emulate in Matlab, so I’m glad that we now have it in Matlab by simply updating a single property value. MathWorks did a very nice job here of dynamically updating the axles, ticks and labels as we pan (drag) the plot towards the edges – try it out!
The undocumented juicy stuff
So far for the documented stuff. The undocumented aspect is that we are not limited to using the (0,0) origin point as the fixed axes crossover location. We can use any x,y crossover location, using the FirstCrossoverValue property of the axes’ hidden XRuler and YRuler properties. In fact, we could do this since R2014b, when the new HG2 graphics engine was released, not just starting in R2016a!
% Set a fixed crossover location of (pi/2,-0.4) hAxis.YRuler.FirstCrossoverValue = pi/2; hAxis.XRuler.FirstCrossoverValue = -0.4; |
For some reason (bug?), setting XAxisLocation/YAxisLocation to ‘origin’ has no visible effect in 3D plots, nor is there any corresponding ZAxisLocation property. Luckily, we can set the axes crossover location(s) in 3D plots using FirstCrossoverValue just as easily as for 2D plots. The rulers also have a SecondCrossoverValue property (default = -inf) that controls the Z-axis crossover, as Yaroslav pointed out in a comment below. For example:
N = 49; x = linspace(-10,10,N); M = peaks(N); mesh(x,x,M); |
hAxis.XRuler.FirstCrossoverValue = 0; % X crossover with Y axis hAxis.YRuler.FirstCrossoverValue = 0; % Y crossover with X axis hAxis.ZRuler.FirstCrossoverValue = 0; % Z crossover with X axis hAxis.ZRuler.SecondCrossoverValue = 0; % Z crossover with Y axis |
hAxis.XRuler.SecondCrossoverValue = 0; % X crossover with Z axis hAxis.YRuler.SecondCrossoverValue = 0; % Y crossover with Z axis |
Labels
Users will encounter the following unexpected behavior (bug?) when using either the documented *AxisLocation or the undocumented FirstCrossoverValue properties: when setting an x-label (using the xlabel function, or the internal axes properties), the label moves from the center of the axes (as happens when XAxisLocation=’top’ or ‘bottom’) to the right side of the axes, where the secondary label (e.g., exponent) usually appears, whereas the secondary label is moved to the left side of the axis:
In such cases, we would expect the labels locations to be reversed, with the main label on the left and the secondary label in its customary location on the right. The exact same situation occurs with the Y labels, where the main label unexpectedly appears at the top and the secondary at the bottom. Hopefully MathWorks will fix this in the next release (it is probably too late to make it into R2016b, but hopefully R2017a). Until then, we can simply switch the strings of the main and secondary label to make them appear at the expected locations:
% Switch the Y-axes labels: ylabel(hAxis, '\times10^{3}'); % display secondary ylabel (x10^3) at top set(hAxis.YRuler.SecondaryLabel, 'Visible','on', 'String','main y-label'); % main label at bottom % Switch the X-axes labels: xlabel(hAxis, '2^{nd} label'); % display secondary xlabel at right set(hAxis.XRuler.SecondaryLabel, 'Visible','on', 'String','xlabel'); % main label at left |
As can be seen from the screenshot, there’s an additional nuisance: the main label appears a bit larger than the axes font size (the secondary label uses the correct font size). This is because by default Matlab uses a 110% font-size for the main axes label, ostensibly to make them stand out. We can modify this default factor using the rulers’ hidden LabelFontSizeMultiplier property (default=1.1). For example:
hAxis.YRuler.LabelFontSizeMultiplier = 1; % use 100% font-size (same as tick labels) hAxis.XRuler.LabelFontSizeMultiplier = 0.8; % use 80% (smaller than standard) font-size |
Note: I described the ruler objects in my first article of the axes series. Feel free to read it for more ideas on customizing the axes rulers.
Hi Yair,
Great post yet again. It is worth mentioning that your methods can be extended to 3 dimensional plots, which are currently unsupported. For example,
@Yaroslav – thanks! I updated the text accordingly.
Hi Yarasov/Yair,
Context: I am using R2015a to display a ternary three-dimensional plot, so I have a base equilateral triangle and a vertical axis on top of this.
My question: When copying the above code in Matlab, I get an error when using the “ZRuler” command.
Do you have an idea why it might not be working in my case?
Many thanks!
Yair,
Great site!
I have been moving axes to cross at the origin as part of plotting for years and I’m glad to see MATLAB adopt this capability. One question though.
How could I make this the default behavior?
Does not work in 2015b, though the property exists and can be modified. Also similar syntax works for other axes properties (‘DefaultAxesLineWidth’).
Thanks for the help,
Frank
@Frank –
(you forgot the “Axes” part in ‘defaultAxesYAxisLocation’)
Thank you!
Hi Yair,
Great post. i tried to rotate the axes in a 3d graph in Matlab. but i couldn’t do that. i have two Point Cloud, which i need to calculate the distance between them. As result want to represent it in a Heatmap with a coded Colormap. My project have Orientation according to the global cartesian coordinate system (measured with Totalstation scanner). I monitor facade of a Building (detect Moving in x,z plane). I want to change the Orientation of my Point cloud along x, y and z to have a good front view of the Project (not distorted). how can i rotate the Axes suitable to my project? Thanks for your help.
Reza – try using the view function.
Thank you Yair!
In order to analyze the deformation of a surface, I would like to monitor this surface (facade of a building) every 2 hours, for example. so I get every 2 hours a point cloud I have to compare with a reference 3d-surface. How can I represent the distance between the surface and the point cloud as a colored figure?
I couldnt find any method or function in matlab to do that.
do you Any idea to do this?
I would be grateful for a answer, help, ideas or suggestions.
I would just like to thank you for your fantastic work. I was looking for ages for a SIMPLE way to do this!
Thanks for the great help
I want to know how to change the x-axis to the z-axis. I mean the position. Like if there is a 3d animated graph then how to change position of the axis. X-axis in place of Z-Axis & Y- axis in place of Z-axis and Z in place of Y.
@Sagar – use the view(az,el) function to rotate the 3D axes.