Riduci i margini sinistro e destro nel grafico matplotlib


178

Sto lottando per gestire i margini della trama in matplotlib. Ho usato il codice qui sotto per produrre il mio grafico:

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

Tuttavia, ottengo una figura di output con molto spazio bianco su entrambi i lati della trama. Ho cercato su Google e letto la documentazione di matplotlib, ma non riesco a trovare il modo per ridurlo.


Il problema è la quantità di spazio bianco nella extentdella imshowfigura, o la quantità di spazio bianco di confine nel png risultante, intorno alla figura, generata da savefig?
unutbu,

Penso entrambi - sembra che ci sia molto spazio sia nella finestra di visualizzazione che nel PNG. Tuttavia, l'output importante è il file png prodotto da savefig- quindi è quello che mi piacerebbe ordinare.
Robintw,

In seguito li ho appena ritagliati in GIMP. : /
endolith

Risposte:


251

Un modo per farlo automaticamente è il bbox_inches='tight'kwarg a plt.savefig.

Per esempio

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')

Un altro modo è quello di usare 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')

5
C'è un modo per renderlo predefinito?
endolith

1
Se si dispone di più sottotrame e si desidera salvare ciascuno di essi, è possibile utilizzare anche questo fig.savefig(). ( plt.savefig()non funzionerà in quel caso.)
Abhranil Das

1
Tutto ciò che fa è ritagliare l'immagine dopo che è stata renderizzata; se stai cercando di applicare una risoluzione particolare, l'immagine risulterà più piccola .
detly

5
@detly - Sì. Questo è esattamente ciò che fa (anche se può anche "ritagliarsi" e ingrandire l'immagine). Per quello che vuoi, dai un'occhiata fig.tight_layout(). Quella funzione non esisteva quando questa risposta era stata originariamente scritta, altrimenti la menzionerei in modo più evidente.
Joe Kington,

2
Se qualcuno ha un problema, usafig = plt.gcf()
KyungHoon Kim il

148

Puoi regolare la spaziatura attorno alle figure di matplotlib usando la funzione 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)

Funzionerà sia per la figura sullo schermo che per il salvataggio in un file, ed è la funzione giusta da chiamare anche se non si hanno più grafici sull'unica figura.

I numeri sono frazioni delle dimensioni delle figure e dovranno essere regolati per consentire le etichette delle figure.


8
I valori assegnati ai parametri e non di quanto modificarli, sono dove impostare il margine. In altre parole, se vuoi portare il margine del margine destro del 10%, dovresti impostare right = 0.9, not right = 0.1 matplotlib.sourceforge.net/api/…
drootang

1
Ha senso sottolineare che ovviamente è possibile specificare valori negativi in ​​plt.subplots_adjust (). Ciò consente anche di disegnare al di fuori dell'area della figura e anche di gestire i margini fastidiosi.
surchs

Questo funziona anche sugli GridSpecoggetti chiamando il updatemetodo (consultare stackoverflow.com/a/20058199/1030876 ).
Aaron Voelker,

57

Tutto ciò che serve è

plt.tight_layout()

prima della tua uscita.

Oltre a ridurre i margini, questo raggruppa strettamente lo spazio tra eventuali sottotrame:

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

7
Penso che questo sia davvero il metodo migliore. Non richiede il salvataggio della figura come `bbox = 'stretto' e risolve tutti i tipi di altri problemi di layout in figure anguste.
pastore

2
questa dovrebbe essere la risposta corretta perché si comporta come ti aspetteresti in quanto si applica alla FIGURA anziché all'immagine.
Majid alDosari,

Stranamente, questo cambia anche la larghezza della trama reale (cioè i picchi sono più vicini tra loro) rispetto a bbox_inches='tight', che taglia semplicemente lo spazio bianco attorno ai bordi ma lascia da solo la trama. Ho creato la figura con plt.figure(figsize=(10,3)).
Fritz,

9

Utilizzare solo ax = fig.add_axes([left, bottom, width, height]) se si desidera il controllo esatto del layout della figura. per esempio.

left = 0.05
bottom = 0.05
width = 0.9
height = 0.9
ax = fig.add_axes([left, bottom, width, height])

6

Nel caso in cui qualcuno si chieda come sbarazzarsi del resto del margine bianco dopo l'applicazione plt.tight_layout()o fig.tight_layout(): Con il parametro pad(che è 1.08di default), puoi renderlo ancora più stretto: "Riempimento tra il bordo della figura e i bordi di sottotrame, come una frazione della dimensione del carattere. " Quindi per esempio

plt.tight_layout(pad=0.05)

lo ridurrà a un margine molto piccolo. Il mettere 0non funziona per me, perché anche la scatola della sottotrama viene tagliata un po '.


4
plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)

1
"pad_inches = -1" perché il mio savefig produce solo parte della figura.
Yu Shen,

L'uso di un parametro nella savefigfunzione è elegante, tuttavia il valore negativo per pad_inchesnon è necessariamente necessario in ogni caso.
MichaelHuelsen, il

impostalo su 0, aiuta
Joop

4

Il problema con matplotlibs subplots_adjust è che i valori immessi sono relativi alle dimensioni x e y della figura. Questo esempio è per il corretto dimensionamento per la stampa di un pdf:

Per questo, ricalcolo la spaziatura relativa su valori assoluti come questo:

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)

per una figura di pollici "figure.xsize" nella dimensione x e pollici "figure.ysize" nella dimensione y. Quindi l'intera figura ha un margine sinistro di 5 mm, un margine inferiore di 4 mm, un diritto di 1 mm e una parte superiore di 3 mm all'interno delle etichette. La conversione di (x / 25.4) è fatta perché avevo bisogno di convertire mm in pollici.

Si noti che la dimensione pura del grafico di x sarà "figure.xsize - margine sinistro - margine destro" e la dimensione pura del grafico di y sarà "figure.ysize - margine inferiore - margine superiore" in pollici

Altri sniplet (non sono sicuro di questi, volevo solo fornire gli altri parametri)

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

e

pyplot.savefig("outputname.eps", dpi = 100)

3
Da dove sei arrivato xsizee ysizeda dove? Uso queste proprietà e ottengoAttributeError: 'Figure' object has no attribute 'xsize'
cj5

4

ispirato dalla risposta di Sammys sopra:

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)

Dove figsize è la tupla che hai usato fig = pyplot.figure(figsize=...)


2

Per me, le risposte sopra non hanno funzionato con matplotlib.__version__ = 1.4.3Win7. Quindi, se siamo interessati solo all'immagine stessa (cioè, se non abbiamo bisogno di annotazioni, assi, segni di spunta, titolo, etichetta ecc.), Allora è meglio semplicemente salvare l'array numpy come immagine anziché 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)

Inoltre, usando le funzioni di disegno opencv (cv2.line, cv2.polylines), possiamo fare alcuni disegni direttamente sull'array numpy. http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.