Réduire les marges gauche et droite dans le tracé matplotlib

185

J'ai du mal à gérer mes marges de parcelle dans matplotlib. J'ai utilisé le code ci-dessous pour produire mon graphique:

plt.imshow(g)
c = plt.colorbar()
c.set_label("Number of Slabs")
plt.savefig("OutputToUse.png")

Cependant, j'obtiens un chiffre de sortie avec beaucoup d'espace blanc de chaque côté de l'intrigue. J'ai cherché sur Google et lu la documentation de matplotlib, mais je n'arrive pas à trouver comment réduire cela.

robintw
la source
Le problème est-il la quantité d'espaces blancs dans le extentde la imshowfigure, ou la quantité d'espaces blancs de bordure dans le png résultant, autour de la figure, générée par savefig?
unutbu
Je pense aux deux - il semble y avoir beaucoup d'espace à la fois dans la fenêtre de visualisation et dans le PNG. Cependant, la sortie importante est le fichier png produit par savefig- c'est donc ce que je voudrais trier.
robintw
Je viens de les recadrer dans GIMP par la suite. : /
endolith

Réponses:

268

Une façon de le faire automatiquement est d' bbox_inches='tight'utiliser le kwarg to plt.savefig.

Par exemple

import matplotlib.pyplot as plt
import numpy as np
data = np.arange(3000).reshape((100,30))
plt.imshow(data)
plt.savefig('test.png', bbox_inches='tight')

Une autre façon est d'utiliser fig.tight_layout()

import matplotlib.pyplot as plt
import numpy as np

xs = np.linspace(0, 1, 20); ys = np.sin(xs)

fig = plt.figure()
axes = fig.add_subplot(1,1,1)
axes.plot(xs, ys)

# This should be called after all axes have been added
fig.tight_layout()
fig.savefig('test.png')
Joe Kington
la source
7
Existe-t-il un moyen d'en faire la valeur par défaut?
endolith
1
Si vous avez plusieurs sous-graphiques et souhaitez enregistrer chacun d'eux, vous pouvez également l'utiliser avec fig.savefig(). ( plt.savefig()ne fonctionnera pas dans ce cas.)
Abhranil Das
1
Tout cela ne fait que recadrer l'image après son rendu; si vous essayez d'appliquer une résolution particulière, l'image sera plus petite .
detly le
5
@detly - Ouais. C'est exactement ce qu'il fait (bien qu'il puisse également «rogner» et agrandir l'image). Pour ce que vous voulez, jetez un œil fig.tight_layout(). Cette fonction n'existait pas lorsque cette réponse a été écrite à l'origine, sinon je la mentionnerais plus en évidence.
Joe Kington
2
Si quelqu'un a un problème, utilisezfig = plt.gcf()
KyungHoon Kim
151

Vous pouvez ajuster l'espacement autour des figures matplotlib en utilisant la fonction subplots_adjust ():

import matplotlib.pyplot as plt
plt.plot(whatever)
plt.subplots_adjust(left=0.1, right=0.9, top=0.9, bottom=0.1)

Cela fonctionnera à la fois pour la figure à l'écran et enregistrée dans un fichier, et c'est la bonne fonction à appeler même si vous n'avez pas plusieurs tracés sur une seule figure.

Les nombres sont des fractions des dimensions de la figure et devront être ajustés pour tenir compte des étiquettes de la figure.

DaveP
la source
8
Les valeurs assignées aux paramètres et non pas de combien les modifier, elles sont l'endroit où définir la marge. En d'autres termes, si vous voulez ramener la marge du bord droit de 10%, vous devez définir à droite = 0,9, pas à droite = 0,1 matplotlib.sourceforge.net/api/…
drootang
1
Il est logique de souligner que vous pouvez évidemment spécifier des valeurs négatives dans plt.subplots_adjust (). Cela vous permet même de dessiner en dehors de la zone de la figure et de gérer les marges ennuyeuses.
surchs le
Cela fonctionne également sur les GridSpecobjets en appelant la updateméthode (voir stackoverflow.com/a/20058199/1030876 ).
Aaron Voelker
58

Tout ce dont tu as besoin c'est

plt.tight_layout()

avant votre sortie.

En plus de réduire les marges, cela regroupe également étroitement l'espace entre les sous-graphiques:

x = [1,2,3]
y = [1,4,9]
import matplotlib.pyplot as plt
fig = plt.figure()
subplot1 = fig.add_subplot(121)
subplot1.plot(x,y)
subplot2 = fig.add_subplot(122)
subplot2.plot(y,x)
fig.tight_layout()
plt.show()
user2065406
la source
7
Je pense que c'est vraiment la meilleure méthode. Il ne nécessite pas d'enregistrer la figure comme `bbox = 'tight' et corrige toutes sortes d'autres problèmes de mise en page dans des figures exiguës.
dshepherd
2
cela devrait être la bonne réponse car il se comporte comme vous vous y attendez car il s'applique à la FIGURE au lieu de l'image.
Majid alDosari
Curieusement, cela change également la largeur du tracé réel (c'est-à-dire que les pics sont plus rapprochés) par rapport à bbox_inches='tight', qui ne fait que couper l'espace blanc autour des bords mais laisse le tracé seul. J'ai créé la figure avec plt.figure(figsize=(10,3)).
Fritz
9

Utilisez simplement ax = fig.add_axes([left, bottom, width, height]) si vous voulez un contrôle exact de la disposition de la figure. par exemple.

left = 0.05
bottom = 0.05
width = 0.9
height = 0.9
ax = fig.add_axes([left, bottom, width, height])
le maçon
la source
7

Au cas où quelqu'un se demanderait comment se débarrasser du reste de la marge blanche après l'application plt.tight_layout()ou fig.tight_layout(): Avec le paramètre pad(qui est 1.08par défaut), vous pouvez le rendre encore plus serré: "Rembourrage entre le bord de la figure et les bords de sous-graphiques, en tant que fraction de la taille de la police. " Donc par exemple

plt.tight_layout(pad=0.05)

le réduira à une très petite marge. Mettre 0ne fonctionne pas pour moi, car cela coupe un peu la boîte de la sous-parcelle.

Oberwaschlappen
la source
5

inspiré par la réponse de Sammys ci-dessus:

margins = {  #     vvv margin in inches
    "left"   :     1.5 / figsize[0],
    "bottom" :     0.8 / figsize[1],
    "right"  : 1 - 0.3 / figsize[0],
    "top"    : 1 - 1   / figsize[1]
}
fig.subplots_adjust(**margins)

Où figsize est le tuple que vous avez utilisé dans fig = pyplot.figure(figsize=...)

Michaelosthege
la source
4
plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)
Tian Chu
la source
1
"pad_inches = -1" parce que mon savefig ne produit qu'une partie de la figure.
Yu Shen
L'utilisation d'un paramètre dans la savefigfonction est élégante, mais la valeur négative de pad_inchesn'est pas nécessairement nécessaire dans tous les cas.
MichaelHuelsen
réglez-le sur 0, aide
Joop
4

Le problème avec matplotlibs subplots_adjust est que les valeurs que vous entrez sont relatives aux tailles x et y de la figure. Cet exemple est pour le dimensionnement correct pour l'impression d'un pdf:

Pour cela, je recalcule l'espacement relatif en valeurs absolues comme ceci:

pyplot.subplots_adjust(left = (5/25.4)/figure.xsize, bottom = (4/25.4)/figure.ysize, right = 1 - (1/25.4)/figure.xsize, top = 1 - (3/25.4)/figure.ysize)

pour une figure de "figure.xsize" pouces en dimension x et "figure.ysize" pouces en dimension y. Ainsi, la figure entière a une marge gauche de 5 mm, une marge inférieure de 4 mm, une marge droite de 1 mm et une marge supérieure de 3 mm à l'intérieur des étiquettes. La conversion de (x / 25,4) est effectuée car j'avais besoin de convertir des mm en pouces.

Notez que la taille de graphique pure de x sera "figure.xsize - marge gauche - marge droite" et la taille de graphique pure de y sera "figure.ysize - marge inférieure - marge supérieure" en pouces

Autres sniplets (pas sûr de ceux-ci, je voulais juste fournir les autres paramètres)

pyplot.figure(figsize = figureSize, dpi = None)

et

pyplot.savefig("outputname.eps", dpi = 100)
Sammy
la source
3
D'où viens-tu xsizeet ysized' où tu viens . J'utilise ces propriétés et j'obtiensAttributeError: 'Figure' object has no attribute 'xsize'
cj5
2

Pour moi, les réponses ci-dessus ne fonctionnaient pas avec matplotlib.__version__ = 1.4.3Win7. Donc, si nous ne nous intéressons qu'à l'image elle-même (c'est-à-dire si nous n'avons pas besoin d'annotations, d'axes, de graduations, de titre, d'étiquette, etc.), il est préférable de simplement enregistrer le tableau numpy en tant qu'image au lieu de savefig.

from pylab import *

ax = subplot(111)
ax.imshow(some_image_numpyarray)
imsave('test.tif', some_image_numpyarray)

# or, if the image came from tiff or png etc
RGBbuffer = ax.get_images()[0].get_array()
imsave('test.tif', RGBbuffer)

De plus, en utilisant les fonctions de dessin opencv (cv2.line, cv2.polylines), nous pouvons faire des dessins directement sur le tableau numpy. http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html

loutre
la source
2

Avec les versions récentes de matplotlib, vous voudrez peut-être essayer la mise en page contrainte .

Michel de Ruiter
la source
2

Parfois, plt.tight_layout()cela ne me donne pas la meilleure vue ou la meilleure vue que je souhaite. Alors pourquoi ne pas tracer d'abord avec une marge arbitraire et fixer la marge après l'intrigue? Depuis que nous avons un bon WYSIWYG à partir de là.

import matplotlib.pyplot as plt

fig,ax = plt.subplots(figsize=(8,8))

plt.plot([2,5,7,8,5,3,5,7,])
plt.show()

Modifiez l'interface graphique de bordure et d'espacement ici

Collez ensuite les paramètres dans la fonction de marge pour la rendre permanente:

fig,ax = plt.subplots(figsize=(8,8))

plt.plot([2,5,7,8,5,3,5,7,])
fig.subplots_adjust(
    top=0.981,
    bottom=0.049,
    left=0.042,
    right=0.981,
    hspace=0.2,
    wspace=0.2
)
plt.show()
Anugrah Andisetiawan
la source