如何用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
- Track Historical Positions: Maintain a buffer of the last N positions of the pendulum's end point to form the trail.
- Render Fading Trail: Use a
LineCollectionto draw segments between consecutive positions, with alpha values decreasing from fully opaque (newest points) to nearly transparent (oldest points). - 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_lengthto 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=2to make the trail thicker or thinner.
- Change
- Optimize Performance: If you notice lag, reduce
max_trail_lengthor decrease the frame count inFuncAnimation.
内容的提问来源于stack exchange,提问作者Mateusz Ormianek
相关产品推荐
相关产品推荐

