You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用FuncAnimation高效更新mpl_toolkits mplot3d中的3D Quiver数据

Efficiently Updating 3D Quiver Data in Matplotlib Animations

Great question! I’ve run into this exact issue with 3D quiver animations in matplotlib before—clearing the axis every frame is a performance killer and breaks your carefully set axis configurations. Let’s fix this by updating the existing quiver directly, just like you do with your 2D line plot.

First, Clarify the Object Type

You mentioned seeing the quiver as a Line3DCollection—that’s actually the 2D quiver implementation. For 3D, ax1.quiver() returns a mpl_toolkits.mplot3d.art3d.Quiver3D instance, which has built-in methods to modify its data without rebuilding the entire object.

Core Methods to Update the Quiver

The Quiver3D class has two key methods for dynamic updates:

  • set_UVC(U, V, W): Updates the direction components of the vector (this is your equivalent of line0.set_ydata())
  • set_offsets(offsets) + set_zdir(z): Use these if you need to change the starting point (X,Y,Z) of the arrow (not needed in your case since you’re starting at (0,0,0), but useful to know)

Modified Code Implementation

Here’s how to adjust your existing code to update the quiver efficiently:

  1. Initialize the quiver with a default vector (so we have an object to modify later):
# Initialize with a zero vector instead of NaN
vec0 = ax1.quiver(0, 0, 0, 0, 0, 0, length=1)
  1. Update the animate function to modify the existing quiver:
def animate(i, ser, ys_roll):
    # Get USB readings
    pos = get_readings(ser)
    
    # Update 2D roll plot as before
    ys_roll.append(pos[0])
    ys_roll = ys_roll[-log_size:]
    line0.set_ydata(ys_roll)
    
    # Update the 3D quiver directly (no clearing or rebuilding!)
    vec0.set_UVC(pos[3], pos[4], pos[5])
    
    # Return ONLY the artists that changed (critical for blit=True)
    return line0, vec0
  1. Fix the animation initialization:
    Your original FuncAnimation setup is mostly correct, but ensure the returned objects match what you’re updating. The blitting system needs to know exactly which elements to redraw each frame.

Key Notes

  • This approach keeps your axis settings intact (no more resetting limits after ax1.clear())
  • It’s far more performant than recreating the quiver every frame, which is essential for smooth real-time animations with ESP32 data
  • If you ever need to change the starting point (X,Y,Z) of the arrow, you can use:
    # For a single starting point (e.g., (x, y, z))
    vec0.set_offsets(np.array([[x, y]]))  # Pass 2D array for X/Y offsets
    vec0.set_zdir(z)  # Set the Z component of the start point
    

Full Modified Code Snippet

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits import mplot3d

# The number of values that are going to be charted
log_size = 200

# Create a figure instance and add subplots
fig = plt.figure()
ax = fig.add_subplot(2, 1, 1)

# Create static arrays for 2D plot
xs = list(range(0, log_size))
ys_roll = [np.NaN] * log_size

# Set 2D plot limits
ax.set_xlim([0, log_size])
ax.set_ylim([-180, 180])

# Setup 2D line
line0, = ax.plot(xs, ys_roll, label="Roll")

# Establish 2D chart parameters
plt.title('Roll, Pitch, and Yaw')
plt.xlabel('X')
plt.ylabel('Angle')
plt.legend()

# Setup 3D subplot and initial quiver (zero vector)
ax1 = fig.add_subplot(212, projection='3d')
ax1.set_xlim([-1, 1])
ax1.set_ylim([-1, 1])
ax1.set_zlim([-1, 1])
vec0 = ax1.quiver(0, 0, 0, 0, 0, 0, length=1)

# Format plot
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)

ser = ...  # Serial port setup here

def get_readings(ser):
    # Function to get serial port readings and return an np.array() with 6 elements:
    # Roll, Pitch, Yaw, and vector U, V, W.
    ...
    return np.array([roll_val, pitch_val, yaw_val, U, V, W])

def animate(i, ser, ys_roll):
    pos = get_readings(ser)
    # Update 2D roll data
    ys_roll.append(pos[0])
    ys_roll = ys_roll[-log_size:]
    line0.set_ydata(ys_roll)
    # Update 3D quiver vector
    vec0.set_UVC(pos[3], pos[4], pos[5])
    # Return updated artists for blitting
    return line0, vec0

# Setup animation
ani = animation.FuncAnimation(fig, animate, fargs=(ser, ys_roll), interval=10, blit=True)
plt.show()

内容的提问来源于stack exchange,提问作者Plant_Boy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 10:22:48