W skrypcie, w którym tworzę wiele figurek fix, ax = plt.subplots(...)
, otrzymuję ostrzeżenie RuntimeWarning: Otwarto ponad 20 figurek. Figury utworzone za pomocą interfejsu pyplot ( matplotlib.pyplot.figure
) są przechowywane do momentu jawnego zamknięcia i mogą zajmować zbyt dużo pamięci.
Nie rozumiem jednak, dlaczego otrzymuję to ostrzeżenie, bo po zapisaniu figury za pomocą fig.savefig(...)
, kasuję ją za pomocą fig.clear(); del fig
. W żadnym momencie w moim kodzie nie mam otwartych więcej niż jednej cyfry naraz. Mimo to otrzymuję ostrzeżenie o zbyt wielu otwartych liczbach. Co to oznacza / jak mogę uniknąć ostrzeżenia?
python
python-3.x
matplotlib
andreas-h
źródło
źródło
plt
całkowicie pominiesz. Np. Stackoverflow.com/a/16337909/325565 (Nie chcę podłączać jednej z moich odpowiedzi, ale to ta, którą znalazłem najszybciej ...)Odpowiedzi:
Użyj
.clf
lub.cla
na swoim obiekcie figury zamiast tworzyć nową figurę. Od @DavidZwickerZakładając, że zaimportowałeś
pyplot
jakoplt.cla()
czyści oś , tj. aktualnie aktywną oś na bieżącej figurze. Pozostawia pozostałe osie nietknięte.plt.clf()
czyści całą bieżącą figurę ze wszystkimi jej osiami, ale pozostawia otwarte okno, aby można było je ponownie wykorzystać na innych wykresach.plt.close()
zamyka okno , które będzie oknem bieżącym, jeśli nie określono inaczej.plt.close('all')
zamknie wszystkie otwarte figury.Przyczyną,
del fig
która nie działa, jest to, żepyplot
maszyna stanu zachowuje odniesienie do figury wokół (tak jak musi, jeśli chce wiedzieć, jaka jest „bieżąca liczba”). Oznacza to, że nawet jeśli usuniesz swój odnośnik do figury, istnieje co najmniej jeden odnośnik na żywo, więc nigdy nie zostanie on usunięty .Ponieważ sonduję tutaj zbiorową mądrość dla tej odpowiedzi, @JoeKington wspomina w komentarzach,
plt.close(fig)
które usuwają konkretną instancję figury z maszyny stanu pylab ( plt._pylab_helpers.Gcf ) i pozwalają na zbieranie śmieci.źródło
clf
nafigure
zajęcia, ale nieclose
. Dlaczegodel fig
właściwie nie zamyka i nie usuwa figury?close
które nie będzie działać z obiektem figury, nazwij to jakplt.close()
zamiastfig.clf()
.del fig
który nie działa, jest to, że nadanie mu__del__
metody (która w zasadzieplt.close(fig)
wywołałaby) skończyłoby się, powodując cykliczne odwołania w tym konkretnym przypadku, afig
posiadanie__del__
metody spowoduje, że inne rzeczy nie będą zbierane jako śmieci . (W każdym razie to moje niejasne wspomnienie.) W każdym razie jest to trochę denerwujące, aleplt.close(fig)
zamiast tego powinieneś zadzwonićdel fig
. Na marginesie, matplotlib może naprawdę użyć do tego menedżera kontekstu ...plt.close(fig)
usunie określoną instancję figury z maszyny stanu pylab (plt._pylab_helpers.Gcf
) i pozwoli na usunięcie jej jako śmieci.plt
jest trochę w bałaganie i zastanawiają się, jak zrobić to ponownie. Menedżer kontekstów jest intrygujący ... Zobacz github.com/matplotlib/matplotlib/pull/2736 , github.com/matplotlib/matplotlib/pull/2624Oto nieco więcej szczegółów, aby rozwinąć odpowiedź Hookeda . Kiedy po raz pierwszy przeczytałem tę odpowiedź, przegapiłem instrukcję, aby zadzwonić
clf()
zamiast tworzyć nową figurę .clf()
samo w sobie nie pomoże, jeśli potem pójdziesz i stworzysz kolejną figurę.Oto trywialny przykład, który powoduje ostrzeżenie:
Aby uniknąć ostrzeżenia, muszę wyciągnąć połączenie
subplots()
poza pętlę. Aby nadal widzieć prostokąty, muszę przełączyć sięclf()
nacla()
. To czyści oś bez usuwania samej osi.Jeśli generujesz wykresy partiami, może być konieczne użycie obu
cla()
iclose()
. Napotkałem problem polegający na tym, że partia mogła mieć więcej niż 20 działek bez narzekania, ale po 20 partiach narzekała. Naprawiłem to, używająccla()
po każdym wykresie iclose()
po każdej partii.Zmierzyłem wydajność, aby sprawdzić, czy warto ponownie użyć liczby w partii, a ten mały przykładowy program zwolnił z 41 s do 49 s (20% wolniej), gdy dzwoniłem
close()
po każdym wykresie.źródło
Jeśli zamierzasz świadomie przechowywać wiele wykresów w pamięci, ale nie chcesz być o tym ostrzegany, możesz zaktualizować swoje opcje przed wygenerowaniem liczb.
Zapobiegnie to wysyłaniu ostrzeżenia bez zmiany sposobu zarządzania pamięcią.
źródło
Poniższy fragment kodu rozwiązał problem za mnie:
Kiedy
_wrapped_figure
wychodzi poza zakres, środowisko wykonawcze wywołuje naszą__del__()
metodę zplt.close()
inside. Dzieje się tak, nawet jeśli wyjątek jest uruchamiany po_wrapped_figure
konstruktorze.źródło
Jest to również przydatne, jeśli chcesz tylko tymczasowo wyłączyć ostrzeżenie:
źródło