70

With, say, 3 rows of subplots in matplotlib, xlabels of one row can overlap the title of the next. One has to fiddle with pl.subplots_adjust(hspace), which is annoying.

Is there a recipe for hspace that prevents overlaps and works for any nrow?

""" matplotlib xlabels overlap titles ? """
import sys
import numpy as np
import pylab as pl

nrow = 3
hspace = .4  # of plot height, titles and xlabels both fall within this ??
exec "\n".join( sys.argv[1:] )  # nrow= ...

y = np.arange(10)
pl.subplots_adjust( hspace=hspace )

for jrow in range( 1, nrow+1 ):
    pl.subplot( nrow, 1, jrow )
    pl.plot( y**jrow )
    pl.title( 5 * ("title %d " % jrow) )
    pl.xlabel( 5 * ("xlabel %d " % jrow) )

pl.show()

My versions:

  • matplotlib 0.99.1.1,
  • Python 2.6.4,
  • Mac OSX 10.4.11,
  • backend: Qt4Agg (TkAgg => Exception in Tkinter callback)

(For many extra points, can anyone outline how matplotlib's packer / spacer works, along the lines of chapter 17 "the packer" in the Tcl/Tk book?)

Michael Currie
  • 13,721
  • 9
  • 42
  • 58
denis
  • 21,378
  • 10
  • 65
  • 88
  • 1
    This question has been closed as a duplicate because the [accepted answer](https://stackoverflow.com/a/2516508/7758804) produces `AttributeError`, this [answer](https://stackoverflow.com/a/6541482/7758804) is a duplicate already in the "close duplicate", and this [answer](https://stackoverflow.com/a/8729186/7758804) is just links to functions, which are also in the duplicate. This question is effectively useless, other than as a pointer. – Trenton McKinney Aug 27 '22 at 02:21

2 Answers2

45

The link posted by Jose has been updated and pylab now has a tight_layout() function that does this automatically (in matplotlib version 1.1.0).

http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.tight_layout

http://matplotlib.org/users/tight_layout_guide.html#plotting-guide-tight-layout

Demis
  • 5,278
  • 4
  • 23
  • 34
kiyo
  • 1,929
  • 1
  • 18
  • 22
  • 3
    `tight_layout()` doesn't account for figure suptitle. See https://stackoverflow.com/questions/8248467/matplotlib-tight-layout-doesnt-take-into-account-figure-suptitle for a solution. – ComFreek Sep 24 '19 at 09:05
  • 2
    Small sidenote: make sure you call `tight_layout()` _after_ setting all the labels and titles, otherwise it won't take them into account! – Thomas Wagenaar Apr 12 '23 at 11:44
31

I find this quite tricky, but there is some information on it here at the MatPlotLib FAQ. It is rather cumbersome, and requires finding out about what space individual elements (ticklabels) take up...

Update: The page states that the tight_layout() function is the easiest way to go, which attempts to automatically correct spacing.

Otherwise, it shows ways to acquire the sizes of various elements (eg. labels) so you can then correct the spacings/positions of your axes elements. Here is an example from the above FAQ page, which determines the width of a very wide y-axis label, and adjusts the axis width accordingly:

import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(range(10))
ax.set_yticks((2,5,7))
labels = ax.set_yticklabels(('really, really, really', 'long', 'labels'))

def on_draw(event):
   bboxes = []
   for label in labels:
       bbox = label.get_window_extent()
       # the figure transform goes from relative coords->pixels and we
       # want the inverse of that
       bboxi = bbox.inverse_transformed(fig.transFigure)
       bboxes.append(bboxi)

   # this is the bbox that bounds all the bboxes, again in relative
   # figure coords
   bbox = mtransforms.Bbox.union(bboxes)
   if fig.subplotpars.left < bbox.width:
       # we need to move it over
       fig.subplots_adjust(left=1.1*bbox.width) # pad a little
       fig.canvas.draw()
   return False

fig.canvas.mpl_connect('draw_event', on_draw)

plt.show()
Demis
  • 5,278
  • 4
  • 23
  • 34
Jose
  • 2,089
  • 2
  • 23
  • 29
  • 1
    accept, but cumbersome indeed -- mttiw, more trouble than it's worth – denis Apr 02 '10 at 10:45
  • Link is gone. This answer became de facto useless. – j-i-l Jul 20 '15 at 16:09
  • 5
    Link exists again - says `tight_layout()` is now the way to go, which indeed it is. – Demis Jan 04 '16 at 01:11
  • 2
    `tight_layout()` doesn't account for figure suptitle. See https://stackoverflow.com/questions/8248467/matplotlib-tight-layout-doesnt-take-into-account-figure-suptitle for a solution. – ComFreek Sep 24 '19 at 09:05