web-dev-qa-db-fra.com

Matplotlib subplots_adjust hspace pour que les titres et les xlabels ne se chevauchent pas?

Avec, disons, 3 lignes de sous-parcelles dans matplotlib, xlabels d'une ligne peut chevaucher le titre de la suivante. Il faut jouer avec pl.subplots_adjust(hspace), ce qui est agaçant.

Existe-t-il une recette pour hspace qui empêche les chevauchements et fonctionne pour n'importe quel 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()

Mes versions:

  • matplotlib 0.99.1.1,
  • Python 2.6.4,
  • Mac OSX 10.4.11,
  • backend: Qt4Agg (TkAgg => Exception dans le rappel Tkinter)

(Pour de nombreux points supplémentaires, quelqu'un peut-il décrire le fonctionnement du packer/spacer de matplotlib, conformément au chapitre 17 "le packer" du livre Tcl/Tk?)

40
denis

Je trouve cela assez délicat, mais il y a des informations à ce sujet ici à la FAQ MatPlotLib . C'est assez lourd et nécessite de savoir quel espace les éléments individuels (ticklabels) occupent ...

Mise à jour: La page indique que la fonction tight_layout() est le moyen le plus simple, qui tente de corriger automatiquement l'espacement.

Sinon, il montre des façons d'acquérir les tailles de divers éléments (par exemple des étiquettes) afin que vous puissiez ensuite corriger les espacements/positions de vos éléments d'axes. Voici un exemple de la page FAQ FAQ ci-dessus, qui détermine la largeur d'une étiquette d'axe y très large et ajuste la largeur d'axe en conséquence:

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()
18
Jose

Vous pouvez utiliser plt.subplots_adjust pour modifier l'espacement entre les sous-parcelles Lien

subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)

left  = 0.125  # the left side of the subplots of the figure
right = 0.9    # the right side of the subplots of the figure
bottom = 0.1   # the bottom of the subplots of the figure
top = 0.9      # the top of the subplots of the figure
wspace = 0.2   # the amount of width reserved for blank space between subplots
hspace = 0.2   # the amount of height reserved for white space between subplots
44
CyanRook

Le lien posté par Jose a été mis à jour et pylab a maintenant une fonction tight_layout() qui le fait automatiquement (dans 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

34
kiyo