Reduzca los márgenes izquierdo y derecho en el gráfico matplotlib

178

Estoy luchando para lidiar con mis márgenes de trama en matplotlib. He usado el siguiente código para producir mi gráfico:

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

Sin embargo, obtengo una cifra de salida con mucho espacio en blanco a cada lado de la trama. Busqué en Google y leí la documentación de matplotlib, pero parece que no puedo encontrar cómo reducir esto.

robintw
fuente
¿El problema es la cantidad de espacio en blanco en el extentde la imshowfigura, o la cantidad de espacio en blanco en el borde png resultante, en torno a la figura, que genera savefig?
unutbu
Creo que ambos: parece que hay mucho espacio tanto en la ventana de visualización como en el PNG. Sin embargo, el resultado importante es el archivo png producido por savefig, así que eso es lo que me gustaría ordenar.
robintw
Los he estado recortando en GIMP después. : /
endolito

Respuestas:

251

Una forma de hacer esto automáticamente es bbox_inches='tight'kwarg to plt.savefig.

P.ej

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

Otra forma es 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
fuente
55
¿Hay alguna forma de hacer que esto sea el predeterminado?
endolith
1
Si tiene varias subtramas y desea guardar cada una de ellas, también puede usar esto fig.savefig(). ( plt.savefig()no funcionará en ese caso.)
Abhranil Das
1
Todo lo que hace es recortar la imagen después de que se ha renderizado; Si está intentando imponer una resolución particular, la imagen saldrá más pequeña .
desvío
55
@detly - Sí. Eso es exactamente lo que hace (aunque también puede recortar "fuera" y agrandar la imagen también). Para lo que quieres, échale un vistazo fig.tight_layout(). Esa función no existía cuando esta respuesta se escribió originalmente, de lo contrario la mencionaría de manera más prominente.
Joe Kington el
2
Si alguien tiene un problema, usefig = plt.gcf()
KyungHoon Kim
148

Puede ajustar el espacio alrededor de las figuras matplotlib utilizando la función 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)

Esto funcionará tanto para la figura en pantalla como para guardarla en un archivo, y es la función correcta para llamar incluso si no tiene múltiples trazados en la figura.

Los números son fracciones de las dimensiones de la figura y deberán ajustarse para permitir las etiquetas de la figura.

DaveP
fuente
8
Los valores asignados a los parámetros y no por cuánto cambiarlos, son dónde establecer el margen. En otras palabras, si desea aumentar el margen del borde derecho en un 10%, debe establecer right = 0.9, not right = 0.1 matplotlib.sourceforge.net/api/…
drootang
1
Tiene sentido señalar que, obviamente, puede especificar valores negativos en plt.subplots_adjust (). Hacerlo incluso le permite dibujar fuera del área de la figura y también lidiar con márgenes molestos.
surchs
Esto también funciona en GridSpecobjetos llamando al updatemétodo (consulte stackoverflow.com/a/20058199/1030876 ).
Aaron Voelker
57

Todo lo que necesitas es

plt.tight_layout()

antes de su salida.

Además de reducir los márgenes, esto también agrupa estrechamente el espacio entre las subtramas:

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()
usuario2065406
fuente
77
Creo que este es realmente el mejor método. No requiere guardar la figura como `bbox = 'tight' y corrige todo tipo de otros problemas de diseño en figuras estrechas.
dshepherd
2
esta debería ser la respuesta correcta porque se comporta como cabría esperar, ya que se aplica a la FIGURA en lugar de a la imagen.
Majid alDosari
Curiosamente, esto también cambia el ancho de la trama real (es decir, los picos están más juntos) en comparación con bbox_inches='tight', que solo recorta el espacio en blanco alrededor de los bordes, pero deja la trama sola. Creé la figura con plt.figure(figsize=(10,3)).
Fritz
9

Solo úselo ax = fig.add_axes([left, bottom, width, height]) si desea un control exacto del diseño de la figura. p.ej.

left = 0.05
bottom = 0.05
width = 0.9
height = 0.9
ax = fig.add_axes([left, bottom, width, height])
masón
fuente
6

En caso de que alguien se pregunte cómo deshacerse del resto del margen blanco después de aplicar plt.tight_layout()o fig.tight_layout(): Con el parámetro pad(que es el 1.08predeterminado), puede hacerlo aún más apretado: "Relleno entre el borde de la figura y los bordes de subtramas, como una fracción del tamaño de fuente ". Así por ejemplo

plt.tight_layout(pad=0.05)

lo reducirá a un margen muy pequeño. Poner 0no funciona para mí, ya que también hace que la caja de la subtrama se corte un poco.

Oberwaschlappen
fuente
4
plt.savefig("circle.png", bbox_inches='tight',pad_inches=-1)
Tian Chu
fuente
1
"pad_inches = -1" porque mi savefig solo produce parte de la figura.
Yu Shen
Usar un parámetro en la savefigfunción es elegante, sin embargo, el valor negativo para pad_inchesno es necesariamente necesario en todos los casos.
MichaelHuelsen
configúrelo en 0, ayuda
Joop
4

El problema con matplotlibs subplots_adjust es que los valores que ingresas son relativos al tamaño x e y de la figura. Este ejemplo es para el correcto dimensionamiento para imprimir un pdf:

Para eso, recalculo el espacio relativo a 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 una figura de pulgadas 'figure.xsize' en dimensión xy pulgadas 'figure.ysize' en dimensión y. Por lo tanto, toda la figura tiene un margen izquierdo de 5 mm, margen inferior de 4 mm, derecho de 1 mm y superior de 3 mm dentro de las etiquetas. La conversión de (x / 25.4) se realizó porque necesitaba convertir mm a pulgadas.

Tenga en cuenta que el tamaño del gráfico puro de x será "figure.xsize - margen izquierdo - margen derecho" y el tamaño del gráfico puro de y será "figure.ysize - margen inferior - margen superior" en pulgadas

Otros fragmentos (no estoy seguro acerca de estos, solo quería proporcionar los otros parámetros)

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

y

pyplot.savefig("outputname.eps", dpi = 100)
Sammy
fuente
3
De dónde sacaste xsizey ysizede dónde . Uso esas propiedades y obtengoAttributeError: 'Figure' object has no attribute 'xsize'
cj5
4

inspirado por la respuesta de Sammys arriba:

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)

Donde figsize es la tupla que usaste en fig = pyplot.figure(figsize=...)

michaelosthege
fuente
2

Para mí, las respuestas anteriores no funcionaron matplotlib.__version__ = 1.4.3en Win7. Entonces, si solo estamos interesados ​​en la imagen en sí (es decir, si no necesitamos anotaciones, eje, marcas, título, etiqueta, etc.), entonces es mejor simplemente guardar la matriz numpy como imagen en lugar 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)

Además, utilizando las funciones de dibujo opencv (cv2.line, cv2.polylines), podemos hacer algunos dibujos directamente en la matriz numpy. http://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html

otterb
fuente
2

Con versiones recientes de matplotlib, es posible que desee probar Diseño restringido .

Michel de Ruiter
fuente