열린 숫자가 너무 많다는 경고


166

로 많은 그림을 만드는 스크립트에서 RuntimeWarning : 20 개 이상의 그림이 열렸다fix, ax = plt.subplots(...) 는 경고가 표시 됩니다. pyplot 인터페이스 ( matplotlib.pyplot.figure) 를 통해 생성 된 그림 은 명시 적으로 닫힐 때까지 유지되며 너무 많은 메모리를 소비 할 수 있습니다.

그러나으로 그림을 저장 한 후으로 삭제 하기 때문에이 경고가 표시되는 이유를 이해할 수 없습니다 . 내 코드에는 아무런 문제가 없지만 한 번에 두 개 이상의 그림이 열려 있습니다. 그래도 열린 숫자가 너무 많다는 경고가 표시됩니다. 이것이 무엇을 의미합니까 / 경고를 피하는 방법은 무엇입니까?fig.savefig(...)fig.clear(); del fig


9
이 작업을 많이하고 대화 형으로 표시하지 않으면 plt완전히 무시하는 것이 좋습니다 . 예 : stackoverflow.com/a/16337909/325565 (내 답변 중 하나를 연결하지는 않지만 가장 빨리 찾을 수있는 답변입니다 ...)
Joe Kington

1
@JoeKington 감사합니다. 이것이 더 나은 솔루션입니다
hihell

Joe Kington의 답변이 기본 답변 목록에 있어야합니다. 그것은 작동하고 또한 Don Kirby가 언급 한 프로그램 속도를 늦춘 plt.close ()의 문제를 해결합니다.
NatalieL

답변:


199

사용 .clf또는 .cla당신의 그림 개체에 대신 창조의 새로운 모습을. 에서 @DavidZwicker

다음 pyplot과 같이 가져온 것으로 가정

import matplotlib.pyplot as plt

plt.cla()axis , 즉 현재 그림에서 현재 활성 축을 지 웁니다 . 다른 축은 그대로 둡니다.

plt.clf()모든 축으로 현재 그림 전체를 지우지 만 창을 열어두고 다른 플롯에 재사용 할 수 있습니다.

plt.close()달리 지정하지 않으면 현재 창이 될 window를 닫습니다 . plt.close('all')열린 숫자를 모두 닫습니다.

del fig작동하지 않는 이유 는 pyplot상태 머신이 그림에 대한 참조를 유지하기 때문입니다 ( '현재 그림'이 무엇인지 알아야 할 때와 마찬가지로). 즉 , 그림에 대한 참조를 삭제하더라도 라이브 참조가 하나 이상 있으므로 가비지 수집되지 않습니다.

@JoeKington 은이 답변에 대한 집단적 지혜에 대해 설문 조사를하고 있기 때문에 @JoeKington plt.close(fig)은 pylab 상태 머신 ( plt._pylab_helpers.Gcf ) 에서 특정 그림 인스턴스를 제거하고 가비지 수집 될 수 있는 의견을 언급했습니다 .


1
hh 이 clf에 대한 figure하지만, 클래스 close. del fig실제로 그림을 닫고 삭제 하지 않는 이유는 무엇 입니까?
andreas-h

2
@ andreas-h 내 추측 : 자체 처리기가있는 창 관리자와 같은 복잡한 경우 범위를 벗어난 것보다 더 많은 정리가 필요할 수 있습니다. close그림 개체에서 작동하지 않는 당신의 권리 plt.close()대신, 처럼 호출하십시오 fig.clf().
걸려

5
@ andreas-h-기본적으로 del fig작동하지 않는 이유 는 __del__메소드 를 제공하면 (기본적으로 호출하는 plt.close(fig))이 특정 경우 순환 참조를 발생시키고 메소드를 fig갖는 것은 __del__다른 것들이 가비지 수집되지 않도록하기 때문입니다 . (또는 어쨌든 내 모호한 기억입니다.) 어쨌든, 그것은 약간 성가 시지만, plt.close(fig)대신에 전화해야합니다 del fig. 참고로, matplotlib는이를 위해 컨텍스트 관리자를 실제로 사용할 수 있습니다.
Joe Kington

6
@Hooked-좀 더 명확하게하기 위해 plt.close(fig)pylab 상태 머신 ( plt._pylab_helpers.Gcf) 에서 특정 그림 인스턴스를 제거하고 가비지 수집 될 수 있다고 언급하도록 질문을 편집 할 수 있습니다 .
Joe Kington

2
@JoeKington plt은 약간 엉망이며 그것을 다시 수행하는 방법에 대한 생각이 있습니다. 컨텍스트 매니저는 .... 참조 흥미로운 github.com/matplotlib/matplotlib/pull/2736 , github.com/matplotlib/matplotlib/pull/2624
tacaswell

32

Hooked 's answer 에 대해 좀 더 자세히 설명 하겠습니다 . 내가 그 대답을 처음 읽었을 때, 나는 clf() 새 인물을 만드는 대신 전화하라는 지시를 놓쳤다 . clf()당신이 가서 다른 인물을 만들면 그 자체로는 도움이되지 않습니다.

다음은 경고를 일으키는 간단한 예입니다.

from matplotlib import pyplot as plt, patches
import os


def main():
    path = 'figures'
    for i in range(21):
        _fig, ax = plt.subplots()
        x = range(3*i)
        y = [n*n for n in x]
        ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10))
        plt.step(x, y, linewidth=2, where='mid')
        figname = 'fig_{}.png'.format(i)
        dest = os.path.join(path, figname)
        plt.savefig(dest)  # write image to file
        plt.clf()
    print('Done.')

main()

경고를 피하려면 subplots()루프 외부로 호출을 당겨야합니다 . 사각형을 계속 보려면로 전환 clf()해야 cla()합니다. 축 자체를 제거하지 않고 축을 지 웁니다.

from matplotlib import pyplot as plt, patches
import os


def main():
    path = 'figures'
    _fig, ax = plt.subplots()
    for i in range(21):
        x = range(3*i)
        y = [n*n for n in x]
        ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10))
        plt.step(x, y, linewidth=2, where='mid')
        figname = 'fig_{}.png'.format(i)
        dest = os.path.join(path, figname)
        plt.savefig(dest)  # write image to file
        plt.cla()
    print('Done.')

main()

배치로 플롯을 생성하는 경우 cla()와를 모두 사용해야 할 수도 있습니다 close(). 배치에 불만을 제기하지 않고 20 개 이상의 플롯을 가질 수있는 문제가 발생했지만 20 배치 후에 불만을 제기했습니다. cla()각 음모 close()후 와 배치 마다 사용하여 문제를 해결했습니다 .

from matplotlib import pyplot as plt, patches
import os


def main():
    for i in range(21):
        print('Batch {}'.format(i))
        make_plots('figures')
    print('Done.')


def make_plots(path):
    fig, ax = plt.subplots()
    for i in range(21):
        x = range(3 * i)
        y = [n * n for n in x]
        ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10))
        plt.step(x, y, linewidth=2, where='mid')
        figname = 'fig_{}.png'.format(i)
        dest = os.path.join(path, figname)
        plt.savefig(dest)  # write image to file
        plt.cla()
    plt.close(fig)


main()

나는 배치 내에서 그림을 재사용 할 가치가 있는지 확인하기 위해 성능을 측정 했으며이 작은 샘플 프로그램은 close()모든 플롯 후에 방금 호출했을 때 41 초에서 49 초 (20 % 느려짐)로 느려졌습니다 .


이것은 좋은 대답입니다. 허용되는 답변은 실제로 실제 문제인 메모리 소비를 해결하지 못합니다.
Kyle

24

의도적으로 많은 플롯을 메모리에 유지하려고하지만 경고하지 않으려면 그림을 생성하기 전에 옵션을 업데이트 할 수 있습니다.

import matplotlib.pyplot as plt
plt.rcParams.update({'figure.max_open_warning': 0})

이렇게하면 메모리 관리 방식에 대한 변경없이 경고가 표시되지 않습니다.


Jupyter 환경에서 플롯을 표시하는 셀이 존재하는 한 메모리 할당이 지속됩니까?
matanster

2
@matanster, 나는 그것이 자신의 질문으로 게시 할 것입니다. 나는 대답하기 시작했고, 정직하게 대답 할 jupyter의 커널 관리에 대해 정말로 모른다는 것을 깨달았습니다.
mightypile

@matanster 커널에 사용자가 명시 적으로 종료 할 때까지 할당 된 모든 변수와 메모리가 존재합니다. 셀에 연결되어 있지 않습니다. 최신 Jupyter Hub에서는 시스템이 커널을 종료 할 수 있습니다 (구성 가능).
greatvovan

0

다음 스 니펫은 문제를 해결했습니다.


class FigureWrapper(object):
    '''Frees underlying figure when it goes out of scope. 
    '''

    def __init__(self, figure):
        self._figure = figure

    def __del__(self):
        plt.close(self._figure)
        print("Figure removed")


# .....
    f, ax = plt.subplots(1, figsize=(20, 20))
    _wrapped_figure = FigureWrapper(f)

    ax.plot(...
    plt.savefig(...
# .....

_wrapped_figure범위를 벗어나 런타임은 우리의 호출 __del__()과 방법 plt.close()내부. _wrapped_figure생성자 후에 예외가 발생하더라도 발생합니다 .


0

일시적으로 경고를 표시하지 않으려는 경우에도 유용합니다.

    import matplotlib.pyplot as plt
       
    with plt.rc_context(rc={'figure.max_open_warning': 0}):
        lots_of_plots()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.