Eliminar espacios en blanco alrededor de una imagen guardada en matplotlib

172

Necesito tomar una imagen y guardarla después de algún proceso. La figura se ve bien cuando la muestro, pero después de guardar la figura, obtuve un espacio en blanco alrededor de la imagen guardada. He probado la 'tight'opción de savefigmétodo, tampoco funcionó. El código:

  import matplotlib.image as mpimg
  import matplotlib.pyplot as plt

  fig = plt.figure(1)
  img = mpimg.imread(path)
  plt.imshow(img)
  ax=fig.add_subplot(1,1,1)

  extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
  plt.savefig('1.png', bbox_inches=extent)

  plt.axis('off') 
  plt.show()

Estoy tratando de dibujar un gráfico básico usando NetworkX en una figura y guardarlo. Me di cuenta de que sin gráfico funciona, pero cuando agrego un gráfico obtengo un espacio en blanco alrededor de la imagen guardada;

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import networkx as nx

G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_edge(1,3)
G.add_edge(1,2)
pos = {1:[100,120], 2:[200,300], 3:[50,75]}

fig = plt.figure(1)
img = mpimg.imread("C:\\images\\1.jpg")
plt.imshow(img)
ax=fig.add_subplot(1,1,1)

nx.draw(G, pos=pos)

extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches = extent)

plt.axis('off') 
plt.show()
Ahmet Tuğrul Bayrak
fuente
Lo que realmente funcionó para mí fue recortar el pdf usando otra herramienta, como pdfcrop.
toliveira

Respuestas:

170

No puedo afirmar que sé exactamente por qué o cómo funciona mi "solución", pero esto es lo que tenía que hacer cuando quería trazar el contorno de un par de secciones de perfil aerodinámico, sin márgenes blancos, en un archivo PDF. (Tenga en cuenta que usé matplotlib dentro de un cuaderno de IPython, con la bandera -pylab).

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.savefig("filename.pdf", bbox_inches = 'tight',
    pad_inches = 0)

He tratado de desactivar diferentes partes de esto, pero esto siempre conduce a un margen blanco en alguna parte. Incluso puede haber modificado esto para evitar que las líneas gruesas cerca de los límites de la figura se afeiten por la falta de márgenes.

Johannes S.
fuente
66
Finalmente algo que funciona, muchas gracias! Por cierto, en mi caso solo las dos líneas que usaban set_major_locatoreran necesarias.
Florian Brucker
66
Pasé la última hora probando varias cosas y no pude deshacerme de un borde blanco de 1px. Esto fue lo único que funcionó, específicamente lo pad_inches=0que otras respuestas no mencionan.
AnnanFay
1
set_major_locatorFue clave para mí.
kmac
16
pad_inchesme ayudó.
Myles Baker
55
matplotlib.ticker.NullLocator ()
Joop
200

Se puede quitar el relleno de espacios en blanco mediante el establecimiento bbox_inches="tight"de savefig:

plt.savefig("test.png",bbox_inches='tight')

Tendrá que poner el argumento bbox_inchescomo una cadena, tal vez es por eso que no funcionó antes para usted.


Posibles duplicados:

Gráficos de Matplotlib: eliminación de ejes, leyendas y espacios en blanco

¿Cómo establecer los márgenes para una figura matplotlib?

Reduzca los márgenes izquierdo y derecho en el diagrama matplotlib

Enganchado
fuente
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
30
Eso no está del todo bien. Cuando usa esa bbox_inchesopción, hay otro valor predeterminado que deja algo de espacio. Si realmente quieres deshacerte de todo, también debes usarlo pad_inches=0.0. Por supuesto, un relleno tan apretado con frecuencia se corta, por ejemplo, exponentes ...
Mike
55
Para eliminar también el borde negro, es posible que deba configurarlopad_inches=-0.1
lenhhoxung
10
Esto simplemente no funciona, aún obtienes espacios en blanco alrededor de la figura. Configurar la opción transparente (como se menciona en algunas respuestas) tampoco ayuda, el espacio en blanco sigue ahí, solo es transparente.
BjornW
1
@piperchester esa es una buena pregunta, pero probablemente debería hacerse como una pregunta nueva para que no se pierda en los comentarios. ¡Sin embargo, debe vincular la nueva pregunta con la anterior!
Enganchado el
21

Después de probar las respuestas anteriores sin éxito (y un montón de otras publicaciones de pila), lo que finalmente funcionó para mí fue simplemente

plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
            hspace = 0, wspace = 0)
plt.margins(0,0)
plt.savefig("myfig.pdf")

Es importante destacar que esto no incluye los argumentos de bbox o relleno.

SuaveSouris
fuente
44
Esta debería ser la respuesta aceptada. Además, ni siquiera necesita llamar set_axis_off. No afecta a la imagen guardada ya que después de que subplots_adjustel eje se encuentra fuera de la extensión de la figura y, de todos modos, no se trazará. Sin embargo, en los portátiles Jupyter, debe deshabilitar explícitamente el eje, ya que el backend en línea sobrescribe esta configuración.
MaxPowers
20

Encontré algo de Arvind Pereira ( http://robotics.usc.edu/~ampereir/wordpress/?p=626 ) y parecía funcionar para mí:

plt.savefig(filename, transparent = True, bbox_inches = 'tight', pad_inches = 0)
unclerico
fuente
77
transparent=Truehará que parezca que no hay problema, pero solo ocultará el espacio en blanco, las dimensiones de la imagen no estarán bien.
Vlady Veselinov
Gracias por mencionar pad_inches! ¡Ojalá hubiera sabido de esta opción antes!
ingomueller.net
1
Esto funciona para la mayoría de las parcelas, pero eliminó el borde derecho de mi matriz de confusión. Solo agregue un pequeño rellenopad_inches=.25
YTZ
14

La siguiente función incorpora la respuesta de johannes anterior. Lo he probado con plt.figurey plt.subplots()con múltiples ejes, y funciona muy bien.

def save(filepath, fig=None):
    '''Save the current image with no whitespace
    Example filepath: "myfig.png" or r"C:\myfig.pdf" 
    '''
    import matplotlib.pyplot as plt
    if not fig:
        fig = plt.gcf()

    plt.subplots_adjust(0,0,1,1,0,0)
    for ax in fig.axes:
        ax.axis('off')
        ax.margins(0,0)
        ax.xaxis.set_major_locator(plt.NullLocator())
        ax.yaxis.set_major_locator(plt.NullLocator())
    fig.savefig(filepath, pad_inches = 0, bbox_inches='tight')
TomNoruega
fuente
Trabajado como un encanto. La respuesta anterior fue algunos comandos necesarios en mi exportación.
Kevin S
11

Encontré que los siguientes códigos funcionan perfectamente para el trabajo.

fig = plt.figure(figsize=[6,6])
ax = fig.add_subplot(111)
ax.imshow(data)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.set_frame_on(False)
plt.savefig('data.png', dpi=400, bbox_inches='tight',pad_inches=0)
Richard Yu Liu
fuente
2
En general, las respuestas son mucho más útiles si incluyen una explicación de lo que se pretende que haga el código y por qué eso resuelve el problema sin introducir otros.
Tim Diekmann
7

Seguí esta secuencia y funcionó a las mil maravillas.

plt.axis("off")
fig=plt.imshow(image array,interpolation='nearest')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('destination_path.pdf',
    bbox_inches='tight', pad_inches=0, format='pdf', dpi=1200)
Kan
fuente
1
En realidad, encontré que esta respuesta es fácil y más conveniente de usar.
sikisis
1
Este funcionó para mí; la respuesta aceptada no.
Joe
3

Para cualquiera que quiera trabajar en píxeles en lugar de pulgadas, esto funcionará.

Además de lo habitual, también necesitarás

from matplotlib.transforms import Bbox

Entonces puedes usar lo siguiente:

my_dpi = 100 # Good default - doesn't really matter

# Size of output in pixels
h = 224
w = 224

fig, ax = plt.subplots(1, figsize=(w/my_dpi, h/my_dpi), dpi=my_dpi)

ax.set_position([0, 0, 1, 1]) # Critical!

# Do some stuff
ax.imshow(img)
ax.imshow(heatmap) # 4-channel RGBA
ax.plot([50, 100, 150], [50, 100, 150], color="red")

ax.axis("off")

fig.savefig("saved_img.png",
            bbox_inches=Bbox([[0, 0], [w/my_dpi, h/my_dpi]]),
            dpi=my_dpi)

ingrese la descripción de la imagen aquí

Simon Thomas
fuente
No tiene que especificar dpi, puede usar el predeterminado en su fig.dpilugar
intsco
1

Un enfoque mucho más simple que he encontrado es de uso plt.imsave:

    import matplotlib.pyplot as plt
    arr = plt.imread(path)
    plt.imsave('test.png', arr)
Parth92
fuente
Respuesta infravalorada. Esto me ayudó después de una larga búsqueda de cómo retener la resolución y eliminar espacios en blanco plt.savefig().
nihal111
Esto funciona solo en caso de que desee guardar una matriz (!) Como imagen. Esto no permite guardar una figura arbitraria.
MaxPowers
¿Qué quieres decir con imagen arbitraria? ¿No es una imagen una matriz de valores?
Parth92
0

Puedes probar esto. Resolvió mi problema.

import matplotlib.image as mpimg
img = mpimg.imread("src.png")
mpimg.imsave("out.png", img, cmap=cmap)
usuario1410665
fuente
-1

Si desea mostrar lo que se va a guardar, le recomiendo usar la plt.tight_layouttransformación, que en realidad es más preferible, ya que no hace recortes innecesarios cuando se usaplt.savefig

import matplotlib as plt    
plt.plot([1,2,3], [1,2,3])
plt.tight_layout(pad=0)
plt.savefig('plot.png')
Keto
fuente
-4

Esto funciona para mí guardando una matriz numpy trazada con imshow para archivar

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(10,10))
plt.imshow(img) # your image here
plt.axis("off")
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, 
        hspace = 0, wspace = 0)
plt.savefig("example2.png", box_inches='tight', dpi=100)
plt.show()
Alejandro Sazo
fuente