Matplotlib에서 회전하는 3D 그래프를 만들려면 Animation 클래스를 사용해 특정 함수를 반복적으로 호출하면 됩니다. 이 방법을 활용하면 3D 곡면 플롯이 마치 회전하는 것처럼 부드럽게 움직이는 애니메이션을 손쉽게 구현할 수 있습니다.
구현 단계
- 메시 그리드 개수(N), 초당 프레임 수(fps), 전체 프레임 수(frn) 등 필요한 변수를 초기화합니다.
- 곡선을 표현하기 위한 x, y, z 배열을 생성합니다.
- 람다(lambda) 함수를 이용해 z 배열의 값을 계산하는 함수를 정의합니다.
- 애니메이션 클래스에 전달할 사용자 정의 함수를 작성하여, 이전 프레임의 플롯을 제거한 뒤 x, y, z 배열로 새 곡면을 다시 그립니다.
- figure() 메서드로 새 figure를 생성하거나 기존 figure를 활성화합니다.
- add_subplot() 메서드로 3D 서브플롯 배치를 추가합니다.
- set_zlim() 메서드로 Z축 표시 범위를 설정합니다.
- animation.FuncAnimation()을 호출하여 곡면 플롯에 애니메이션을 적용합니다.
- show() 메서드로 완성된 애니메이션 플롯을 화면에 출력합니다.
예제 코드
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
plt.rcParams["figure.figsize"] = [7.00, 3.50]
plt.rcParams["figure.autolayout"] = True
N = 50
fps = 250
frn = 75
x = np.linspace(-4, 4, N + 1)
x, y = np.meshgrid(x, x)
zarray = np.zeros((N + 1, N + 1, frn))
f = lambda x, y, sig: 1 / np.sqrt(sig) * np.exp(-(x ** 2 + y ** 2) / sig ** 2)
for i in range(frn):
zarray[:, :, i] = f(x, y, 1.5 + np.sin(i * 2 * np.pi / frn))
def change_plot(frame_number, zarray, plot):
plot[0].remove()
plot[0] = ax.plot_surface(x, y, zarray[:, :, frame_number], cmap="afmhot_r")
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
plot = [ax.plot_surface(x, y, zarray[:, :, 0], color='0.75', rstride=1, cstride=1)]
ax.set_zlim(0, 1.1)
ani = animation.FuncAnimation(fig, change_plot, frn, fargs=(zarray, plot), interval=1000 / fps)
ani.save('526.gif')
plt.show()
코드 핵심 설명
- 변수 설정: N=50은 격자 해상도, fps=250은 초당 프레임 수, frn=75는 전체 프레임 수를 의미합니다.
- f 함수: 가우시안(Gaussian) 형태의 함수로, sig 값이 작아지면 중심이 뾰족해지고 커지면 완만한 곡면이 됩니다.
- 반복문: sin 함수를 이용해 sig 값을 1.5 ± 1 범위에서 주기적으로 변화시키며 각 프레임의 zarray를 채웁니다.
- change_plot 함수: 매 프레임마다 remove()로 기존 곡면을 지우고 plot_surface()로 새 곡면을 그려 애니메이션 효과를 만듭니다.
- FuncAnimation: figure, 업데이트 함수, 프레임 수, 추가 인자(fargs), 프레임 간격(interval=1000/fps 밀리초)을 지정합니다.
- ani.save('526.gif'): 완성된 애니메이션을 GIF 파일로 저장합니다.
실행 결과
위 코드를 실행하면 sin 함수에 따라 sigma 값이 주기적으로 변하면서 3D 가우시안 곡면이 위아래로 출렁이듯 회전하는 애니메이션이 생성됩니다. 결과는 '526.gif' 파일로 저장되며, show() 메서드를 통해 팝업 창에서도 실시간으로 확인할 수 있습니다.
