杰瑞科技汇

FuncAnimation如何高效实现Python动画?

Of course! FuncAnimation is a powerful and popular class from the matplotlib.animation module. It's the primary tool for creating animations in Matplotlib.

FuncAnimation如何高效实现Python动画?-图1
(图片来源网络,侵删)

Let's break it down from the core concept to practical examples.

What is FuncAnimation?

At its heart, FuncAnimation is a class that repeatedly calls a user-defined function. It takes the output of that function and uses it to update a plot. This creates the illusion of motion.

Think of it like a flipbook:

  1. You draw a picture on a page (update_function).
  2. You turn the page (frame).
  3. You draw the next picture, slightly changed from the last one.
  4. You repeat this process and flip the pages quickly to see an animation.

FuncAnimation automates this process for you.

FuncAnimation如何高效实现Python动画?-图2
(图片来源网络,侵删)

Core Components & How it Works

The key to understanding FuncAnimation is understanding its arguments, especially the update_function.

The update_function (The Heart of the Animation)

This is the most important argument. It's the function that FuncAnimation will call for every single frame of the animation.

Signature: update_function(frame_number, *fargs)

  • frame_number: An integer that starts at 0 and increments by 1 for each new frame. This is how you make your animation change over time.
  • *fargs: Any additional arguments you want to pass to your update function.

What must it return? The update_function must return a sequence of artists that need to be redrawn. An "artist" is any Matplotlib object that can be drawn on a figure, like a Line2D object (from plot()), a PathPatch object (from scatter() or patch objects), or a text object.

FuncAnimation如何高效实现Python动画?-图3
(图片来源网络,侵删)

frames

This argument defines the number of frames in your animation.

  • It can be an integer (e.g., frames=100 for 100 frames).
  • It can be a generator or list of values (e.g., frames=np.linspace(0, 2*np.pi, 100)). In this case, the frame_number passed to your function will be the actual value from the sequence.

init_function (Optional but Recommended)

This function is called once at the very beginning, before the animation starts. Its job is to set up the initial plot.

Why is it important? Without an init_function, Matplotlib will draw the first frame using your update_function with frame_number=0. Then, for the next frame, it will redraw everything. This can be inefficient and can cause flickering.

The init_function should return all the artists that will be animated, just like the update_function. This tells Matplotlib, "These are the objects I'm going to be changing, so only redraw these."

interval

The time between frames in milliseconds. interval=50 means 50ms, or 20 frames per second (1000ms / 50ms = 20 fps).

blit=True (Performance Booster)

This is a crucial performance argument.

  • When blit=True, Matplotlib only redraws the parts of the plot that have changed (the artists returned by your update_function). This makes animations much, much faster.
  • To use blit=True, you MUST return a list/tuple of artists from both your init_function and your update_function.

Step-by-Step Example: A Simple Sine Wave

Let's animate a sine wave moving across the screen.

Step 1: Setup and Imports

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

Step 2: Create the Figure and Axes

This is our "canvas".

# Create a figure and an axes
fig, ax = plt.subplots()
plt.style.use('seaborn-v0_8-palette') # For nice colors

Step 3: Initialize Plot Elements

We need to create the plot elements that will be animated. Here, it's a line plot.

# Set the limits of the plot
ax.set_xlim(0, 2 * np.pi)
ax.set_ylim(-1.1, 1.1)
# Create a line object. We'll update its data later.
# The initial data is empty.
x = np.linspace(0, 2 * np.pi, 200)
line, = ax.plot([], [], lw=2, color='blue')
# Add a title
ax.set_title("Animated Sine Wave")

Note the comma: line, = ax.plot(...) is important. ax.plot() returns a list of line objects. We want the single line object itself, so we unpack it with a comma.

Step 4: Define the init_function

This function sets up the initial state of our animated artists.

def init():
    """Initialize the animation."""
    # Set the line's data to be empty
    line.set_data([], [])
    # Return the artist that needs to be redrawn
    return line,
  • We set the line's data to empty lists.
  • We return the line object inside a tuple (line,). This is required for blitting.

Step 5: Define the update_function

This function is called for each frame.

def update(frame):
    """Update the animation for each frame."""
    # Calculate the new y-values for the sine wave
    # We shift the wave by the 'frame' amount
    y = np.sin(x + frame / 10.0)
    # Update the line's data
    line.set_data(x, y)
    # Return the artist that needs to be redrawn
    return line,
  • We calculate the new y values based on the frame number.
  • We update the data of our line object.
  • We return the line artist.

Step 6: Create and Run the Animation

Now we put it all together.

# Create the animation
# frames=200: 200 frames
# init_func=init: our initialization function
# ffunc=update: our update function
# interval=20: 20ms between frames (50 fps)
# blit=True: use blitting for performance
ani = FuncAnimation(fig=fig, 
                    func=update, 
                    frames=200, 
                    init_func=init, 
                    interval=20, 
                    blit=True)
# To display the animation in a Jupyter Notebook or a script:
plt.show()
# To save the animation as a video file (requires ffmpeg or imagemagick):
# ani.save('sine_wave.mp4', writer='ffmpeg', fps=30)

Complete, Runnable Code

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# --- 1. Setup ---
fig, ax = plt.subplots()
plt.style.use('seaborn-v0_8-palette')
ax.set_xlim(0, 2 * np.pi)
ax.set_ylim(-1.1, 1.1)
ax.set_title("Animated Sine Wave")
ax.set_xlabel("x")
ax.set_ylabel("sin(x)")
# --- 2. Initialize Plot Elements ---
x = np.linspace(0, 2 * np.pi, 200)
line, = ax.plot([], [], lw=2, color='blue')
# --- 3. Define Functions ---
def init():
    """Initialize the animation."""
    line.set_data([], [])
    return line,
def update(frame):
    """Update the animation for each frame."""
    y = np.sin(x + frame / 10.0)
    line.set_data(x, y)
    return line,
# --- 4. Create Animation ---
# Note: Use 'save_count' to prevent a bug in some environments
# when saving with a writer. For display, it's not needed.
ani = FuncAnimation(fig=fig, 
                    func=update, 
                    frames=200,
                    init_func=init, 
                    interval=20, 
                    blit=True)
# --- 5. Display or Save ---
# To display the animation
plt.show()
# To save the animation (uncomment the line below)
# You might need to install ffmpeg: `conda install ffmpeg` or `pip install ffmpeg-python`
# ani.save('sine_wave.mp4', writer='ffmpeg', fps=30)

Advanced Example: Animated Scatter Plot

This example shows how to animate multiple objects (scatter points) and use a custom frame sequence.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# --- Setup ---
fig, ax = plt.subplots()
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.set_title("Animated Scatter Plot")
ax.set_xlabel("X-axis")
ax.set_ylabel("Y-axis")
ax.grid(True)
# --- Data ---
num_points = 50
# Initial positions
positions = np.random.rand(num_points, 2) * 10 - 5
# Velocities
velocities = (np.random.rand(num_points, 2) - 0.5) * 0.2
分享:
扫描分享到社交APP
上一篇
下一篇