![](/img/trans.png)
[英]How can I fix "list index out of range" error in my scatter plot on Python?
[英]How do I avoid the 'list index out of range' error when animating line as well as scatter plot
我只是在玩 matplotlib 的動畫模塊。 我想創建一個彈丸運動的動畫情節。 我設法使用以下代碼創建它:
import matplotlib.animation as ani
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['figure.dpi'] = 150
## Inputs
angle = 30 # deg
angleRad = angle*np.pi/180
vel = 2 # m/s
deltat = 0.005 # s (timestep)
acc = -9.81 # m/s^2 (gravitational acc)
## Calculations
# Initialisations
ux0 = vel*np.cos(angleRad)
uy0 = vel*np.sin(angleRad)
U = [ux0]
V = [uy0]
# Acceleration
ax = 0
ay = acc
# Velocity
def calcVel(time):
Uvel = ux0 + ax*time
Vvel = uy0 + ay*time
return (Uvel, Vvel)
# Location
x0 = 0
y0 = 0
x = [x0]
y = [y0]
def location(time):
locx = U[0]*time + 0.5*ax*time**2
locy = V[0]*time + 0.5*ay*time**2
return (locx, locy)
yn = y0
t0 = 0
n = 1
count = [0]
while yn>=0:
t = t0 + n*deltat
xVel, yVel = calcVel(t)
posx, posy = location(t)
yn = posy
if yn>=0:
U.append(xVel)
V.append(yVel)
x.append(posx)
y.append(posy)
count.append(t)
n +=1
def buildframes(i=int):
line.set_data(x[:i], y[:i])
points.set_offsets([x[i-1], y[i-1]])
index.set_text('time = %.3f s' % count[i])
plt.pause(0.001)
## Plotting
fig = plt.figure()
axes = fig.add_subplot(1,1,1)
line, = axes.plot([], []) # , 'bo', lw=2, scalex = True, scaley = True
points = plt.scatter([], [], c='red', s=15)
axes.set_ylim(min(y), np.true_divide(np.ceil(max(y) * 10**2), 10**2))
axes.set_xlim(min(x), np.true_divide(np.ceil(max(x) * 10**2), 10**2))
plt.ylabel('Height')
plt.xlabel('Distance')
index = axes.annotate('', xy=(0.75, 0.95), xycoords='axes fraction')
animator = ani.FuncAnimation(fig, buildframes, interval = 500)
#animator.save("filename")
plt.show()
animator.save('animation.gif')
標題問題很容易成為一個通用的“我如何改進此代碼”,但這里不鼓勵這樣做。 雖然代碼生成動畫,但此代碼存在幾個更精細的問題。 我按重要性降序列出了它們:
ani.FuncAnimation(fig, buildframes, frames=len(x), interval=500)
zorder
強制以適當的順序顯示事物。 在這里,我使用 ``zorder=1' for the line and
使用 zorder=2' 作為散布,因此散布將在線條頂部可視化。plt.pause
放在動畫函數中。 調用ani.FuncAnimation
時設置適當的interval
。 動畫功能本來就很好。 在下面的代碼中,我使用 Numpy 的“矢量化”進行了相同的計算,因此無需使用循環(這節省了一些代碼行)。import matplotlib.animation as ani
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['figure.dpi'] = 150
## Inputs
angle = 30 # deg
angleRad = angle*np.pi/180
vel = 2 # m/s
deltat = 0.005 # s (timestep)
acc = -9.81 # m/s^2 (gravitational acc)
# Initialisations
x0 = 0
y0 = 0
ux0 = vel*np.cos(angleRad)
uy0 = vel*np.sin(angleRad)
ax = 0
ay = acc
# https://stackoverflow.com/a/64083631/2329968
def linspace(start, stop, step=1.):
"""
Like np.linspace but uses step instead of num
This is inclusive to stop, so if start=1, stop=3, step=0.5
Output is: array([1., 1.5, 2., 2.5, 3.])
"""
return np.linspace(start, stop, int((stop - start) / step + 1))
t0 = 0
tf = 1 # arbitrary value
# discretize the time with a given deltat
time = linspace(t0, tf, deltat)
# compute x-y locations
x = ux0*time + 0.5*ax*time**2
y = uy0*time + 0.5*ay*time**2
# now there is a change that y < 0 for some x.
# We need to only keep the locations and times where y >= 0.
idx = y >= 0
x = x[idx]
y = y[idx]
time = time[idx]
# compute velocities
U = ux0 + ax*time
V = uy0 + ay*time
def buildframes(i):
line.set_data(x[:i+1], y[:i+1])
points.set_offsets([x[i], y[i]])
index.set_text('time = %.3f s' % time[i])
## Plotting
fig = plt.figure()
axes = fig.add_subplot(1,1,1)
line, = axes.plot([], [], zorder=1) # , 'bo', lw=2, scalex = True, scaley = True
points = plt.scatter([], [], c='red', s=15, zorder=2)
axes.set_ylim(min(y), np.true_divide(np.ceil(max(y) * 10**2), 10**2))
axes.set_xlim(min(x), np.true_divide(np.ceil(max(x) * 10**2), 10**2))
plt.ylabel('Height')
plt.xlabel('Distance')
index = axes.annotate('', xy=(0.75, 0.95), xycoords='axes fraction')
animator = ani.FuncAnimation(fig, buildframes, frames=len(x), interval=500)
# plt.show()
animator.save('animation.gif')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.