-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathanimate_double_pendula.py
102 lines (92 loc) · 2.93 KB
/
animate_double_pendula.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""Animate a system of multiple double pendula, each with slightly different
initial conditions to exemplify the signficance of initial conditions in a
chaotic systems
"""
# pylint: disable=redefined-outer-name
import string
from typing import List
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
from double_pendula.double_pendula import DoublePendula
def random_hex() -> str:
"""Return a random hex color i.e. #FFFFFF"""
hex_value = "".join(
np.random.choice(
list(string.hexdigits),
6
)
)
return f"#{hex_value}"
def animate(i):
"""Annimation frame"""
# pylint: disable=used-before-assignment
time_template = 'time = %.1fs'
dt = .05
return_arr = []
for double_pendulum, ax_data in pendula_axes:
_, line, time_text = ax_data
frame_x, frame_y = double_pendulum.get_frame_coordinates(i)
line.set_data(frame_x, frame_y)
time_text.set_text(time_template % (dt*i))
return_arr.extend([
line,
time_text,
])
return return_arr
def create_axes(
fig: "matplotlib.figure.Figure",
pendula: List["DoublePendula"]
) -> List["matplotlib.axes._subplots.AxesSubplot"]:
"""Create all the individual axes for the double pendula"""
axes = []
longest_double_pendulum = max(pendula, key=lambda x: x.max_length)
for i in range(len(pendula)):
color = random_hex()
ax = _create_individual_axis(
longest_double_pendulum=longest_double_pendulum,
fig=fig,
i=i
)
line, = ax.plot([], [], 'o-', lw=2, color=color)
time_text = ax.text(0.05, 0.9, '', transform=ax.transAxes)
axes.append((ax, line, time_text))
return axes
def _create_individual_axis(
longest_double_pendulum: "DoublePendula",
fig: "matplotlib.figure.Figure",
i: int
) -> None:
"""Create dynamic axis to plot the double pendulum to"""
# HACK: adding a label to supress the MatplotlibDeprecationWarning causes
# the plot to drastically slow down so purposely not fixing that for now
# pylint: disable=unused-argument
ax = fig.add_subplot(
111,
autoscale_on=False,
xlim=(
-longest_double_pendulum.max_length,
longest_double_pendulum.max_length
),
ylim=(
-longest_double_pendulum.max_length,
longest_double_pendulum.max_length
),
)
ax.set_aspect('equal')
ax.grid()
return ax
if __name__ == "__main__":
# Create the pendula
fig = plt.figure()
pendula = DoublePendula.create_multiple_double_pendula(num_pendula=10)
axes = create_axes(fig=fig, pendula=pendula)
pendula_axes = list(zip(pendula, axes))
ani = animation.FuncAnimation(
fig,
animate,
np.arange(1, len(pendula[0].y)),
interval=25,
blit=True,
)
plt.show()