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.