Skip to content

Commit 7fbde72

Browse files
authored
Add Lorenz attractor example to tests and tag v0.9.1 (#37)
1 parent e073617 commit 7fbde72

File tree

3 files changed

+74
-3
lines changed

3 files changed

+74
-3
lines changed

matplotloom/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from .loom import Loom
66

7-
__version__ = "0.9.0"
7+
__version__ = "0.9.1"
88
__all__ = ["Loom"]
99

1010

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "matplotloom"
7-
version = "0.9.0"
7+
version = "0.9.1"
88
description = "Weave your frames into matplotlib animations."
99
authors = [
1010
{ name = "ali-ramadhan", email = "ali.hh.ramadhan@gmail.com" }

tests/test_examples.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
import datetime
2+
from dataclasses import dataclass, field
23

34
import numpy as np
45
import matplotlib.pyplot as plt
56
import cartopy.crs as ccrs
67

78

89
from cmocean import cm
9-
1010
from cartopy.feature.nightshade import Nightshade
1111
from joblib import Parallel, delayed
12+
from matplotlib.colors import Normalize
13+
from mpl_toolkits.mplot3d.art3d import Line3DCollection
1214
from scipy.integrate import solve_ivp
1315
from scipy.special import j0
1416
from tqdm import tqdm
1517

18+
1619
from matplotloom import Loom
1720

1821
def test_sine_wave(test_output_dir):
@@ -252,3 +255,71 @@ def plot_frame(day_of_year, loom, frame_number):
252255

253256
assert (test_output_dir / "test_night_time_shading.mp4").is_file()
254257
assert (test_output_dir / "test_night_time_shading.mp4").stat().st_size > 0
258+
259+
def test_lorenz(test_output_dir):
260+
@dataclass
261+
class Lorenz:
262+
dt: float = 0.01
263+
sigma: float = 10.0
264+
rho: float = 28.0
265+
beta: float = 8.0 / 3.0
266+
x: float = 1.0
267+
y: float = 1.0
268+
z: float = 1.0
269+
270+
def step(self):
271+
dx = self.sigma * (self.y - self.x)
272+
dy = self.x * (self.rho - self.z) - self.y
273+
dz = self.x * self.y - self.beta * self.z
274+
self.x += dx * self.dt
275+
self.y += dy * self.dt
276+
self.z += dz * self.dt
277+
278+
@property
279+
def position(self) -> tuple[float, float, float]:
280+
return self.x, self.y, self.z
281+
282+
@dataclass
283+
class LorenzPlotter:
284+
steps_per_frame: int = 20
285+
attractor = Lorenz()
286+
points: list[tuple[float, float, float]] = field(default_factory=list)
287+
288+
def initialize(self, steps: int):
289+
self.points = [self.attractor.position]
290+
for _ in range(steps):
291+
self.attractor.step()
292+
self.points.append(self.attractor.position)
293+
294+
@property
295+
def frames(self) -> list[int]:
296+
return list(range(1, len(self.points) // self.steps_per_frame))
297+
298+
def get_frame(self, i: int, loom: Loom):
299+
fig, ax = plt.subplots(figsize=(12, 8), subplot_kw={'projection': '3d'})
300+
points = np.array(self.points[: i * self.steps_per_frame])
301+
xs, ys, zs = points.T
302+
segments = np.array([points[:-1], points[1:]]).transpose(1, 0, 2)
303+
norm = Normalize(vmin=0, vmax=len(xs))
304+
colors = plt.get_cmap('inferno')(norm(np.arange(len(xs) - 1)))
305+
lc = Line3DCollection(segments, colors=colors, linewidth=0.5)
306+
ax.add_collection3d(lc)
307+
ax.set_xlim(-30, 30)
308+
ax.set_ylim(-30, 30)
309+
ax.set_zlim(0, 50)
310+
ax.view_init(
311+
azim=(np.pi * 1.7 + 0.8 * np.sin(2.0 * np.pi * i * self.steps_per_frame / len(self.frames) / 10))
312+
* 180.0
313+
/ np.pi
314+
)
315+
ax.set_axis_off()
316+
ax.grid(visible=False)
317+
loom.save_frame(fig, i - 1)
318+
319+
with Loom(test_output_dir / 'test_lorenz.mp4', fps=60, parallel=True) as loom:
320+
attractor = LorenzPlotter()
321+
attractor.initialize(1000)
322+
Parallel(n_jobs=-1)(delayed(attractor.get_frame)(i, loom) for i in attractor.frames[:5])
323+
324+
assert (test_output_dir / "test_lorenz.mp4").is_file()
325+
assert (test_output_dir / "test_lorenz.mp4").stat().st_size > 0

0 commit comments

Comments
 (0)