Guarde el gráfico en el archivo de imagen en lugar de mostrarlo usando Matplotlib

1408

Estoy escribiendo un script rápido y sucio para generar gráficos 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 gráfico en una GUI, en su lugar, quiero guardar el gráfico en un archivo (digamos foo.png), para que, por ejemplo, se pueda usar en scripts por lotes. ¿Cómo puedo hacer eso?

6
  • 92
    Parece que encontré la respuesta: es pylab.savefig ('foo.png') 8/03/12 a las 17:42
  • 2
    ¿El enlace debería enlazar a algún lugar de matplotlib.org?
    A.Wan
    10/12/15 a las 19:40
  • 46
    Además, si no usa pylab, el objeto de figura también tiene un savefigmétodo. Para que pueda llamar fig = plt.figure()a continuación fig.savefig(...).
    A.Wan
    10/12/15 a las 19:43
  • 31
    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 figuras permanecen abiertas y esperando en la memoria y todas las figuras abiertas se mostrarán al ejecutarplt.show() 8 de junio de 2017 a las 4:09
  • nb: se prefiere matplotlib.pyplot: stackoverflow.com/questions/11469336/… 11/08/18 a las 9:18
1748

Si bien la pregunta ha sido respondida, me gustaría agregar algunos consejos útiles al usar matplotlib.pyplot.savefig . El formato de archivo se puede especificar 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. Puede eliminar el espacio en blanco usando:

plt.savefig('foo.png', bbox_inches='tight')
10
  • 13
    ¿Es posible cambiar las dimensiones de la imagen resultante? 28/10/2013 a las 21:15
  • 45
    @Asmageddon En plt.savefigpuede cambiar el dpi, vea 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
    Hooked
    29/10/2013 a las 0:46
  • 5
    @MoTSCHIGGE puede llamar, lo plt.ioff()que debería deshabilitar la interactividad en los matplotlib.pyplotcomandos.
    rubenvb
    10 de diciembre de 2015 a las 8:25
  • 7
    @STMohammed foo.png es el camino. Podría, por ejemplo, ponerlo en un directorio como este savefig("mydir/foo.png").
    Hooked
    3 de agosto de 2018 a las 13:56
  • 3
    bbox_inches = 'tight' funciona a las mil maravillas. Me has alegrado el día 3 oct 2019 a las 8:34
249

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 = Activado). Soluciono 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 fig.show()(no me probé).

5
  • 11
    También puede configurar plt.ioff() # turn of interactive plotting mode, pero eso podría deshabilitar el comportamiento que le gustaría usar si su código sale con un error.
    Demis
    14/12/15 a las 19:04
  • 2
    Verá el mismo problema en los cuadernos de Jupyter. plt.close(fig)resuelto
    intsco
    15/07/19 a las 14:21
  • Podría explicar lo que son ax, figy plt? El uso de estos siempre me confunde. 8/06/20 a las 21:25
  • pltes solo un alias para matplotlib.pyplot, para facilitar la escritura. Busque el help(plt.subplots)para ver qué devuelve, que también se menciona en los comentarios de mi código, un Figureobjeto y un Axisobjeto.
    Demis
    10/06/20 a las 0:20
  • 1
    Tenga en cuenta que los nombres ax/ fig/ pltse componen de nombres de variables; llámelos como desee. De cualquier manera, contienen Objetos. Puede ver qué objetos subplotsdevuelve aquí: matplotlib.org/3.2.1/api/_as_gen/… , y qué pyplotmódulo es aquí: matplotlib.org/tutorials/introductory/pyplot.html .
    Demis
    28/06/20 a las 22:45
171

La solucion es:

pylab.savefig('foo.png')
1
  • 4
    pylab no está definido
    user14349917
    6 de enero a las 3:42
101

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 aparezca la figura es utilizar 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')

Personalmente, sigo prefiriendo usar plt.close( fig ), ya que entonces tiene la opción de ocultar ciertas figuras (durante un bucle), pero aún mostrar figuras para el procesamiento de datos posterior al bucle. 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 backend de esta manera (porque Spyder generalmente carga matplotlib temprano, lo que le impide usarlo 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

3
  • 1
    Esto funciona muy bien para situaciones en las que no tienes una pantalla configurada. El uso de otro backend con .plot()arrojará un error si os.environ['DISPLAY']no está configurado correctamente.
    economy
    30 de mayo de 2018 y 18:23
  • 1
    Gracias. esto funciona y es muy útil para los servidores de producción donde no hay conexión a Internet y se necesita un administrador del sistema para instalar los paquetes. 11/11/18 a las 6:48
  • Me gusta el tutorial que tiene el sitio matplotlib para la descripción / definición de "backends": matplotlib.org/tutorials/introductory/… 30 de mayo de 2020 a las 16:52
56

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

import matplotlib.image as mpimg

img = mpimg.imread("src.png")
mpimg.imsave("out.png", img)
5
  • 2
    ¿Esto no sólo copiar src.pnga out.png?
    gerrit
    26 de mayo de 2016 a las 11:44
  • 1
    Eso es solo un ejemplo, que muestra si tiene un objeto de imagen ( img), entonces puede guardarlo en un archivo con el .imsave()método. 26 de mayo de 2016 a las 23:29
  • 6
    @ wonder.mice ayudaría a mostrar cómo crear una imagen sin usar la figura actual.
    scry
    10 de agosto de 2016 a las 6:50
  • 1
    @ wonder.mice Gracias por este ejemplo, es el primero que me mostró cómo guardar un objeto de imagen en .png. 24 de mayo de 2017 a las 21:09
  • @scry No siempre es necesario crear una imagen, a veces prueba algún código y desea una salida visual, es útil en tales ocasiones. 13 feb 2019 a las 15:08
34
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()
1
  • plt.close() es exactamente lo que estaba buscando!
    Eenoku
    18 de mayo a las 10:57
33

Las otras respuestas son correctas. Sin embargo, a veces encuentro que quiero abrir el objeto de figura más tarde. Por ejemplo, es posible que desee cambiar los tamaños de las etiquetas, agregar una cuadrícula o realizar 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 eso, 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 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 luego poder decir exactamente qué generó la figura.

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

2
  • ¿No sería más fácil hacer el desarrollo en un portátil jupyter, con las cifras en línea? De esta manera, puede realizar un seguimiento exacto del historial e incluso volver a ejecutarlo. 4 dic 2017 a las 14:55
  • 4
    @CiprianTomoiaga Nunca genero gráficos de producción desde un shell interactivo de Python (Jupyter o de otro tipo). Trazo todo a partir de guiones.
    gerrit
    5 de diciembre de 2017 a las 23:42
30

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 en un archivo:

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()
1
  • Algunos dicen que fig = plt.figure(figuresize=4, 5)podría serfig = plt.figure(figsize=(4, 5)) #figure sizes in inches
    user
    13/01/19 a las 12:32
25

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

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

1
  • 3
    lo siento, ¿qué hay en esto? archivo de imagen trazado?f= plt.savefig('data.png')
    Morse
    4/04/18 a las 13:48
14

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

plt.ioff()

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

Si desea habilitarlo nuevamente, use:

plt.ion()

14

Puedes hacer:

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

y recuerde dejar que savefig finalice antes de cerrar el gráfico de la GUI. De esta forma puedes ver la imagen de antemano.

Alternativamente, puede verlo con plt.show() Luego cierre la GUI y ejecute el script nuevamente, pero esta vez reemplace plt.show()con plt.savefig().

Alternativamente, puede usar

fig, ax = plt.figure(nrows=1, ncols=1)
plt.plot(...)
plt.show()
fig.savefig('out.pdf')
1
  • 2
    obtuvo un argumento de palabra clave inesperado 'retención' 6 de diciembre de 2017 a las 1:36
13

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

Una cosa debe tener en cuenta: si lo usa plt.showy debe hacerlo 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í

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 además de guardarla, utilice:

%matplotlib inline

después import matplotlib

9

Al usarlo matplotlib.pyplot, primero debe guardar su gráfico y luego cerrarlo 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
7
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.

0
6

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

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

1
  • 1
    Esa es una buena idea, solo necesita tomar nota del impacto en si la imagen se deja incrustada en el cuaderno. 29/12/18 a las 17:28
3

Solo una nota adicional porque todavía no puedo comentar las publicaciones.

Si está utilizando plt.savefig('myfig')o algo similar, asegúrese de agregar una plt.clf()después de que se guarde la imagen. Esto se debe a que savefig no cierra el gráfico y si agrega al gráfico después sin un plt.clf(), lo agregará al gráfico anterior.

Es posible que no note si sus tramas son similares, ya que se trazarán sobre la trama anterior, pero si está en un bucle guardando sus figuras, la trama se volverá masiva lentamente y hará que su guión sea muy lento.

2

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 se pone a trabajar con un CV abierto, o si ha importado un CV abierto, puede optar por:

import cv2

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

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

2

bueno, recomiendo usar envoltorios para renderizar o controlar el trazado. los ejemplos pueden ser mpltex ( https://github.com/liuyxpp/mpltex ) o prettyplotlib ( https://github.com/olgabot/prettyplotlib ).

import mpltex

@mpltex.acs_decorator
def myplot():
  plt.figure()
  plt.plot(x,y,'b-',lable='xxx')
  plt.tight_layout(pad=0.5)
  plt.savefig('xxxx')  # the figure format was controlled by the decorator, it can be either eps, or pdf or png....
  plt.close()

Básicamente, utilizo mucho este decorador para publicar artículos académicos en varias revistas de la American Chemical Society, American Physics Society, Opticcal Society American, Elsivier, etc.

Se puede encontrar un ejemplo en la siguiente imagen ( https://github.com/MarkMa1990/gradientDescent ): un ejemplo de descenso de gradiente

0

Puedes guardar tu imagen con cualquier extensión (png, jpg, etc.) Y con la resolución que desees. Aquí tienes 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:)

0

Puedes hacerlo así:

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

Nada funcionaba para mí. El problema es que la imagen guardada era muy pequeña y no pude encontrar cómo diablos hacerla más grande.

Esto parece hacerlo más grande, pero aún no a pantalla completa.

https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.set_size_inches

fig.set_size_inches ((ancho, alto))

Espero que ayude a alguien.