HOWTO · Matplotlib

Matplotlib의 cla(), clf(), close() 함수 차이

Matplotlib의 cla(), clf(), close() 함수가 각각 현재 Axes, Figure, Figure 관리에 어떤 영향을 주는지 비교합니다. 서브플롯 하나의 내용만 지우거나 Figure 전체를 비우거나 Figure를 닫는 방법을 예제로 설명합니다.

이 페이지의 내용

어떤 객체에 작용할지를 기준으로 함수를 선택하세요. matplotlib.pyplot.cla()는 현재 Axes를 지우고, matplotlib.pyplot.clf()는 현재 Figure를 지우며, matplotlib.pyplot.close()는 Figure를 닫습니다. 이들은 메서드가 아니라 pyplot 함수이며, 각각 작용하는 범위가 다릅니다. 서브플롯 하나를 다시 그리려면 cla()를, Figure를 새 레이아웃으로 재사용하려면 clf()를, Figure 사용이 끝났다면 close()를 사용하세요.

한눈에 보는 차이

세 함수는 작용 범위의 계층을 이룹니다. cla()는 가장 작은 단위인 단일 Axes에 작용합니다. clf()는 그 Axes를 포함하는 Figure 전체에 작용합니다. close()는 한 단계 더 나아가 Figure를 pyplot에서 완전히 제거합니다.

함수 작용 대상 제거되는 것 남는 것
plt.cla() 현재 Axes 그려진 데이터, 레이블, 제목, 범례 및 기타 Axes 내용 Axes 자체, 레이아웃에서의 위치, 인접한 모든 Axes, Figure
plt.clf() 현재 Figure Figure 안의 모든 Axes와 그 내용 새 Axes를 받을 준비가 된 Figure 객체와 그 창
plt.close() pyplot이 관리하는 Figure pyplot에 대한 Figure 등록(대화형 백엔드에서는 그 창도) pyplot 안에 그 Figure에 대한 것은 아무것도 남지 않음; 인접한 Figure는 영향을 받지 않음

작용 범위가 가장 중요해지는 경우는 Figure에 여러 서브플롯이 들어 있을 때입니다. Axes를 지우면 그 Axes가 레이아웃에 남으므로 그 위치와 다른 서브플롯을 계속 사용할 수 있습니다. Figure를 지우면 그 안의 모든 Axes가 한 번에 제거되지만, Figure 자체는 새 Axes와 플롯을 위해 계속 사용할 수 있습니다. Figure를 닫으면 pyplot의 해당 Figure 관리가 종료되며, 세 함수 중 유일하게 Figure의 리소스를 해제합니다.

세 pyplot 함수는 모두 대상을 미리 선택하지 않는 한 현재 Axes 또는 Figure에 작용합니다. Axes 객체나 Figure 객체를 이미 가지고 있다면 객체 수준 연산인 ax.clear()와 fig.clear()를 사용해, 어떤 Axes나 Figure가 현재 대상인지에 의존하지 않고 대상을 명시할 수 있습니다. close()의 경우 plt.close(fig)처럼 Figure를 직접 전달할 수 있습니다.

matplotlib.pyplot.cla()

cla()는 현재 Axes의 그려진 데이터, 축 레이블, 제목, 범례 및 기타 내용을 지웁니다. Axes 자체는 원래 위치 그대로 Figure에 남으므로 서브플롯 격자는 레이아웃을 유지하고 인접한 각 서브플롯은 자신의 플롯을 유지합니다. Axes를 지워도 fig.axes에서 제거되지 않으며 이웃의 위치도 바뀌지 않습니다.

이 덕분에 cla()는 업데이트 루프에 적합한 도구입니다. Axes를 선택하고, 그 내용을 지우고, 같은 자리에 새 데이터를 그리는 방식입니다. Figure의 나머지는 그대로 둔 채 하나의 패널만 새로 고치는 단순한 애니메이션과 대시보드가 이 패턴을 따릅니다.

다음 예제는 서브플롯 두 개를 만든 뒤 그중 두 번째만 지웁니다. 출력된 검사는 Figure에 여전히 두 Axes가 모두 들어 있고, 첫 번째 Axes에는 선이 남아 있으며, 두 번째 Axes에는 선이 없고 제목이 비어 있음을 보여줍니다.

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 2 * np.pi, 100)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 3.2))
ax1.plot(x, np.sin(x))
ax1.set_title("Sine (kept)")
ax2.plot(x, np.cos(x), color="orange")
ax2.set_title("Cosine (to be cleared)")
fig.tight_layout()
plt.sca(ax2)
plt.cla()
print(f"axes={len(fig.axes)}; ax1_lines={len(ax1.lines)}; ax2_lines={len(ax2.lines)}; ax2_title={ax2.get_title()!r}")
plt.close(fig)

출력:

axes=2; ax1_lines=1; ax2_lines=0; ax2_title=''

호출 전에는 두 서브플롯 모두 곡선을 담고 있습니다.

cla()를 호출하기 전의 서브플롯 두 개: 왼쪽에 사인 곡선, 오른쪽에 코사인 곡선.

plt.cla() 이후에는 두 번째 Axes가 비어 있지만 여전히 제자리를 차지하고, 첫 번째 서브플롯은 변하지 않았습니다.

cla() 이후의 같은 서브플롯 두 개: 사인 곡선은 그대로이고 두 번째 Axes는 비어 있지만 제자리에 있다.

서브플롯 배치는 그대로 두고 하나의 Axes 내용만 새로 고치고 싶다면 cla()를 선택하세요. 코드에 이미 Axes 변수가 있다면 ax.clear()가 pyplot의 현재 Axes 선택을 바꾸지 않으면서 같은 Axes 수준의 의도를 표현합니다.

matplotlib.pyplot.clf()

matplotlib.pyplot.clf()는 현재 Figure를 그 안의 모든 Axes와 그 내용까지 포함해 지웁니다. Figure 객체는 재사용할 수 있도록 남겨 두고 연결된 Figure 관리자는 닫지 않으므로, 같은 Figure를 — 대화형 세션에서는 같은 창을 — 처음부터 다시 채울 수 있습니다. 이 함수는 Figure 범위에서 동작하므로 Axes 단위의 clf() 연산은 존재하지 않습니다.

clf() 이후에는 Figure에 Axes가 전혀 없으므로 다시 그리기 전에 새 Axes를 만들어야 합니다. 단독 plt.plot() 호출은 암묵적으로 새 Axes를 만들어 줍니다. Figure가 여러 개 열려 있다면 plt.clf()를 호출하기 전에 원하는 Figure를 선택하세요. fig.clear()는 객체 수준에서 동등한 연산으로, 대상을 명시합니다.

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(8, 3.2))
axes[0].plot([0, 1, 2], [0, 1, 4])
axes[0].set_title("Line")
axes[1].bar(["A", "B", "C"], [3, 7, 5])
axes[1].set_title("Bar")
fig.tight_layout()
plt.figure(fig.number)
plt.clf()
print(f"figure_axes={len(fig.axes)}; figure_open={plt.fignum_exists(fig.number)}")
ax = fig.add_subplot(1, 1, 1)
ax.plot([0, 1, 2], [4, 1, 0], color="green")
ax.set_title("Rebuilt on the same Figure")
fig.tight_layout()
plt.close(fig)

출력:

figure_axes=0; figure_open=True

Figure는 처음에 꺾은선 그래프와 막대 그래프를 나란히 담고 있습니다.

clf()를 호출하기 전의 Figure: 두 서브플롯에 꺾은선 그래프와 막대 그래프가 나란히 있다.

출력은 clf()가 모든 Axes를 제거했고(figure_axes=0) Figure 자체는 열린 상태로 남았음(figure_open=True)을 확인합니다. 이어서 예제는 새 Axes를 하나 추가하고 같은 Figure 위에 완전히 다른 단일 플롯을 그립니다.

clf()와 재구성 이후의 같은 Figure: 새로운 초록색 꺾은선 그래프 하나가 Figure 전체를 채운다.

Figure를 계속 사용할 수 있도록 유지하면서 그 모든 플롯이나 서브플롯 레이아웃을 처음부터 다시 만들고 싶다면 clf()를 사용하세요. 같은 Figure 안의 다른 Axes는 건드리지 않아야 한다면 대신 cla()를 사용하세요.

matplotlib.pyplot.close()

matplotlib.pyplot.close()는 pyplot이 관리하는 Figure를 닫습니다. 인수 없이 호출하면 현재 Figure를 닫습니다. 특정 Figure를 대상으로 하려면 Figure 객체, 그 번호, 또는 등록된 Figure 이름을 전달하세요. 예를 들어 plt.close(fig)와 같습니다. 'all'을 전달하면 모든 Figure를 한 번에 닫습니다.

닫으면 Figure가 pyplot의 레지스트리에서 제거되므로 plt.fignum_exists()가 더 이상 그것을 보고하지 않고, pyplot은 그 내용을 메모리에 유지하지 않습니다. 지우기와의 중요한 차이는 여기에 있습니다. close() 이후에는 pyplot에 재사용할 Figure가 남지 않지만, clf() 이후에는 같은 Figure가 비어 있는 상태로 새 내용을 기다립니다. 대화형 백엔드에서는 Figure의 창도 파괴되지만, 눈에 보이는 창의 정확한 동작은 백엔드와 실행 컨텍스트에 따라 달라집니다.

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

fig1, ax1 = plt.subplots(figsize=(5, 3.2))
ax1.plot([0, 1, 2], [0, 2, 1])
ax1.set_title("Report 1 (to be closed)")
fig1.tight_layout()
fig2, ax2 = plt.subplots(figsize=(5, 3.2))
ax2.plot([0, 1, 2], [1, 0, 3], color="purple")
ax2.set_title("Report 2 (kept open)")
fig2.tight_layout()
print(f"open_before={plt.get_fignums()}")
plt.close(fig1)
print(f"open_after={plt.get_fignums()}; fig1_open={plt.fignum_exists(fig1.number)}")
plt.close("all")

출력:

open_before=[1, 2]
open_after=[2]; fig1_open=False

호출 후 등록된 채로 남는 것은 Figure 2뿐이며, 표시하거나 저장할 수 있도록 계속 사용할 수 있는 Figure도 바로 그것입니다.

close()가 첫 번째 Figure를 제거한 뒤 남은 두 번째 Figure: Report 2라는 제목의 보라색 꺾은선 그래프 하나.

더 이상 필요 없는 Figure를 만들 때마다, 특히 많은 Figure를 생성하는 스크립트와 루프에서는 close()를 사용하세요. 같은 Figure를 재사용해야 한다면 대신 clf()로 지우세요. 서브플롯 하나만 새로 고치면 된다면 cla() 또는 ax.clear()를 사용하세요.

메모리와 Figure 수명 주기

세 함수는 비용 면에서도 다릅니다. cla()와 clf()는 저렴하고 반복할 수 있는 연산입니다. Figure는 pyplot에 등록된 채로 남고, 그 창과 버퍼는 살아 있으며, 버려지는 것은 내용뿐입니다. 다시 그려질 Figure에 정확히 필요한 동작입니다. close()는 Figure 자체를 해제하는 유일한 함수이므로, 다시 그려지지 않을 Figure에 대한 유일하게 올바른 마무리입니다.

pyplot은 만든 모든 Figure를 명시적으로 닫을 때까지 등록해 두고, 그 레지스트리가 너무 커지면 경고를 보냅니다. 루프 안에서 Figure를 닫지 않고 만들면 메모리가 쌓이고 결국 RuntimeWarning이 발생합니다.

import warnings
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always")
    for _ in range(25):
        plt.figure()
    print(f"figures_open={len(plt.get_fignums())}")
    print(f"too_many_figures_warning={any(str(w.message).startswith('More than 20 figures') for w in caught)}")
plt.close("all")
print(f"after_close_all={plt.get_fignums()}")

출력:

figures_open=25
too_many_figures_warning=True
after_close_all=[]

그 루프에서는 cla()도 clf()도 도움이 되지 않습니다. 문제가 내용이 아니라 등록된 Figure의 수이기 때문입니다. 경험 법칙은 다음과 같습니다. 같은 Figure가 계속되면 지우고, 그렇지 않으면 닫으세요. Figure마다 파일 하나를 저장하는 배치 작업은 저장 직후 plt.close(fig)를 호출해야, 작업이 생성하는 보고서 수와 관계없이 최대 메모리가 일정하게 유지됩니다.

어떤 함수를 사용해야 할까?

  • 애니메이션이나 실시간 대시보드처럼 여러 패널이 있는 Figure의 한 패널을 다시 그릴 때: 레이아웃과 다른 패널이 유지되도록 cla()(또는 ax.clear())를 사용하세요.
  • 같은 창이나 Figure 객체를 유지하면서 다른 레이아웃으로 Figure를 처음부터 다시 시작할 때: clf()(또는 fig.clear())를 사용한 뒤 새 Axes를 추가하세요.
  • Figure 사용이 끝났을 때, 특히 루프나 배치 스크립트 안에서: pyplot이 해제하도록 Figure, 그 번호, 또는 'all'을 전달해 close()를 사용하세요.

가장 흔한 실수는 cla()를 써야 할 곳에 clf()를 사용하는 것 — 현재 Axes만이 아니라 Figure 안의 모든 서브플롯을 조용히 지워 버립니다 —, 잘못된 Axes가 현재 대상인 상태에서 cla()를 호출하는 것, 그리고 닫은 Figure가 이후에도 pyplot을 통해 닿을 수 있다고 기대하는 것입니다. 요약하면, Axes 하나는 cla()로 지우고, Figure 안의 모든 Axes는 clf()로 지우며, Figure는 close()로 마무리하세요.