Enregistrer le tracé dans un fichier image au lieu de l'afficher à l'aide de Matplotlib

1150

J'écris un script rapide et sale pour générer des tracés à la volée. J'utilise le code ci-dessous (de la documentation Matplotlib ) comme point de départ:

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

Je ne veux pas afficher le tracé sur une interface graphique, au lieu de cela, je veux enregistrer le tracé dans un fichier (disons foo.png), afin que, par exemple, il puisse être utilisé dans des scripts de traitement par lots. Comment je fais ça?

Homunculus Reticulli
la source
85
On dirait que j'ai trouvé la réponse: son pylab.savefig ('foo.png')
Homunculus Reticulli
2
Le lien devrait peut-être renvoyer vers quelque part dans matplotlib.org?
A.Wan
40
De plus, si vous n'utilisez pas pylab, l'objet figure a également une savefigméthode. Vous pouvez donc appeler fig = plt.figure()alors fig.savefig(...).
A.Wan
27
Beaucoup de réponses en bas de la page mentionnent plt.close(fig)ce qui est particulièrement important dans les grandes boucles. Sinon, les chiffres restent ouverts et attendent en mémoire et tous les chiffres ouverts seront affichés lors de l'exécutionplt.show()
timctran
nb: matplotlib.pyplot est préféré: stackoverflow.com/questions/11469336/…
ErichBSchulz

Réponses:

1441

Bien que la question ait été répondue, je voudrais ajouter quelques conseils utiles lors de l'utilisation de matplotlib.pyplot.savefig . Le format de fichier peut être spécifié par l'extension:

from matplotlib import pyplot as plt

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

Donnera respectivement une sortie tramée ou vectorisée, les deux pouvant être utiles. De plus, vous constaterez que cela pylablaisse un espace généreux, souvent indésirable, autour de l'image. Retirez-le avec:

savefig('foo.png', bbox_inches='tight')
Accroché
la source
9
Est-il possible de changer les dimensions de l'image résultante?
Llamageddon
43
@Asmageddon Dans plt.savefigvous pouvez changer le dpi, voir le lien dans la réponse. Les dimensions peuvent être contrôlées lors de la création de la figure, voir figsizedans matplotlib.org/api/figure_api.html#matplotlib.figure.Figure
Hooked
5
@MoTSCHIGGE que vous pouvez appeler, plt.ioff()ce qui devrait désactiver l'interactivité dans les matplotlib.pyplotcommandes.
rubenvb
5
@STMohammed foo.png est le chemin. Vous pouvez, par exemple, le mettre dans un répertoire comme celui-ci savefig("mydir/foo.png").
accroché
3
bbox_inches = 'tight' fonctionne comme un charme. Tu as fait ma journée
Catbuilts
205

Comme d'autres l'ont dit, plt.savefig()ou fig1.savefig()est en effet le moyen de sauvegarder une image.

Cependant, j'ai trouvé que dans certains cas, le chiffre est toujours affiché . (par exemple avec Spyder ayant plt.ion(): mode interactif = On.) Je contourne cela en forçant la fermeture de la fenêtre de figure dans ma boucle géante avec plt.close(figure_object)(voir la documentation ), donc je n'ai pas un million de chiffres ouverts pendant la boucle:

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

Vous devriez pouvoir rouvrir la figure plus tard si nécessaire avec fig.show()(je ne me suis pas testé).

Demis
la source
9
Vous pouvez également définir plt.ioff() # turn of interactive plotting mode, mais cela peut désactiver le comportement que vous souhaitez utiliser si votre code se termine avec une erreur.
Demis
2
Vous verrez le même problème dans les cahiers Jupyter. plt.close(fig)résolu
intsco
163

La solution est:

pylab.savefig('foo.png')
Lukasz Czerwinski
la source
89

Je viens de trouver ce lien sur la documentation MatPlotLib traitant exactement ce problème: http://matplotlib.org/faq/howto_faq.html#generate-images-without-having-a-window-appear

Ils disent que le moyen le plus simple d'empêcher la figure d'apparaître est d'utiliser un backend non interactif (par exemple Agg), via matplotib.use(<backend>), par exemple:

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

Personnellement, je préfère toujours utiliser plt.close( fig ), car vous avez la possibilité de masquer certains chiffres (pendant une boucle), mais d'afficher toujours des chiffres pour le traitement des données après la boucle. Il est probablement plus lent que de choisir un backend non interactif - serait intéressant si quelqu'un le testait.

MISE À JOUR : pour Spyder, vous ne pouvez généralement pas définir le backend de cette manière (parce que Spyder charge généralement matplotlib tôt, vous empêchant d'utiliser matplotlib.use()).

À la place, utilisez plt.switch_backend('Agg')ou désactivez « activer le support » dans les préférences de Spyder et exécutez la matplotlib.use('Agg')commande vous-même.

De ces deux indices: un , deux

Demis
la source
1
Cela fonctionne très bien pour les situations où vous n'avez pas d'affichage défini. L'utilisation d'un autre backend avec .plot()générera une erreur s'il os.environ['DISPLAY']n'est pas défini correctement.
économie
1
Merci. cela fonctionne et est très utile pour les serveurs de production où il n'y a pas de connexion Internet et qui ont besoin d'un administrateur système pour installer les packages.
Leon
J'aime le tutoriel du site matplotlib pour la description / définition des "backends": matplotlib.org/tutorials/introductory/…
Tanner Strunk
47

Si vous n'aimez pas le concept de la figure "actuelle", faites:

import matplotlib.image as mpimg

img = mpimg.imread("src.png")
mpimg.imsave("out.png", img)
wonder.mice
la source
2
N'est-ce pas juste copier src.png à out.png?
gerrit
C'est juste un exemple, qui montre que si vous avez un objet image ( img), vous pouvez l'enregistrer dans un fichier avec la .imsave()méthode.
wonder.mice
4
@ wonder.mice aiderait à montrer comment créer une image sans utiliser la figure actuelle.
scry
@ wonder.mice Merci pour cet exemple, c'est le premier qui m'a montré comment enregistrer un objet image en .png.
Arthur Dent
@scry Vous n'avez pas toujours besoin de créer une image, parfois vous essayez du code et souhaitez une sortie visuelle, c'est pratique dans de telles occasions.
Schütze
29

Les autres réponses sont correctes. Cependant, je trouve parfois que je veux ouvrir l' objet figure plus tard. Par exemple, je pourrais vouloir changer la taille des étiquettes, ajouter une grille ou effectuer un autre traitement. Dans un monde parfait, je relancerais simplement le code générant l'intrigue et j'adapterais les paramètres. Hélas, le monde n'est pas parfait. Par conséquent, en plus d'enregistrer au format PDF ou PNG, j'ajoute:

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

Comme ça, je peux plus tard charger l'objet figure et manipuler les paramètres à ma guise.

J'écris également la pile avec le code source et le locals()dictionnaire pour chaque fonction / méthode de la pile, afin de pouvoir dire plus tard exactement ce qui a généré la figure.

NB: Attention, cette méthode génère parfois des fichiers volumineux.

gerrit
la source
ne serait-il pas plus facile de faire du développement dans un cahier jupyter, avec les chiffres en ligne? De cette façon, vous pouvez suivre exactement l'historique et même le réexécuter.
Ciprian Tomoiagă
3
@CiprianTomoiaga Je ne génère jamais de parcelles de production à partir d'un shell Python interactif (Jupyter ou autre). Je trace tout à partir de scripts.
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
la source
28

Après avoir utilisé plot () et d'autres fonctions pour créer le contenu que vous souhaitez, vous pouvez utiliser une clause comme celle-ci pour choisir entre le traçage à l'écran ou le fichier:

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.
la source
Certains disent que cela fig = plt.figure(figuresize=4, 5)pourrait êtrefig = plt.figure(figsize=(4, 5)) #figure sizes in inches
utilisateur
24

J'ai utilisé ce qui suit:

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

J'ai trouvé très important d'utiliser plt.show après avoir enregistré la figure, sinon cela ne fonctionnera pas. figure exportée en png

Cristian Muñoz
la source
2
désolé, qu'est-ce que c'est? fichier d'image tracé? f= plt.savefig('data.png')
Morse
14

Vous pouvez soit faire:

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

et n'oubliez pas de laisser savefig se terminer avant de fermer le tracé de l'interface graphique. De cette façon, vous pouvez voir l'image à l'avance.

Alternativement, vous pouvez le regarder avec plt.show() Puis fermez l'interface graphique et réexécutez le script, mais cette fois remplacez plt.show()par plt.savefig().

Vous pouvez également utiliser

fig, ax = plt.figure(nrows=1, ncols=1)
plt.plot(...)
plt.show()
fig.savefig('out.pdf')
casse Noisette
la source
2
a obtenu un argument de mot clé inattendu 'hold'
amitdatta
13

Si, comme moi, vous utilisez Spyder IDE, vous devez désactiver le mode interactif avec:

plt.ioff()

(cette commande est lancée automatiquement avec le démarrage scientifique)

Si vous souhaitez le réactiver, utilisez:

plt.ion()

Covich
la source
12

La solution :

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 vous souhaitez afficher l'image ainsi que sauvegarder l'image, utilisez:

%matplotlib inline

après import matplotlib

Durgesh satam
la source
9

Selon la question Matplotlib (pyplot) savefig affiche une image vierge .

Une chose doit noter: si vous utilisez plt.showet que cela devrait aprèsplt.savefig , ou vous donnerez une image vierge.

Un exemple détaillé:

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

entrez la description de l'image ici

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

Dans Jupyter Notebook, vous devez supprimer plt.show()et ajouter plt.savefig(), avec le reste du code plt dans une cellule. L'image apparaîtra toujours dans votre carnet.

Punnerud
la source
1
"remove plt.show ()" .. cela m'a sauvé la journée ...
Guru
4

Étant donné qu'aujourd'hui (n'était pas disponible lorsque cette question a été posée), de nombreuses personnes utilisent Jupyter Notebook comme console python, il existe un moyen extrêmement simple d'enregistrer les tracés car .png, il suffit d'appeler la classe matplotlib's à pylabpartir de Jupyter Notebook, de tracer la figure' en ligne 'jupyter cells, puis faites glisser cette figure / image vers un répertoire local. N'oubliez pas %matplotlib inlineen première ligne!

Hamidreza
la source
1
c'est une bonne idée, il suffit de prendre note de l'impact sur la taille du fichier si l'image est laissée intégrée dans le cahier ..
prusswan
3

En plus de ceux ci-dessus, j'ai ajouté __file__pour le nom afin que l'image et le fichier Python obtiennent les mêmes noms. J'ai également ajouté quelques arguments pour le rendre plus beau:

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

la source
2

Lors de l'utilisation matplotlib.pyplot, vous devez d'abord enregistrer votre tracé puis le fermer en utilisant ces 2 lignes:

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
Glace silencieuse
la source
1

Comme suggéré précédemment, vous pouvez utiliser:

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

Pour enregistrer l'image IPhython que vous affichez. Ou sur une note différente (en regardant sous un angle différent), si jamais vous travaillez avec un cv ouvert, ou si vous avez importé un cv ouvert, vous pouvez opter pour:

importer cv2

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

Mais c'est juste au cas où vous auriez besoin de travailler avec Open CV. Sinon, plt.savefig () devrait être suffisant.

Aditya Bhattacharya
la source
0

Vous pouvez enregistrer votre image avec n'importe quelle extension (png, jpg, etc.) et avec la résolution que vous souhaitez. Voici une fonction pour enregistrer votre silhouette.

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' est le nom sous lequel vous souhaitez enregistrer votre figure. J'espère que cela aide:)

Rudresh Dixit
la source
0

Vous pouvez le faire comme ceci:

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