Reduzir as margens esquerda e direita no gráfico matplotlib

178

Estou lutando para lidar com as margens da minha plotagem no matplotlib. Eu usei o código abaixo para produzir meu gráfico:

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

No entanto, recebo uma figura de saída com muito espaço em branco em ambos os lados do gráfico. Pesquisei no google e li a documentação do matplotlib, mas não consigo encontrar como reduzir isso.

robintw
fonte
O problema é a quantidade de espaço em branco na extentda imshowfigura, ou a quantidade de espaço em branco fronteira no png resultante, em torno da figura, gerada por savefig?
Unutbu 28/10/10
Acho que ambos - parece haver muito espaço na janela de visualização e no PNG. No entanto, a saída importante é o arquivo png produzido por savefig- então é isso que eu gostaria de classificar.
robintw
Acabei de recortá-los no GIMP depois. : /
endolith 28/11

Respostas:

251

Uma maneira de fazer isso automaticamente é bbox_inches='tight'usando o kwarg plt.savefig.

Por exemplo

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

Outra maneira é usar 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
fonte
5
Existe alguma maneira de fazer isso o padrão?
endolith
1
Se você possui várias subparcelas e deseja salvar cada uma delas, também pode usar isso fig.savefig(). ( plt.savefig()não funcionará nesse caso).
Abhranil Das
1
Tudo o que isso faz é cortar a imagem depois de renderizada; se você estiver tentando aplicar uma resolução específica, a imagem será menor .
detly
5
@detly - Sim. É exatamente o que faz (embora possa cortar "também" e aumentar a imagem também). Para o que você está querendo, dê uma olhada fig.tight_layout(). Essa função não existia quando esta resposta foi originalmente escrita, caso contrário, eu a mencionaria com mais destaque.
21815 Joe
2
Se alguém tiver um problema, usefig = plt.gcf()
KyungHoon Kim
148

Você pode ajustar o espaçamento em torno das figuras matplotlib usando a função 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)

Isso funcionará para a figura na tela e salva em um arquivo, e é a função correta para chamar, mesmo que você não tenha várias plotagens na figura.

Os números são frações das dimensões da figura e precisarão ser ajustados para permitir os rótulos das figuras.

DaveP
fonte
8
Os valores atribuídos aos parâmetros e não o quanto alterá-los, são onde definir a margem. Em outras palavras, se você deseja aumentar a margem da borda direita em 10%, defina right = 0,9, not right = 0,1 matplotlib.sourceforge.net/api/…
drootang
1
Faz sentido ressaltar que, obviamente, você pode especificar valores negativos em plt.subplots_adjust (). Isso permite que você desenhe fora da área da figura e também lide com margens irritantes.
surchs
Isso também funciona em GridSpecobjetos chamando o updatemétodo (consulte stackoverflow.com/a/20058199/1030876 ).
Aaron Voelker
57

Tudo o que você precisa é

plt.tight_layout()

antes da sua saída.

Além de reduzir as margens, isso também agrupa fortemente o espaço entre quaisquer subparcelas:

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
fonte
7
Eu acho que esse é realmente o melhor método. Não é necessário salvar a figura como `bbox = 'tight' e corrige todos os tipos de outros problemas de layout em figuras reduzidas.
usar o seguinte comando
2
essa deve ser a resposta correta, pois se comporta conforme o esperado, como se aplica à FIGURA em vez da imagem.
Majid alDosari
Estranhamente, isso também altera a largura do gráfico real (ou seja, os picos estão mais próximos) em comparação com o bbox_inches='tight'que apenas corta o espaço em branco nas bordas, mas deixa o gráfico sozinho. Eu criei a figura com plt.figure(figsize=(10,3)).
Fritz
9

Basta usar ax = fig.add_axes([left, bottom, width, height]) se você quiser controle exato do layout da figura. por exemplo.

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

Caso alguém se pergunte como se livrar do restante da margem branca após aplicar plt.tight_layout()ou fig.tight_layout(): Com o parâmetro pad(que é o 1.08padrão), você poderá torná-lo ainda mais apertado: "Preenchimento entre a borda da figura e as bordas da subtramas, como uma fração do tamanho da fonte ". Então por exemplo

plt.tight_layout(pad=0.05)

reduzirá a uma margem muito pequena. Colocar 0não funciona para mim, pois também faz com que a caixa da subtrama seja um pouco cortada.

Oberwaschlappen
fonte
4
plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)
Tian Chu
fonte
1
"pad_inches = -1" porque meu savefig produz apenas parte da figura.
Yu Shen
O uso de um parâmetro na savefigfunção é elegante; no entanto, o valor negativo para pad_inchesnão é necessariamente necessário em todos os casos.
26717 MichaelHuelsen
configurá-lo como 0, ajuda #
318 Joop
4

O problema com o subplots_adjust do matplotlibs é que os valores inseridos são relativos ao tamanho de figura xey da figura. Este exemplo é para o correto dimensionamento de figuras para impressão de um pdf:

Para isso, recalculo o espaçamento relativo para valores absolutos como este:

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)

para uma figura de 'figure.xsize' polegadas na dimensão x e 'figure.ysize' polegadas na dimensão y Portanto, a figura inteira tem uma margem esquerda de 5 mm, margem inferior de 4 mm, direita de 1 mm e parte superior de 3 mm nas etiquetas. A conversão de (x / 25,4) é feita porque eu precisava converter mm em polegadas.

Observe que o tamanho puro do gráfico de x será "figure.xsize - margem esquerda - margem direita" e o tamanho puro do gráfico de y será "figure.ysize - margem inferior - margem superior" em polegadas

Outros sniplets (não tenho certeza sobre esses, eu só queria fornecer os outros parâmetros)

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

e

pyplot.savefig("outputname.eps", dpi = 100)
Sammy
fonte
3
De onde você veio xsizee ysizede onde? Eu uso essas propriedades e receboAttributeError: 'Figure' object has no attribute 'xsize'
cj5 16/05
4

inspirado na resposta de Sammys acima:

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)

Onde figsize é a tupla usada em fig = pyplot.figure(figsize=...)

michaelosthege
fonte
2

Para mim, as respostas acima não funcionaram com matplotlib.__version__ = 1.4.3 no Win7. Portanto, se estivermos interessados ​​apenas na imagem em si (ou seja, se não precisarmos de anotações, eixos, ticks, título, rótulo etc.), é melhor simplesmente salvar a matriz numpy como imagem em vez 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)

Além disso, usando as funções de desenho opencv (cv2.line, cv2.polylines), podemos fazer alguns desenhos diretamente na matriz numpy. http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html

otterb
fonte
2

Nas versões recentes do matplotlib, convém experimentar o Layout restrito .

Michel de Ruiter
fonte