File Exchange

image thumbnail

rotateXLabels( ax, angle, varargin )

version 1.5.0.1 (18.1 KB) by

Rotate x-tick labels to any angle, preserving font settings and coping with resize, zoom, pan etc

4.71429
45 Ratings

25 Downloads

Updated

View License

<b>NB: As of R2014b this functionality is built into MATLAB axes using the 'XTickLabelRotation' property.</b>
This function rotates the x-tick labels on a plot. An arbitrary angle can be specified for the text and the label justification adjusts appropriately to ensure the labels lie below the ticks. The axes font properties are preserved in the labels, which will update in response to font changes. Changes to the axes limits are also handled.
Main features:
* Arbitrary angle of rotation
* Justification adjusts appropriately for the specified angle
* Axes font property changes are reflected
* Labels move correctly when zooming and panning

As with other functions that achieve the same result, this works by replacing the xtick labels with text objects. Handles to the created text objects are returned for you to tinker with.

Comments and Ratings (78)

imu931

imu931 (view profile)

Thanks a lot!

Sevda Aslan

John

John (view profile)

Abhinav

Excellent codes, works very well.

Kevin

Kevin (view profile)

Works perfectly

Works good ! thank's

Perfect!

jimmy Hsu

Thanks a lot!!!

Aaron Diaz

I had to change the addListeners() function to the following to get it to work in R2015a

function addListeners( ax )
% Create listeners. We store the array of listeners in the axes to make
% sure that they have the same life-span as the axes they are listening to.
axh = handle( ax );
listeners = [
addlistener( axh, findprop( axh, 'FontName' ), 'PostSet', @onAxesFontChanged )
addlistener( axh, findprop( axh, 'FontSize' ), 'PostSet', @onAxesFontChanged )
addlistener( axh, findprop( axh, 'FontWeight' ), 'PostSet', @onAxesFontChanged )
addlistener( axh, findprop( axh, 'FontAngle' ), 'PostSet', @onAxesFontChanged )
addlistener( axh, findprop( axh, 'FontUnits' ), 'PostSet', @onAxesFontChanged )
addlistener( axh, findprop( axh, 'OuterPosition' ), 'PostSet', @onAxesPositionChanged )
addlistener( axh, findprop( axh, 'XLim' ), 'PostSet', @onAxesLimitsChanged )
addlistener( axh, findprop( axh, 'YLim' ), 'PostSet', @onAxesLimitsChanged )
addlistener( axh, findprop( axh, 'XAxisLocation' ), 'PostSet', @onXAxisLocationChanged )
];
setappdata( ax, 'RotateXLabelsListeners', listeners );
end % addListeners

Sanjay

Sanjay (view profile)

Excellent ! Works as promised. No fuss.

Awesome. This code perfectly works. Here you get your five stars. =)

Cool, works as it should (tested in <=R2013b).
Big Pro: you can specify the handle to the plot/subplot whose labels shall be rotated, and don't need to set this axes active for automatic determinations.

Hi Nikolas,

I met the same problem with 2014b and solved it like this:

Add at beginning to rotatexlabels.m

if ~verLessThan('matlab','8.4.0')
% execute code for R2014b or higher
set(ax,'XTickLabelRotation',angle);
else
% execute code for R2014a or earlier
.
.
.
end
(put this end just before the first function [maxStringLength] = parseInputs( varargin ).

Good luck,

Thomas

Nikolas

Nikolas

Dear friend,

I am working with Matlab14b and your function shows the following error:

No constructor 'handle.listener' with matching signature found.

Error in rotateXLabels/addListeners (line 390)
listeners = [

Error in rotateXLabels/repositionAxes (line 214)
addListeners( ax );

Error in rotateXLabels (line 37)
repositionAxes( ax );

When I was working with Matlab 14a it was operating correctly, could you please recommend me ways to solve this problem?

Thank you

very simple to deploy and producing the desired result !

Filipe

Filipe (view profile)

Hey Ben, awesome job with this one! I was just in need of something like this. Just one detail... When I run your code everything goes well except for the plot title which lowers slightly. Any way of fixing this?

Cheers,
Filipe Belga

Ok I've found out the reason: removing the function repositionXLabel makes the labels to go outside the plot when zomming in.

Cheers,

Sebastian

Hi Ben,

many thanks for your amazing script. I have one question for you: if I profile your function the most of the execution time (about 66%) comes from "repositionXLabel", ( in particular from "ext = get( textLabels(ll), 'Extent' )" ). I do not understand what this function is used for (line 49) also because it works even if i comment that out. I'm sure the funcion is there for a reason, could you please give me some further info?
Thanks again,

Sebastian

goc3

goc3 (view profile)

This was very helpful. I tried various user-created functions to rotate text tick labels (cell array of strings) for the x-axis tick label. This is the only one I found that can rotate text tick labels on subplots without changing the subplots' sizes. Thanks.

DIEGO

DIEGO (view profile)

Excellent work.

R Bakker

Good work.
Got an issue when YDir is reversed.
Here is the fix, starting at line 137:

reverse = xor(strcmpi( get( ax, 'XAxisLocation' ), 'Top' ),strcmpi( get( ax, 'YDir' ), 'Reverse' ))
if reverse,
y = ylim(2);
else
y = ylim(1);
end

Chen Chen

John Yang

Fulfill my need. Works for subplot, too. Thanks,

Robert

Robert (view profile)

Great! But not working with the pre-release of 2014b.

Eduardo

Thanks!

Chris

Chris (view profile)

very useful, thanks

Quan Wang

Quan Wang (view profile)

Useful

Art Blair

Having problems with this. consider
figure;plot(1:10);
set(gca,'xlimmode','manual','xlim',[0,11]);
rotateXlabels(gca,90);
set(gca, 'xlim', [0,15]);

The labels do not update correctly. 13,14,&15 don't show. Adding 'xtick',[0:15] to the set command didn't help.
Using matlab 7.12.0 on an xp box.

Amit

Amit (view profile)

Nice function.

Follow-on to the discussion about imagesc
Had some trouble (position of labels) using this with imagesc. Solved it modifying the following

line 139: y = ylim(1);
line 141: y = ylim(2);
line 357: pos = [0 ylim(2)];
line 359: pos = [0 ylim(1)];

Still a remaining problem. If colorbar is visible the figure sizing is not correct.
Not sure how to fix this part.

Patrick Cloke

Very useful! Some errors when saving a figure and reopening them (it looks like the old axes is trying to be modified).

Forest

Forest (view profile)

things are not right if one set the axis reverse as:
set(gca,'YDir','reverse')

Forest

Forest (view profile)

Pretty good and handy tool to display long strings as X tick label!

Idea is great and it works for some plots. I had issues with plots being incorrectly resized that required code changes. I also had some blots for which this function placed tick labels inside the plot area. So it needs more debugging and possibly a tutorial page with examples.

Gadi

Gadi (view profile)

I've pinpointed the issue with the "Index exceeds matrix dimensions." error and it's a bug somewhere else.

It has to do with "hold on" somehow adding 2 new tick marks to the figure.

Here is how to reproduce it on 2012a:

dat = 1:5;
fh = figure;
hold all;
bar(dat);
set(gca,'XTickLabel', dat);
rotateXLabels(gca,10);

If you would remove "hold on", no error.

Thanks for sharing! Do you have any ideas on applying this to the Y-axis ?

Jorge

Jorge (view profile)

Andrea

Andrea (view profile)

M H

M H (view profile)

Very nice function!!

the imagesc() workaround would be to create a copy of the function e.g. 'rotateXLabelsIMGSC()' and change

'y = ylim(2);' to 'y = ylim(1);' in line 124
and
'y = ylim(1);' to 'y = ylim(2);' in line 126

..would be nicer to catch the imagesc()-case by an 'if' but I am not sure if there is a handle/handle-combination to do it...
cheers

Ben Tordoff

Ben Tordoff (view profile)

Hi Fernando & Martin, could one of you post (or email me) an example? When I try the obvious:

imagesc
rotateXLabels(gca, 45)

it all looks fine. Also, which MATLAB version, just in case it matters?

Ben Tordoff

Ben Tordoff (view profile)

Thanks Matt, that's an interesting bug you've found.

I think we can do something slightly better and remove everything to do with rotated labels when the axes are cleared. I'll post an update that does this for you to try. Hopefully it won't break any existing functionality.

Matt Jardin

Hey Ben. Very useful function indeed! I may have found an odd issue that occurs if you run cla on the axis that contains rotated x-axis labels. In that case, the next time you trigger one of the listeners that your function sets up, an error is thrown because all of the properties it expects to find have been cleared. I hacked a quick fix by checking inside of each of the listener callbacks to check if the particular axis property is empty. If so, I remove the listeners. Perhaps you have a better suggestion? Thanks again for the function.

Jingmin

Thanks!! Just what I needed.

Matlab2010

great! eg rotateXLabels(gca, 40);

Fernando

I have the same problem of Martin

Edward

Edward (view profile)

Martin

Martin (view profile)

Love the function, but have one problem: when I use it with imagesc() the labels end up on the top of the graph and inside the face of the graph. How can I move them to be outside?

Sam

Sam (view profile)

Thanks for the sweet function. However, I'm also getting an "Index exceeds matrix dimensions" error with R2012a, and I isolated what's causing the problem for me at least (although I have no idea why). The code below simulates the scenario I'm working on. When I set 'YGrid' to 'on', I get the error that follows the code. No error when I leave out a 'YGrid' specification. (Note that the code seems to execute just fine despite the error, so it's not a huge deal.)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

% Create fake data
%%% 14 groups of 4 percentages, each group adding to 100
data = zeros(14,4) ;
data(:,1) = randi(100,14,1) ;
for y = 2:3
for x = 1:14
if sum(data(x,:)) == 100
continue
end
data(x,y) = randi(100-sum(data(x,:)),1,1) ;
end
end
for x = 1:14
data(x,4) = 100 - sum(data(x,:)) ;
end

% Make grouped bar graph
bar(data,'grouped') ;
xlabels = char('Grp01','Grp02','Grp03','Grp04','Grp05','Grp06','Grp07','Grp08','Grp09','Grp10','Grp11','Grp12','Grp13','Grp14') ;
set(gca,'XTickLabel',xlabels,'YLim',[0 100],'YGrid','on')
rotateXLabels(gca,45)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Here's the error message:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Index exceeds matrix dimensions.

Error in rotateXLabels/getLabelHeight (line 226)
oldUnits = get( textLabels(1), 'Units' );

Error in rotateXLabels/repositionXLabel (line 204)
labelHeight = getLabelHeight(ax);

Error in rotateXLabels/onAxesLimitsChanged (line 353)
repositionXLabel( ax );

Warning: Error occurred while evaluating listener callback.
> In graphics/private/clo at 83
In cla at 29
In newplot>ObserveAxesNextPlot at 125
In newplot at 74
In bar at 76

Ben Tordoff

Ben Tordoff (view profile)

Hi Vaibhav, any chance you could post a version of the code that doesn't require a data-file? You can use RAND etc to generate some fake data. The important thing is that the range of the data (both in x and y) is similar to the data that you are having trouble with.

Vaibhav Jain

Hi Ben,

Thank you for your function. It works absolutely perfect but I am facing a problem when converting the x ticks to mm/dd hh:mm format using datetick command. The eroor message arises specifically when I increase the number of x ticks beyond a certain limit (more than 8 in this case) using linspace command.

Please look at the following code. I have tried to explain its steps in the commented lines. In the end I am pasting the error message I get on running. I would like to know your views on it. Thanks again!

file=importdata('HourlyTemperature.csv');
DateTime=file.textdata(2:end,1);
% textdata is a <168x1 double> array with values in 'dd/mm hh:mm:ss' format

DateTime=datenum(DateTime);
% Converts mm/dd hh:mm to numeric values

Temperature=file.data(:,1);
% data is a <168x1 double> array with numeric format

plot(DateTime,Temperature);
datetick('x','dd/mm HH:MM:SS','keepticks');
xData=linspace(735105.0416666666,735112,8);
% linspace('first value of DateTime array', 'last value of DateTime array',
% 'number of XTicks in between')

set(gca,'XTick',xData)

rotateXLabels(gca, 90)

Error message:
??? Index exceeds matrix dimensions.

Error in ==> rotateXLabels>createNewLabels at 132
textLabels(ll) = text( ...

Error in ==> rotateXLabels at 35
h = createNewLabels( ax, vals, labels, angle );

Error in ==> HourlyTempPlot at 29
rotateXLabels(gca, 90)

- Vaibhav Jain

Vaibhav Jain

Worked perfectly in 2 minutes.
A great and user-friendly file.
Some warnings about latex markups while using no interpreter but it's harmless so far
Thanks for sharing!

Ben Tordoff

Ben Tordoff (view profile)

OK, I've submitted an update that will hopefully fix the printing issues. Please keep a backup of the old version in case this change breaks something else (it passes all my tests, but they probably don't cover all uses). The update should appear here in the next few days. When it does, let me know if it helped.

Cheers.
Ben

Ben Tordoff

Ben Tordoff (view profile)

Hi Johan, I can see the problem. I am using "normalized" coordinates for the text used as the labels. It seems that with the units set to normalized they don't print, but if I set them to something else they do. I have no idea why this would be.

I will see if I can re-arrange the code to use something other than normalized units without breaking something else (zooming, panning, titles, etc).

:-(

Ben

Johan Carlson

Hi,
On screen everything looks fine. However, when I try to print, the tick labels disappear, same as for Wolfgang. I'm running MATLAB 2011b (7.13.0.564) on Windows 7 (x64 version). All plot settings are at the default.

Other than that, great function!
/Johan

Here's the test script that used:

%------------------
clear all
close all
clc

x = 1:0.2:2.8;
y = x.^2;
plot(x,y);
xlab = get(gca,'XTickLabel');
xlab = num2str(xlab);
set(gca,'XTickLabel',xlab);
xlabel('X axis label');
ylabel('Y axis label');
title('Plot title');
rotateXLabels(gca, 45)
set(gcf, 'PaperPositionMode', 'auto');
print('-dpng','plot.png');

Pablo

Pablo (view profile)

Chris Sparrow

yes I am using an old version of Matlab - thanks for the suggestion. Great script btw!

Ben Tordoff

Ben Tordoff (view profile)

Hi Chris, are you by any chance using a version of MATLAB older than R2010a?

If so, you may still be able to get it to work by replacing the '~' with a real variable name, but bear in mind this hasn't been developed or tested on older releases.

Cheers. Ben

Chris Sparrow

I get the following error:
>> rotateXLabels( gca(), 22 )
??? Error: File: rotateXLabels.m Line: 310 Column: 33
Unexpected MATLAB operator.

line 310 is function onAxesFontChanged( ~, ~ )

it will work if I commnet out the functions having ( ~, ~ )
any thoughts why I have this error?

thanks

Ben Tordoff

Ben Tordoff (view profile)

Hi Wolfgang, I've just tried this using the example in the help and printing using the lines you provided and the labels appear OK. Could you provide a more detailed example that shows the problem? There may be some setting of your figure that makes a difference.

Cheers. Ben

Wolfgang

Hi Ben,

This works fine with me, but the x-Axis labels are not printed into a png-file via
set(gcf, 'PaperPositionMode', 'auto');
print('-dpng','-r90','bild.png');

Can you reproduce this, and do you have a solution.

Thijs

Thijs (view profile)

First rotate script I came across that works without issues (yet ;) ) on subplots.

Thank you!

Denzel Li

Hi Ben and Miranda:
The program is cool, especially comparing to other rotation programs which may not adjust the text object position well. Also the code style is clear.
For my previous request of setting the axis to the top, I just manually set the y to a proper value in creatNewLabels(...) and it works.

Miranda

Hi Ben,
Thank you for this nice program. One disadvantage is that the labels are very close to the x-axes, especially if I choose an angle of -90 or 90. I thought of including an extra space in the labels:
if 0 <= angle && angle < 180
labels = cellfun(@(x) horzcat(x,' '),labels,'UniformOutput', false);
else
labels = cellfun(@(x) horzcat(' ',x),labels,'UniformOutput', false);
end
Maybe an extra if-expression is needed for the labels on XAxisLocation top...
Miranda

Ben Tordoff

Ben Tordoff (view profile)

Hi Denzel, my first attempt at getting this to work is on its way through the approval process now. You should see it arrive on here in the next day or two.

Denzel Li

Hi Ben:
Thanks for your quick reply. Having xticklabels on top and yticklabels on right are especially useful when displaying heatmap with labels. Please keep me updated. Thanks.

Ben Tordoff

Ben Tordoff (view profile)

Hi Denzel,
this hack works by replacing the tick labels with text objects and removing the existing tick labels. This means that setting properties of the tick labels (fonts, position etc) will no longer have any effect. I'll have a look and see if I can make them honour the "XAxisLocation" property, but I suspect that even then you will need to set it before rotating the labels. Watch this space...

Ben

Denzel Li

Hi Ben:
Thanks for the great tool. However it only produces xticklabels which is at the bottom and not on the top. That is, even with the function call:
set(gca, 'XAxisLocation', 'top');
the xticklabels are still at the bottom. Please note that get(gca,XAxisLocation') returns 'top'.
Please let me know if anyone has any suggestion. Thanks.

Best,
Denzel

Dan Glaser

Thanks, the positioning now works great.

Ben Tordoff

Ben Tordoff (view profile)

Hi Dan. I'm hoping this latest update will have fixed your problem. Please let me know if it doesn't.

Cheers. Ben

Dan Glaser

Thanks Ben,
I appreciate you looking into this!
-Dan

Ben Tordoff

Ben Tordoff (view profile)

Hi Dan. Having done some testing, it looks like text object positions are only stored to the nearest pixel. This means that when you call rotateXLabels, any labels that are drawn at the same pixel location will store their position as the same value. This seems to be a limitation of MATLAB's normalised position units or at least a restriction imposed when you switch to them. I will see if it's possible to achieve the same label behavior without using normalised coordinates as this may fix your problem. Watch this space...

Cheers. Ben

Dan Glaser

This works beautifully, but when it is used with a plot that has a very large number of x tick labels (1000 for example) it does not position them correctly.

Initially of course in this case, they labels are all overlapping, but after zooming it can be seen that they do not position equally and some are directly on top of each other.

Does anyone have any suggestions?

Dan Glaser

Suresh Joel

Suresh Joel (view profile)

Some function arguments missing? (line 256 col 33)

Updates

1.5.0.1

Updated license

1.5

* On MATLAB R2014b, just use XTickLabelRotation instead

1.4

Improve behavior when "cla" is called on the axes.

1.3

Switch to using data coordinates internally to allow printing to work. Please keep the old version in case this breaks something else!

1.2

Should now honour the "XAxisLocation" property of the axes.

1.1

Switch to using normalized units for labels to prevent loss of accuracy with hundreds/thousands of labels.

MATLAB Release
MATLAB 7.10 (R2010a)
Tags Add Tags

Download apps, toolboxes, and other File Exchange content using Add-On Explorer in MATLAB.

» Watch video