Zapisz działkę do pliku obrazu zamiast wyświetlać go za pomocą Matplotlib

1150

Piszę szybki i brudny skrypt do generowania fabuł w locie. Korzystam z poniższego kodu (z dokumentacji Matplotlib ) jako punktu wyjścia:

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

Nie chcę wyświetlać wykresu w GUI, zamiast tego chcę zapisać wykres do pliku (powiedzmy foo.png), aby na przykład można go było użyć w skryptach wsadowych. Jak mogę to zrobić?

Homunculus Reticulli
źródło
84
Wygląda na to, że znalazłem odpowiedź: jego pylab.savefig ('foo.png')
Homunculus Reticulli
2
Link może link do gdzieś na matplotlib.org?
A.Wan
40
Również jeśli nie używa się pylab, obiekt figury również ma savefigmetodę. Więc można nazwać fig = plt.figure()potem fig.savefig(...).
A.Wan
27
Wiele odpowiedzi na dole strony wspomina, plt.close(fig)co jest szczególnie ważne w dużych pętlach. W przeciwnym razie liczby pozostaną otwarte i czekają w pamięci, a wszystkie otwarte liczby zostaną wyświetlone po wykonaniuplt.show()
timctran
Uwaga: preferowany jest matplotlib.pyplot: stackoverflow.com/questions/11469336/…
ErichBSchulz 11.08.19

Odpowiedzi:

1438

Chociaż pytanie zostało udzielone, chciałbym dodać kilka użytecznych wskazówek podczas korzystania z matplotlib.pyplot.savefig . Format pliku można określić przez rozszerzenie:

from matplotlib import pyplot as plt

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

Daje odpowiednio zrasteryzowane lub wektoryzowane wyjście, które mogą być przydatne. Ponadto zauważysz, że pylabpozostawia hojny, często niepożądane, białe znaki wokół obrazu. Usuń za pomocą:

savefig('foo.png', bbox_inches='tight')
Haczykowaty
źródło
9
Czy można zmienić wymiary obrazu wynikowego?
Llamageddon
43
@Asmageddon W plt.savefigmożna zmienić dpi, patrz link w odpowiedzi. Te wymiary mogą być sterowane podczas tworzenia postać, patrz figsizena matplotlib.org/api/figure_api.html#matplotlib.figure.Figure
Hooked
5
@MoTSCHIGGE możesz zadzwonić, plt.ioff()co powinno wyłączyć interaktywność matplotlib.pyplotpoleceń.
rubenvb,
5
@STMohammed foo.png to ścieżka. Możesz na przykład umieścić go w takim katalogu savefig("mydir/foo.png").
Hooked
3
bbox_inches = „ciasno” działa jak urok. Zrobiłeś mój dzień
Catbuilts
205

Jak powiedzieli inni, plt.savefig()lub fig1.savefig()rzeczywiście jest to sposób na zapisanie obrazu.

Przekonałem się jednak, że w niektórych przypadkach liczba jest zawsze wyświetlana . (np. z Spyderem posiadającym plt.ion(): tryb interaktywny = Wł.) Obejdę ten problem, wymuszając zamknięcie okna figury w mojej gigantycznej pętli za pomocą plt.close(figure_object)(patrz dokumentacja ), więc nie mam miliona otwartych liczb podczas pętli:

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

W razie potrzeby powinieneś być w stanie ponownie otworzyć tę postać fig.show()(nie testowałem siebie).

Demis
źródło
9
Można również ustawić plt.ioff() # turn of interactive plotting mode, ale może to uniemożliwić zachowanie, którego należy użyć, jeśli kod zakończy działanie z błędem.
Demis
2
Ten sam problem zobaczysz w notesach Jupyter. plt.close(fig)rozwiązany
intsco
163

Rozwiązaniem jest:

pylab.savefig('foo.png')
Łukasz Czerwiński
źródło
89

Właśnie znalazłem ten link w dokumentacji MatPlotLib dotyczący dokładnie tego problemu: http://matplotlib.org/faq/howto_faq.html#generate-images-without-having-a-window-appear

Mówią, że najłatwiejszym sposobem, aby zapobiec wyskakiwaniu figury, jest użycie nieinteraktywnego zaplecza (np. Agg), poprzez matplotib.use(<backend>)np .:

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

Nadal osobiście wolę używać plt.close( fig ), ponieważ odtąd masz opcję ukrywania niektórych liczb (podczas pętli), ale nadal wyświetlasz liczby do przetwarzania danych po pętli. Jest to prawdopodobnie wolniejsze niż wybór nieinteraktywnego zaplecza - byłoby interesujące, gdyby ktoś to przetestował.

AKTUALIZACJA : w przypadku Spyder zwykle nie można ustawić backendu w ten sposób (ponieważ Spyder zwykle ładuje matplotlib wcześnie, uniemożliwiając korzystanie matplotlib.use()).

Zamiast tego użyj plt.switch_backend('Agg')lub Wyłącz „ włącz obsługę ” w prefiksach Spyder i uruchom matplotlib.use('Agg')polecenie samodzielnie.

Z tych dwóch wskazówek: raz , dwa

Demis
źródło
1
Działa to naprawdę dobrze w sytuacjach, gdy nie masz ustawionego wyświetlacza. Użycie innego backendu .plot()spowoduje błąd, jeśli os.environ['DISPLAY']nie zostanie poprawnie ustawiony.
ekonomia
1
dzięki. działa to i jest bardzo pomocne w przypadku serwerów produkcyjnych, na których nie ma połączenia z Internetem i potrzebuje administratora systemu, aby zainstalować jakiekolwiek pakiety.
Leon
Podoba mi się samouczek witryny matplotlib dotyczący opisu / definicji „zaplecza”: matplotlib.org/tutorials/introductory/…
Tanner Strunk
47

Jeśli nie podoba Ci się koncepcja „aktualnej” liczby, wykonaj:

import matplotlib.image as mpimg

img = mpimg.imread("src.png")
mpimg.imsave("out.png", img)
wonder.mice
źródło
2
Czy to nie wystarczy skopiować src.pngdo out.png?
gerrit
To tylko przykład, który pokazuje, że jeśli masz obiekt image ( img), możesz zapisać go do pliku za pomocą .imsave()metody.
wonder.mice
4
@ wonder.mice pomógłby pokazać, jak utworzyć obraz bez użycia bieżącej figury.
scry
@ wonder.mice Dzięki za ten przykład, pierwszy pokazał mi, jak zapisać obiekt obrazu w formacie .png.
Arthur Dent
@scry Nie zawsze trzeba tworzyć obraz, czasem wypróbowuje się jakiś kod i chce się uzyskać efekt wizualny, w takich przypadkach jest to przydatne.
Schütze
29

Pozostałe odpowiedzi są poprawne. Czasami jednak okazuje się, że chcę później otworzyć obiekt figury . Na przykład mógłbym chcieć zmienić rozmiary etykiet, dodać siatkę lub wykonać inne przetwarzanie. W idealnym świecie po prostu uruchomiłbym ponownie kod generujący fabułę i dostosowałem ustawienia. Niestety świat nie jest idealny. Dlatego oprócz zapisywania w formacie PDF lub PNG dodaję:

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

W ten sposób mogę później załadować obiekt figury i dowolnie modyfikować ustawienia.

Zapisuję również stos z kodem źródłowym i locals()słownikiem dla każdej funkcji / metody na stosie, dzięki czemu mogę później dokładnie powiedzieć, co wygenerowało liczbę.

Uwaga: bądź ostrożny, ponieważ czasami ta metoda generuje ogromne pliki.

gerrit
źródło
czy nie byłoby łatwiej robić prac programistycznych w notatniku jupyter, mając wstawione liczby? W ten sposób możesz dokładnie śledzić historię, a nawet uruchomić ją ponownie.
Ciprian Tomoiagă
3
@CiprianTomoiaga Nigdy nie generuję wykresów produkcyjnych z interaktywnej powłoki Pythona (Jupyter lub w inny sposób). Spisuję wszystko ze skryptów.
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
źródło
28

Po użyciu plot () i innych funkcji do stworzenia pożądanej zawartości, możesz użyć takiej klauzuli, aby wybrać między drukowaniem na ekranie a plikiem:

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.
źródło
Niektórzy mówią, że fig = plt.figure(figuresize=4, 5)może byćfig = plt.figure(figsize=(4, 5)) #figure sizes in inches
użytkownik
24

Użyłem następujących:

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

Uważam, że bardzo ważne jest użycie plt.show po zapisaniu figury, w przeciwnym razie to nie zadziała. postać wyeksportowana w png

Cristian Muñoz
źródło
2
przepraszam, co w tym jest? wydrukowany plik obrazu? f= plt.savefig('data.png')
Morse
14

Możesz albo:

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

i pamiętaj, aby savefig skończył się przed zamknięciem wykresu GUI. W ten sposób możesz wcześniej zobaczyć obraz.

Alternatywnie, można spojrzeć na to z plt.show() czym zamknij GUI i ponownie uruchomić skrypt, ale tym razem zastąpić plt.show()z plt.savefig().

Alternatywnie możesz użyć

fig, ax = plt.figure(nrows=1, ncols=1)
plt.plot(...)
plt.show()
fig.savefig('out.pdf')
Orzechówka
źródło
2
otrzymałem nieoczekiwany argument słowa kluczowego „przytrzymaj”
amitdatta
13

Jeśli, podobnie jak ja, używasz Spyder IDE, musisz wyłączyć tryb interaktywny za pomocą:

plt.ioff()

(to polecenie jest uruchamiane automatycznie wraz ze startem naukowym)

Jeśli chcesz go ponownie włączyć, użyj:

plt.ion()

Covich
źródło
12

Rozwiązanie :

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

Jeśli chcesz wyświetlić obraz, a także zapisać obraz, użyj:

%matplotlib inline

po import matplotlib

Durgesh satam
źródło
9

Zgodnie z pytaniem Matplotlib (pyplot) savefig wyświetla pusty obraz .

Należy zwrócić uwagę na jedną rzecz: jeśli użyjesz plt.showi powinno być później plt.savefig, lub otrzymasz pusty obraz.

Szczegółowy przykład:

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

wprowadź opis zdjęcia tutaj

Jayhello
źródło
6
import matplotlib.pyplot as plt
plt.savefig("image.png")

W Jupyter Notebook musisz usunąć plt.show()i dodać plt.savefig()wraz z resztą kodu plt w jednej komórce. Obraz nadal będzie wyświetlany w twoim notatniku.

Punnerud
źródło
1
„remove plt.show ()” .. to uratowało mi dzień…
Guru
4

Biorąc pod uwagę, że dziś (nie było dostępne, kiedy zadawano to pytanie) wiele osób używa Jupyter Notebook jako konsoli Pythona, istnieje niezwykle łatwy sposób na zapisanie wykresów, ponieważ .pngwystarczy wywołać matplotlibpylabklasę z Jupyter Notebook, narysować rysunek” 'komórki jupyter, a następnie przeciągnij tę figurę / obraz do lokalnego katalogu. Nie zapomnij %matplotlib inlinew pierwszej linii!

Hamidreza
źródło
1
to dobry pomysł, wystarczy wziąć pod uwagę wpływ na rozmiar pliku, jeśli obraz pozostanie osadzony w notatniku.
prusswan
3

Oprócz powyższych, dodałem __file__nazwę, aby zdjęcie i plik Python otrzymywały te same nazwy. Dodałem również kilka argumentów, aby wyglądało to lepiej:

# 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
źródło
2

Podczas używania matplotlib.pyplotmusisz najpierw zapisać działkę, a następnie zamknąć ją za pomocą tych 2 wierszy:

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
Cichy lód
źródło
1

Jak sugerowano wcześniej, możesz użyć:

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

Do zapisywania dowolnego wyświetlanego obrazu IPhython. Lub z innej nuty (patrząc pod innym kątem), jeśli kiedykolwiek zaczniesz pracować z otwartym cv lub jeśli masz otwarte cv zaimportowane, możesz wybrać:

import cv2

cv2.imwrite („myfig.png”, obraz)

Ale tak jest na wszelki wypadek, jeśli chcesz pracować z Open CV. W przeciwnym razie wystarczy plt.savefig ().

Aditya Bhattacharya
źródło
0

Możesz zapisać swój obraz z dowolnym rozszerzeniem (png, jpg itp.) I z odpowiednią rozdzielczością. Oto funkcja zapisywania twojej figury.

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” to nazwa, pod którą chcesz zapisać swoją figurę. Mam nadzieję, że to pomoże:)

Rudresh Dixit
źródło
0

Możesz to zrobić w następujący sposób:

def plotAFig():
  plt.figure()
  plt.plot(x,y,'b-')
  plt.savefig("figurename.png")
  plt.close()
Mark90
źródło