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

如何用Matplotlib绘制跟随运动点的轨迹阴影?附双摆示例代码

Adding a Fading Trail Shadow to Your Double Pendulum Animation

To create the smooth, fading trajectory shadow effect you're aiming for, we'll track the historical positions of the second pendulum's end point and render them as a gradually fading line trail. Here's how to modify your existing code to achieve this:

Key Implementation Steps

  1. Track Historical Positions: Maintain a buffer of the last N positions of the pendulum's end point to form the trail.
  2. Render Fading Trail: Use a LineCollection to draw segments between consecutive positions, with alpha values decreasing from fully opaque (newest points) to nearly transparent (oldest points).
  3. Layer Visuals: Ensure the trail is drawn behind the pendulum to keep the animation clear and visually appealing.

Modified Working Code

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.collections import LineCollection
from scipy.integrate import odeint
from time import time

class DoublePendulum:
    def __init__(self, init_state = [120,0,-20,0], L1 = .5, L2 = .5, M1 = 1.0, M2 = 2.0, G = 9.8, origin=(0,0)):
        self.init_state = np.asarray(init_state,dtype='float')
        self.params = (L1,L2,M1,M2,G)
        self.origin = origin
        self.time_elapsed = 0
        self.state = self.init_state * np.pi/180
    def position(self):
        (L1, L2, M1, M2, G) = self.params
        x = np.cumsum([self.origin[0], L1 * np.sin(self.state[0]), L2 * np.sin(self.state[2])])
        y = np.cumsum([self.origin[1], -L1 * np.cos(self.state[0]), -L2 * np.cos(self.state[2])])
        return (-x,-y)
    def dstate_dt(self,state,t):
        (M1,M2,L1,L2,G)=self.params
        dydx = np.zeros_like(state)
        dydx[0] = state[1]
        dydx[2] = state[3]
        cos_delta = np.cos(state[2] - state[0])
        sin_delta = np.sin(state[2] - state[0])
        den1 = (M1 + M2) * L1 - M2 * L1 * cos_delta * cos_delta
        dydx[1] = (M2 * L1 * state[1] * state[1] * sin_delta * cos_delta + M2 * G * np.sin(state[2]) * cos_delta + M2 * L2 * state[3] * state[3] * sin_delta - (M1+M2) * G * np.sin(state[0])) / den1
        den2 = (L2 / L1) * den1
        dydx[3] = (-M2 * L2 * state[3] * state[3] * sin_delta * cos_delta + (M1 + M2) * G * np.sin(state[0]) * cos_delta - (M1 + M2) * L1 * state[1] * state[1] * sin_delta - (M1 + M2) * G * np.sin(state[2])) / den2
        return dydx
    def step(self,dt):
        self.state = odeint(self.dstate_dt, self.state, [0,dt])[1]
        self.time_elapsed += dt

pendulum = DoublePendulum([120.,0.0,180.,0.0],.5,.5,10,10,10)
dt = 1./30 #fps
fig = plt.figure(1)
lim1,lim2 = 2,-2
ax = fig.add_subplot(111,aspect='equal', autoscale_on=False, xlim=(lim1,lim2),ylim=(lim1,lim2),alpha=0.5)
ax.grid()

# Pendulum line (drawn on top of the trail)
line, = ax.plot([],[],'o-',lw=2)
line.set_zorder(1)

# Time display text
time_text = ax.text(0.02,0.95,'', transform=ax.transAxes)

# Trail configuration
max_trail_length = 100  # Adjust to control how long the trail persists
trail_points = []
trail_collection = LineCollection([], linewidths=2, color='gray')
trail_collection.set_zorder(0)  # Ensure trail stays behind the pendulum
ax.add_collection(trail_collection)

def init():
    line.set_data([],[])
    time_text.set_text('')
    trail_collection.set_segments([])
    return line, time_text, trail_collection

def animate(i):
    global pendulum, dt, trail_points, max_trail_length, trail_collection
    pendulum.step(dt)
    x_pos, y_pos = pendulum.position()
    line.set_data(x_pos, y_pos)
    time_text.set_text('time = %.1f' % pendulum.time_elapsed)
    
    # Add current end position to trail buffer
    end_x = x_pos[-1]
    end_y = y_pos[-1]
    trail_points.append((end_x, end_y))
    
    # Trim trail to keep only the most recent points
    if len(trail_points) > max_trail_length:
        trail_points.pop(0)
    
    # Update trail visualization
    if len(trail_points) > 1:
        # Create segments between consecutive trail points
        segments = [np.array([trail_points[i], trail_points[i+1]]) for i in range(len(trail_points)-1)]
        trail_collection.set_segments(segments)
        # Apply gradient alpha: oldest segments fade to nearly transparent
        alphas = np.linspace(0.1, 1.0, len(segments))
        trail_collection.set_alpha(alphas)
    else:
        trail_collection.set_segments([])
    
    return line, time_text, trail_collection

t0 = time()
animate(0)
t1 = time()
interval = 100 * dt - (t1-t0)
ani = FuncAnimation(fig,animate,frames=150, interval=interval, blit=True, init_func=init)
fig.set_size_inches(6.5, 6.5)
plt.show()

Customization Tips

  • Adjust Trail Length: Modify max_trail_length to make the trail longer (higher values) or shorter (lower values).
  • Tweak Trail Appearance:
    • Change color='gray' to match your pendulum's color (e.g., color='#1f77b4' for the default blue).
    • Adjust the alpha range in np.linspace(0.1, 1.0, len(segments)) to make the trail fade faster (lower start value) or slower (higher start value).
    • Modify linewidths=2 to make the trail thicker or thinner.
  • Optimize Performance: If you notice lag, reduce max_trail_length or decrease the frame count in FuncAnimation.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:37:51