Guarde el diagrama en el archivo de imagen en lugar de mostrarlo con Matplotlib

1150

Estoy escribiendo un script rápido y sucio para generar tramas sobre la marcha. Estoy usando el siguiente código (de la documentación de Matplotlib ) como punto de partida:

from pylab import figure, axes, pie, title, show

# Make a square figure and axes
figure(1, figsize=(6, 6))
ax = axes([0.1, 0.1, 0.8, 0.8])

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
fracs = [15, 30, 45, 10]

explode = (0, 0.05, 0, 0)
pie(fracs, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True)
title('Raining Hogs and Dogs', bbox={'facecolor': '0.8', 'pad': 5})

show()  # Actually, don't show, just save to foo.png

No quiero mostrar el diagrama en una GUI, en cambio, quiero guardar el diagrama en un archivo (por ejemplo, foo.png), para que, por ejemplo, pueda usarse en scripts por lotes. ¿Cómo puedo hacer eso?

Homunculus Reticulli
fuente
85
Parece que encontré la respuesta: its pylab.savefig ('foo.png')
Homunculus Reticulli
2
¿El enlace tal vez debería enlazar a algún lugar en matplotlib.org?
A.Wan
40
Además, si no usa pylab, el objeto figura también tiene un savefigmétodo. Entonces puedes llamar fig = plt.figure()entonces fig.savefig(...).
A.Wan
27
Muchas de las respuestas en la parte inferior de la página mencionan lo plt.close(fig)que es especialmente importante en los bucles grandes. De lo contrario, las cifras se mantienen abiertos a la espera en la memoria y todas las figuras abiertas se le aparecen al momento de celebrarplt.show()
timctran
nb: se prefiere matplotlib.pyplot: stackoverflow.com/questions/11469336/…
ErichBSchulz

Respuestas:

1441

Si bien la pregunta ha sido respondida, me gustaría agregar algunos consejos útiles al usar matplotlib.pyplot.savefig . El formato de archivo puede especificarse mediante la extensión:

from matplotlib import pyplot as plt

plt.savefig('foo.png')
plt.savefig('foo.pdf')

Dará una salida rasterizada o vectorizada respectivamente, ambas que podrían ser útiles. Además, encontrará que pylabdeja un espacio en blanco generoso, a menudo indeseable, alrededor de la imagen. Eliminarlo con:

savefig('foo.png', bbox_inches='tight')
Enganchado
fuente
99
¿Es posible cambiar las dimensiones de la imagen resultante?
Llamageddon
43
@Asmageddon En plt.savefigpuedes cambiar el dpi, mira el enlace en la respuesta. Las dimensiones se pueden controlar al crear la figura, ver figsizeen matplotlib.org/api/figure_api.html#matplotlib.figure.Figure
Enganchado el
55
@MoTSCHIGGE puede llamar, lo plt.ioff()que debería desactivar la interactividad en los matplotlib.pyplotcomandos.
rubenvb
55
@STMohammed foo.png es el camino. Podría, por ejemplo, ponerlo en un directorio como este savefig("mydir/foo.png").
Enganchado el
3
bbox_inches = 'tight' funciona como un encanto. Me
alegraste el
205

Como han dicho otros, plt.savefig()o de fig1.savefig()hecho es la forma de guardar una imagen.

Sin embargo, he descubierto que en ciertos casos la figura siempre se muestra . (por ejemplo, con Spyder teniendo plt.ion(): modo interactivo = Encendido). Trabajo alrededor de esto forzando el cierre de la ventana de la figura en mi bucle gigante con plt.close(figure_object)(ver documentación ), por lo que no tengo un millón de figuras abiertas durante el bucle:

import matplotlib.pyplot as plt
fig, ax = plt.subplots( nrows=1, ncols=1 )  # create figure & 1 axis
ax.plot([0,1,2], [10,20,3])
fig.savefig('path/to/save/image/to.png')   # save the figure to file
plt.close(fig)    # close the figure window

Debería poder volver a abrir la figura más tarde si es necesario con fig.show()(no me probé).

Demis
fuente
99
También puede establecer plt.ioff() # turn of interactive plotting mode, pero eso puede deshabilitar el comportamiento que desea utilizar si su código sale con un error.
Demis
2
Verá el mismo problema en los cuadernos Jupyter. plt.close(fig)resuelto
intsco
163

La solucion es:

pylab.savefig('foo.png')
Lukasz Czerwinski
fuente
89

Acabo de encontrar este enlace en la documentación de MatPlotLib que aborda exactamente este problema: http://matplotlib.org/faq/howto_faq.html#generate-images-without-having-a-window-appear

Dicen que la forma más fácil de evitar que la figura aparezca es usar un backend no interactivo (por ejemplo, Agg), a través de matplotib.use(<backend>), por ejemplo:

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
plt.plot([1,2,3])
plt.savefig('myfig')

Todavía prefiero usarlo personalmente plt.close( fig ), desde entonces tienes la opción de ocultar ciertas figuras (durante un ciclo), pero aún así mostrar las cifras para el procesamiento de datos posterior al ciclo. Sin embargo, probablemente sea más lento que elegir un backend no interactivo; sería interesante si alguien lo probara.

ACTUALIZACIÓN : para Spyder, generalmente no puede configurar el back-end de esta manera (porque Spyder generalmente carga matplotlib temprano, evitando que lo use matplotlib.use()).

En su lugar, use plt.switch_backend('Agg')o desactive " habilitar soporte " en las preferencias de Spyder y ejecute el matplotlib.use('Agg')comando usted mismo.

De estos dos consejos: uno , dos

Demis
fuente
1
Esto funciona muy bien para situaciones en las que no tiene una pantalla establecida. Usar otro backend con .plot()arrojará un error si os.environ['DISPLAY']no está configurado correctamente.
economía
1
Gracias. Esto funciona y es muy útil para los servidores de producción donde no hay conexión a Internet y necesitan que el administrador del sistema instale los paquetes.
Leon
Me gusta el tutorial que tiene el sitio matplotlib para la descripción / definición de "backends": matplotlib.org/tutorials/introductory/…
Tanner Strunk
47

Si no le gusta el concepto de la figura "actual", haga lo siguiente:

import matplotlib.image as mpimg

img = mpimg.imread("src.png")
mpimg.imsave("out.png", img)
wonder.mice
fuente
2
¿Esto no sólo copiar src.pnga out.png?
gerrit
Ese es solo un ejemplo, que muestra que si tiene un objeto de imagen ( img), puede guardarlo en un archivo con el .imsave()método.
wonder.mice
44
@ wonder.mice ayudaría a mostrar cómo crear una imagen sin usar la figura actual.
scry
@ wonder.mice Gracias por este ejemplo, es el primero que me mostró cómo guardar un objeto de imagen en .png.
Arthur Dent
@scry No siempre necesita crear una imagen, a veces prueba un código y desea una salida visual, es útil en tales ocasiones.
Schütze
29

Las otras respuestas son correctas. Sin embargo, a veces encuentro que quiero abrir el objeto de la figura más tarde. Por ejemplo, podría querer cambiar los tamaños de las etiquetas, agregar una cuadrícula o hacer otro procesamiento. En un mundo perfecto, simplemente volvería a ejecutar el código que genera la trama y adaptaría la configuración. Por desgracia, el mundo no es perfecto. Por lo tanto, además de guardar en PDF o PNG, agrego:

with open('some_file.pkl', "wb") as fp:
    pickle.dump(fig, fp, protocol=4)

De esta manera, luego puedo cargar el objeto de la figura y manipular la configuración como me plazca.

También escribo la pila con el código fuente y el locals()diccionario para cada función / método en la pila, para que luego pueda decir exactamente qué generó la figura.

NB: Tenga cuidado, ya que a veces este método genera archivos enormes.

gerrit
fuente
¿No sería más fácil desarrollar en un cuaderno Jupyter con las cifras en línea? De esta manera, puede rastrear exactamente el historial e incluso volver a ejecutarlo.
Ciprian Tomoiagă
3
@CiprianTomoiaga Nunca genero gráficos de producción desde un shell interactivo de Python (Jupyter o de otro tipo). Trazo todo de los guiones.
gerrit
28
import datetime
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.pyplot as plt

# Create the PdfPages object to which we will save the pages:
# The with statement makes sure that the PdfPages object is closed properly at
# the end of the block, even if an Exception occurs.
with PdfPages('multipage_pdf.pdf') as pdf:
    plt.figure(figsize=(3, 3))
    plt.plot(range(7), [3, 1, 4, 1, 5, 9, 2], 'r-o')
    plt.title('Page One')
    pdf.savefig()  # saves the current figure into a pdf page
    plt.close()

    plt.rc('text', usetex=True)
    plt.figure(figsize=(8, 6))
    x = np.arange(0, 5, 0.1)
    plt.plot(x, np.sin(x), 'b-')
    plt.title('Page Two')
    pdf.savefig()
    plt.close()

    plt.rc('text', usetex=False)
    fig = plt.figure(figsize=(4, 5))
    plt.plot(x, x*x, 'ko')
    plt.title('Page Three')
    pdf.savefig(fig)  # or you can pass a Figure object to pdf.savefig
    plt.close()

    # We can also set the file's metadata via the PdfPages object:
    d = pdf.infodict()
    d['Title'] = 'Multipage PDF Example'
    d['Author'] = u'Jouni K. Sepp\xe4nen'
    d['Subject'] = 'How to create a multipage pdf file and set its metadata'
    d['Keywords'] = 'PdfPages multipage keywords author title subject'
    d['CreationDate'] = datetime.datetime(2009, 11, 13)
    d['ModDate'] = datetime.datetime.today()
Victor Juliet
fuente
28

Después de usar plot () y otras funciones para crear el contenido que desea, puede usar una cláusula como esta para seleccionar entre trazar en la pantalla o archivar:

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(4, 5))       # size in inches
# use plot(), etc. to create your plot.

# Pick one of the following lines to uncomment
# save_file = None
# save_file = os.path.join(your_directory, your_file_name)  

if save_file:
    plt.savefig(save_file)
    plt.close(fig)
else:
    plt.show()
Mark P.
fuente
Algunos dicen que fig = plt.figure(figuresize=4, 5)podría serfig = plt.figure(figsize=(4, 5)) #figure sizes in inches
usuario
24

Usé lo siguiente:

import matplotlib.pyplot as plt

p1 = plt.plot(dates, temp, 'r-', label="Temperature (celsius)")  
p2 = plt.plot(dates, psal, 'b-', label="Salinity (psu)")  
plt.legend(loc='upper center', numpoints=1, bbox_to_anchor=(0.5, -0.05),        ncol=2, fancybox=True, shadow=True)

plt.savefig('data.png')  
plt.show()  
f.close()
plt.close()

Me pareció muy importante usar plt.show después de guardar la figura, de lo contrario no funcionará. figura exportada en png

Cristian Muñoz
fuente
2
lo siento, ¿qué hay en esto? archivo de imagen trazada? f= plt.savefig('data.png')
Morse
14

Puedes hacer:

plt.show(hold=False)
plt.savefig('name.pdf')

y recuerde dejar que savefig termine antes de cerrar el diagrama de la GUI. De esta manera puedes ver la imagen de antemano.

Alternativamente, puede mirarlo con plt.show() Luego cierre la GUI y ejecute el script nuevamente, pero esta vez reemplácelo plt.show()con plt.savefig().

Alternativamente, puedes usar

fig, ax = plt.figure(nrows=1, ncols=1)
plt.plot(...)
plt.show()
fig.savefig('out.pdf')
Cascanueces
fuente
2
tiene un argumento de palabra clave inesperado 'hold'
amitdatta
13

Si, como yo, usa Spyder IDE, debe deshabilitar el modo interactivo con:

plt.ioff()

(este comando se inicia automáticamente con el inicio científico)

Si desea habilitarlo nuevamente, use:

plt.ion()

Covich
fuente
12

La solución :

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.style.use('ggplot')
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000))
ts = ts.cumsum()
plt.figure()
ts.plot()
plt.savefig("foo.png", bbox_inches='tight')

Si desea mostrar la imagen y guardarla, use:

%matplotlib inline

después import matplotlib

Durgesh satam
fuente
9

De acuerdo con la pregunta Matplotlib (pyplot) savefig genera una imagen en blanco .

Una cosa debe tener en cuenta: si usa plt.showy debería después plt.savefig, o le dará una imagen en blanco.

Un ejemplo detallado:

import numpy as np
import matplotlib.pyplot as plt


def draw_result(lst_iter, lst_loss, lst_acc, title):
    plt.plot(lst_iter, lst_loss, '-b', label='loss')
    plt.plot(lst_iter, lst_acc, '-r', label='accuracy')

    plt.xlabel("n iteration")
    plt.legend(loc='upper left')
    plt.title(title)
    plt.savefig(title+".png")  # should before plt.show method

    plt.show()


def test_draw():
    lst_iter = range(100)
    lst_loss = [0.01 * i + 0.01 * i ** 2 for i in xrange(100)]
    # lst_loss = np.random.randn(1, 100).reshape((100, ))
    lst_acc = [0.01 * i - 0.01 * i ** 2 for i in xrange(100)]
    # lst_acc = np.random.randn(1, 100).reshape((100, ))
    draw_result(lst_iter, lst_loss, lst_acc, "sgd_method")


if __name__ == '__main__':
    test_draw()

ingrese la descripción de la imagen aquí

Jayhello
fuente
6
import matplotlib.pyplot as plt
plt.savefig("image.png")

En Jupyter Notebook, debe eliminar plt.show()y agregar plt.savefig(), junto con el resto del código plt en una celda. La imagen seguirá apareciendo en su cuaderno.

Punnerud
fuente
1
"remove plt.show ()" .. esto me salvó el día ...
Guru
4

Dado que hoy (no estaba disponible cuando se hizo esta pregunta) muchas personas usan Jupyter Notebook como consola de Python, hay una manera extremadamente fácil de guardar las tramas ya que .png, simplemente llame a la clase matplotlib's pylabde Jupyter Notebook, trace la figura' en línea 'jupyter celdas, y luego arrastre esa figura / imagen a un directorio local. ¡No te olvides %matplotlib inlineen la primera línea!

Hamidreza
fuente
1
que es una idea buena, sólo tiene que tomar nota de los efectos de tamaño de archivo si la imagen se deja incrustado en el cuaderno ..
prusswan
3

Además de los anteriores, agregué __file__el nombre para que la imagen y el archivo Python obtengan los mismos nombres. También agregué algunos argumentos para que se vea mejor:

# Saves a PNG file of the current graph to the folder and updates it every time
# (nameOfimage, dpi=(sizeOfimage),Keeps_Labels_From_Disappearing)
plt.savefig(__file__+".png",dpi=(250), bbox_inches='tight')
# Hard coded name: './test.png'
re
fuente
2

Al usar matplotlib.pyplot, primero debe guardar su trama y luego cerrarla usando estas 2 líneas:

fig.savefig('plot.png') # save the plot, place the path you want to save the figure in quotation
plt.close(fig) # close the figure window
Hielo silencioso
fuente
1

Como se sugirió anteriormente, puede usar:

import matplotlib.pyplot as plt
plt.savefig("myfig.png")

Para guardar cualquier imagen de IPhython que esté mostrando. O en una nota diferente (mirando desde un ángulo diferente), si alguna vez puede trabajar con cv abierto, o si ha importado cv abierto, puede optar por:

importar cv2

cv2.imwrite ("myfig.png", imagen)

Pero esto es solo por si necesitas trabajar con Open CV. De lo contrario, plt.savefig () debería ser suficiente.

Aditya Bhattacharya
fuente
0

Puede guardar su imagen con cualquier extensión (png, jpg, etc.) y con la resolución que desee. Aquí hay una función para guardar tu figura.

import os

def save_fig(fig_id, tight_layout=True, fig_extension="png", resolution=300):
    path = os.path.join(IMAGES_PATH, fig_id + "." + fig_extension)
    print("Saving figure", fig_id)
    if tight_layout:
        plt.tight_layout()
    plt.savefig(path, format=fig_extension, dpi=resolution)

'fig_id' es el nombre con el que desea guardar su figura. Espero eso ayude:)

Rudresh Dixit
fuente
0

Puedes hacerlo así:

def plotAFig():
  plt.figure()
  plt.plot(x,y,'b-')
  plt.savefig("figurename.png")
  plt.close()
Mark90
fuente