Python案例如何用Matplotlib做动画

wen python案例 1

本文目录导读:

Python案例如何用Matplotlib做动画

  1. 基础动画:FuncAnimation(最常用)
  2. 3D动画
  3. 复杂案例:物理模拟
  4. 高级技巧
  5. 实用技巧总结

我来分享几种用Matplotlib制作动画的常用方法,从简单到复杂。

基础动画:FuncAnimation(最常用)

示例1:正弦波动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# 创建图形
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 100)
line, = ax.plot(x, np.sin(x), 'b-', linewidth=2)
# 设置坐标轴
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1.5, 1.5)
ax.grid(True, alpha=0.3)
# 动画更新函数
def update(frame):
    line.set_ydata(np.sin(x + frame/10))  # 更新y数据
    ax.set_title(f'正弦波动画 - 帧: {frame}')
    return line,
# 创建动画
ani = FuncAnimation(fig, update, frames=100, interval=50, blit=True)
# 显示动画
plt.show()
# 保存动画(可选)
# ani.save('sine_wave.gif', writer='pillow', fps=20)

示例2:散点图动态更新

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# 准备数据
np.random.seed(42)
n_points = 50
x = np.random.randn(n_points)
y = np.random.randn(n_points)
colors = np.random.rand(n_points)
sizes = np.random.randint(50, 200, n_points)
fig, ax = plt.subplots(figsize=(8, 6))
scatter = ax.scatter(x, y, c=colors, s=sizes, alpha=0.6)
ax.set_xlim(-3, 3)
ax.set_ylim(-3, 3)
ax.grid(True, alpha=0.3)
ax.set_title('动态散点图')
def update(frame):
    # 更新数据点位置
    new_x = x + np.random.randn(n_points) * 0.1
    new_y = y + np.random.randn(n_points) * 0.1
    scatter.set_offsets(np.c_[new_x, new_y])
    scatter.set_sizes(sizes + np.random.randint(-10, 10, n_points))
    ax.set_title(f'动态散点图 - 帧: {frame}')
    return scatter,
ani = FuncAnimation(fig, update, frames=100, interval=100, blit=True)
plt.show()

3D动画

示例3:3D曲面动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from mpl_toolkits.mplot3d import Axes3D
# 创建3D图形
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# 生成数据网格
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
# 初始Z值
Z = np.sin(np.sqrt(X**2 + Y**2))
# 绘制初始曲面
surf = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
def update(frame):
    ax.clear()
    # 动态变化的曲面
    Z = np.sin(np.sqrt(X**2 + Y**2) + frame/10) * (1 + 0.1*np.sin(frame/5))
    # 重绘
    surf = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
    ax.set_xlim(-5, 5)
    ax.set_ylim(-5, 5)
    ax.set_zlim(-1.5, 1.5)
    ax.set_title(f'3D曲面动画 - 帧: {frame}')
    return surf,
ani = FuncAnimation(fig, update, frames=100, interval=50)
plt.show()

复杂案例:物理模拟

示例4:粒子系统动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
class Particle:
    def __init__(self, x, y, vx, vy, color, size):
        self.x = x
        self.y = y
        self.vx = vx
        self.vy = vy
        self.color = color
        self.size = size
    def update(self, dt=0.1):
        # 简单物理模拟
        self.x += self.vx * dt
        self.y += self.vy * dt
        # 边界碰撞
        if abs(self.x) > 5:
            self.vx *= -1
        if abs(self.y) > 5:
            self.vy *= -1
# 创建粒子
np.random.seed(42)
n_particles = 30
particles = []
for _ in range(n_particles):
    particles.append(Particle(
        x=np.random.uniform(-4, 4),
        y=np.random.uniform(-4, 4),
        vx=np.random.uniform(-2, 2),
        vy=np.random.uniform(-2, 2),
        color=np.random.rand(3),
        size=np.random.uniform(20, 80)
    ))
# 创建图形
fig, ax = plt.subplots(figsize=(8, 8))
scatter = ax.scatter([], [], c=[], s=[])
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.grid(True, alpha=0.3)
ax.set_aspect('equal')
def update(frame):
    # 更新所有粒子位置
    for p in particles:
        p.update()
    # 更新散点图数据
    x_data = [p.x for p in particles]
    y_data = [p.y for p in particles]
    colors = [p.color for p in particles]
    sizes = [p.size for p in particles]
    scatter.set_offsets(np.c_[x_data, y_data])
    scatter.set_color(colors)
    scatter.set_sizes(sizes)
    ax.set_title(f'粒子系统模拟 - 帧: {frame}')
    return scatter,
ani = FuncAnimation(fig, update, frames=200, interval=50, blit=True)
plt.show()

高级技巧

示例5:多子图同步动画

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# 创建多个子图
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
ax1, ax2, ax3, ax4 = axes.flatten()
# 初始化数据
t = np.linspace(0, 2*np.pi, 100)
line1, = ax1.plot(t, np.sin(t), 'r-', linewidth=2)
line2, = ax2.plot(t, np.cos(t), 'b-', linewidth=2)
line3, = ax3.plot(t, np.sin(t), 'g-', linewidth=2)
scatter = ax4.scatter([], [], c=[], s=[])
# 设置坐标轴
for ax in [ax1, ax2, ax3, ax4]:
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1.5, 1.5)
    ax.grid(True, alpha=0.3)
ax4.set_title('散点图')
ax1.set_title('正弦波')
ax2.set_title('余弦波')
ax3.set_title('正弦波')
def update(frame):
    phase = frame / 20
    # 更新线条
    line1.set_ydata(np.sin(t + phase))
    line2.set_ydata(np.cos(t + phase))
    line3.set_ydata(np.sin(t + 2*phase))
    # 更新散点图
    x_data = np.cos(t + phase)
    y_data = np.sin(t + phase)
    scatter.set_offsets(np.c_[x_data[::5], y_data[::5]])
    scatter.set_color(np.random.rand(20, 3))
    return line1, line2, line3, scatter,
ani = FuncAnimation(fig, update, frames=200, interval=30, blit=True)
plt.tight_layout()
plt.show()

实用技巧总结

保存动画

# 保存为GIF
ani.save('animation.gif', writer='pillow', fps=20)
# 保存为MP4(需要ffmpeg)
ani.save('animation.mp4', writer='ffmpeg', fps=20)
# 保存为HTML5视频(在Jupyter中)
from IPython.display import HTML
HTML(ani.to_html5_video())

性能优化

# 1. 使用blit=True减少重绘
ani = FuncAnimation(fig, update, frames=100, interval=50, blit=True)
# 2. 减少数据点数量
x = np.linspace(0, 2*np.pi, 50)  # 而不是1000
# 3. 使用更简单的图形元素
# 首选:Line2D, Scatter
# 避免:填充区域、等高线

常见问题解决

# 1. 动画不显示
plt.ion()  # 打开交互模式
# 2. 内存泄露
ani.event_source.stop()  # 停止动画
# 3. 调整帧率
# interval=50 表示50毫秒一帧,即20fps
ani = FuncAnimation(fig, update, frames=100, interval=50)

这些案例覆盖了Matplotlib动画的主要应用场景,开始学习时推荐从FuncAnimation和简单的一维动画入手,逐步扩展到复杂应用。

抱歉,评论功能暂时关闭!