การทำ Animation ของ Colorbar ใน Matplotlib ต้องอัปเดตทั้ง Image Data (imshow) และ Colorbar ให้ซิงค์กันในแต่ละเฟรม โดยใช้ FuncAnimation และสร้าง Colorbar ใหม่หรืออัปเดต Colormap ทุกเฟรม
หลักการ
- สร้าง Figure และ Axes หลัก
- ใช้
make_axes_locatableสร้าง Axes สำหรับ Colorbar (cax) - สร้าง
imshowและcolorbarเริ่มต้น - ใน
animate(): อัปเดตข้อมูลim.set_data(),im.set_cmap(), แล้วสร้าง Colorbar ใหม่ใน cax
ตัวอย่างโค้ด
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from mpl_toolkits.axes_grid1 import make_axes_locatable
plt.rcParams["figure.figsize"] = [10, 6]
plt.rcParams["figure.autolayout"] = True
fig, ax = plt.subplots()
# สร้าง Axes สำหรับ Colorbar (ขวา 5% กว้าง 5%)
divider = make_axes_locatable(ax)
cax = divider.append_axes('right', size='5%', pad='5%')
# ข้อมูลเริ่มต้น
data = np.random.rand(10, 10)
im = ax.imshow(data, cmap='viridis', animated=True)
# สร้าง Colorbar เริ่มต้น
cbar = fig.colorbar(im, cax=cax)
cbar.set_label('Intensity', fontsize=12)
# Title แบบไดนามิก
title = ax.set_title('Frame 0', fontsize=14, pad=15)
# รายการ Colormaps สำหรับสลับ
colormaps = ['viridis', 'plasma', 'inferno', 'magma', 'cividis', 'hot', 'coolwarm', 'turbo']
def animate(frame):
# สร้างข้อมูลใหม่
new_data = np.random.rand(10, 10)
# สลับ Colormap
cmap_name = colormaps[frame % len(colormaps)]
# อัปเดต Image
im.set_data(new_data)
im.set_cmap(cmap_name)
im.set_clim(0, 1) # Fix color range
# สร้าง Colorbar ใหม่ (ต้อง Clear cax ก่อน)
cax.cla()
cbar = fig.colorbar(im, cax=cax)
cbar.set_label('Intensity', fontsize=12)
# อัปเดต Title
title.set_text(f'Frame {frame} | Colormap: {cmap_name}')
return im, title
ani = animation.FuncAnimation(
fig, animate,
frames=50,
interval=300, # 300 ms = ~3.3 FPS
blit=False, # Colorbar ต้อง blit=False (ซับซ้อน)
repeat=True
)
plt.show()
ผลลัพธ์
Animation แสดง Heatmap ที่ข้อมูลและ Colormap สลับเปลี่ยนไปเรื่อยๆ Colorbar ด้านขวาอัปเดตตาม Colormap ใหม่ทุกเฟรม
เทคนิคสำคัญ
- cax.cla(): Clear Colorbar Axes ก่อนสร้างใหม่ (จำเป็น)
- make_axes_locatable: สร้าง cax แยกต่างหาก ไม่ให้ Colorbar บีบ Axes หลัก
- blit=False: การอัปเดต Colorbar ซับซ้อน ไม่รองรับ Blitting ได้ดี
- im.set_clim(): คง Color Range ไว้ เพื่อเปรียบเทียบระหว่างเฟรมได้
วิธีอัปเดต Colorbar เดิม (ไม่สร้างใหม่) - เร็วกว่า
# สร้าง Colorbar ครั้งเดียว
cbar = fig.colorbar(im, cax=cax)
def animate(frame):
new_data = np.random.rand(10, 10)
im.set_data(new_data)
im.set_cmap(colormaps[frame % len(colormaps)])
# อัปเดต Colorbar เดิม (ไม่ต้อง cla + สร้างใหม่)
cbar.update_normal(im) # หรือ cbar.update_bruteforce(im)
title.set_text(f'Frame {frame}')
return im, title
# ต้องใช้ blit=False ยังคง
ani = animation.FuncAnimation(fig, animate, frames=50, interval=200, blit=False)
คำแนะนำ
- ใช้
cbar.update_normal(im)เร็วกว่าสร้าง Colorbar ใหม่ - กำหนด
vmin,vmaxคงที่ เพื่อให้สีสอดคล้องระหว่างเฟรม - สำหรับ Export:
ani.save('colorbar_anim.gif', writer='pillow', fps=5)