35

I want to plot a graph with a lot of ticks on the X axis using the following code:

import pylab

N = 100
data = pylab.np.linspace(0, N, N)

pylab.plot(data)

pylab.xticks(range(N)) # add loads of ticks
pylab.grid()
pylab.tight_layout()
pylab.show()

pylab.close()

The resulting plot looks like this:

plot

As you can see, the X axis is a mess because the tick labels are plotted with too few space between them or even overlap.

I would like to create constant space between each tick label automatically, no matter how many ticks there are. So, I'd like to increase the space between individual ticks, thus potentially increasing the 'length' of a plot.

Note that the tick labels may be strings of variable length.

What I have found so far is all about spacing between the axis and labels (which is not what I want), tick frequency (which I can already do) and tick parameters (which don't seem to have any options for spacing).

I can change the size of a figure manually with matplotlib.pyplot.figure(figsize=(a, b)), but that would require knowledge of the default spacing between ticks (there's none, as far as I can tell) and the greatest width (in inches) of a tick label, which I have no clue how to measure, so this is not an option, to my mind.

What can I do to increase spacing between ticks? I'm OK with getting a pretty lengthy image.

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
ForceBru
  • 43,482
  • 10
  • 63
  • 98
  • That's the way matplotlib works. You create a figure of given size and put the plot into it. If there are more labels, they will overlap. You may of course change the figure size after creation; find out the space the longest label takes, multiply it with the number of labels, add the margin and set this as the new figure size. This is a rather complicated procedure, so I'm not sure if this is really what you want. – ImportanceOfBeingErnest Jul 01 '17 at 17:18
  • @ImportanceOfBeingErnest, I was talking about this in the last but one paragraph, and this indeed seems very hard to do, given that I don't know how to calculate space the longest label takes... I hope there's some nice trick to do that. – ForceBru Jul 01 '17 at 17:22
  • Yes that's my point. So apparenty you exclude the only possible solution. Would you like to go that route or not? I guess you can ask for help along that line instead of excluding that option. – ImportanceOfBeingErnest Jul 01 '17 at 17:24
  • Another possible option it to have it omit adjacent Labels if they will collide. When everything is fully-automatic (no manual tick locations), it seems MPL has some way for figuring this out, and chooses a tick spacing such that labels don't (usually) collide. It would be helpful if similar code could be used to determine which labels collide and omit, for ex., every other label etc. – Demis Apr 24 '22 at 05:01

4 Answers4

31

The spacing between ticklabels is exclusively determined by the space between ticks on the axes. Therefore the only way to obtain more space between given ticklabels is to make the axes larger.

In order to determine the space needed for the labels not to overlap, one may find out the largest label and multiply its length by the number of ticklabels. One may then adapt the margin around the axes and set the calculated size as a new figure size.

import numpy as np
import matplotlib.pyplot as plt

N = 150
data = np.linspace(0, N, N)

plt.plot(data)

plt.xticks(range(N)) # add loads of ticks
plt.grid()

plt.gca().margins(x=0)
plt.gcf().canvas.draw()
tl = plt.gca().get_xticklabels()
maxsize = max([t.get_window_extent().width for t in tl])
m = 0.2 # inch margin
s = maxsize/plt.gcf().dpi*N+2*m
margin = m/plt.gcf().get_size_inches()[0]

plt.gcf().subplots_adjust(left=margin, right=1.-margin)
plt.gcf().set_size_inches(s, plt.gcf().get_size_inches()[1])

plt.savefig(__file__+".png")
plt.show()

enter image description here

Note that if the figure shown in the plotting window is larger than the screen, it will be shrunk again, so the resized figure is only shown in its new size when saved. Or, one may choose to incorporate it in some window with scrollbars as shown in this question: Scrollbar on Matplotlib showing page

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Wow, that works very well, thank you! I've stumbled upon a tiny problem, though: a bit of tick labels of the Y axis gets [cut off](http://imgur.com/a/bWyXk), presumably because of `plt.gca().margins(x=0)`. Can anything be done about that? – ForceBru Jul 01 '17 at 18:49
  • `margins(x=0)` is the inner margin and has nothing to do with cut labels outside. Instead, in the code above I've chosen `m = 0.2 # inch margin`, so if you want more space around the axes, use a bigger value of `m`. – ImportanceOfBeingErnest Jul 01 '17 at 18:51
  • awesome, now everything works absolutely perfectly! Thanks! – ForceBru Jul 01 '17 at 18:55
  • This should be the default behavior. Thanks – M at Mar 04 '23 at 08:20
4

You could use the following to rotate the labels and make the font smaller:

ax.set_xticklabels(rotation = (45), fontsize = 10, va='bottom', ha='left')
seralouk
  • 30,938
  • 9
  • 118
  • 133
  • 5
    The problem is, I want to plot _a lot of_ ticks on purpose, and they will overlap, unfortunately. – ForceBru Jul 01 '17 at 16:59
  • maybe if you use something like: `ax.set_xticklabels(rotation = (45), fontsize = 10, va='bottom', ha='left')` to rotate the labels – seralouk Jul 01 '17 at 17:00
  • @ser, did you read the question and visit the links I put there? _The first_ of them is a link to this very question, which is about a very different problem. – ForceBru Jul 01 '17 at 17:02
  • @ChristianDean i just edited my commment. I think `ax.set_xticklabels` should do the trick – seralouk Jul 01 '17 at 17:02
  • @ser, no, this doesn't work, it's a snippet from another SO answer I've already tried. – ForceBru Jul 01 '17 at 17:07
  • @ForceBru Maybe if you plot using the astropy module, you can edit the spacing. In the middle of this page [link](http://wcsaxes.readthedocs.io/en/latest/ticks_labels_grid.html), there is an example in the paragraph: "Tick/label spacing and properties". Also, another example from this [link](https://www.packtpub.com/mapt/book/big_data_/9781849513265/3/ch03lvl1sec48/controlling-tick-spacing) manipulates the gap between the ticks on the x axis. – seralouk Jul 01 '17 at 17:35
3

This is an old question, but for anyone searching, there is a way: ticker.MaxNLocator (and the other locators there). It can put a maximum of N ticks on a graph, no matter the zoom size.

Levi Lesches
  • 1,508
  • 1
  • 13
  • 23
0

One other solution is to adjust your data to make the tick spacing work.

Note: if you have huge amounts of data this may become very difficult

import matplotlib.pyplot as plt
import numpy as np

# **************************************************************************
# This plot shows inconsistent spacing between ticks
# **************************************************************************
f, test = plt.subplots()
xdata = [0,1,5,6,9,10]
ydata = [1,2,3,4,5,6]
test.step(xdata,ydata)
test.set_xticks([0,1,5,6,9,10],['Zero', 'one', 'five', 'six', 'nine', 'ten'])

plt.show()

# **************************************************************************
# Adjust data so tick marks have consistent spacing
# **************************************************************************
prettyxdata = xdata
for i in range(len(xdata)):
    if prettyxdata [i] == 5:
        prettyxdata [i]=2
    elif prettyxdata [i] == 6:
        prettyxdata [i]=3
    elif prettyxdata [i] == 9:
        prettyxdata [i]=4
    elif prettyxdata [i] == 10:
        prettyxdata [i]=5

f, test = plt.subplots()
test.step(prettyxdata,ydata)
test.set_xticks([0,1,2,3,4,5],['Zero', 'one', 'five', 'six', 'nine', 'ten'])

plt.show()
Fred
  • 1,054
  • 1
  • 12
  • 32