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

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

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



답변

사용 .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 ) 에서 특정 그림 인스턴스를 제거하고 가비지 수집 될 수 있는 의견을 언급했습니다 .


답변

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 % 느려짐)로 느려졌습니다 .


답변

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

import matplotlib.pyplot as plt
plt.rcParams.update({'figure.max_open_warning': 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생성자 후에 예외가 발생하더라도 발생합니다 .


답변

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

    import matplotlib.pyplot as plt

    with plt.rc_context(rc={'figure.max_open_warning': 0}):
        lots_of_plots()


답변