Nice orbit¶
Creates a visually appealing, nice orbits of a 2d dynamical system.
Code adapted from Nice_orbits.ipynb.
All credits go to Simone Conradi; the only addition here was wrapping the code into a function and using streamjoy
to create the animation. Please consider giving the Python_Simulations repo a star!
Highlights:
- Uses
wrap_matplotlib
to automatically handle saving and closing the figure. - Uses a custom
renderer
function to create each frame of the animation.
import numpy as np
import matplotlib.pyplot as plt
from numba import njit
from streamjoy import stream, wrap_matplotlib
@njit
def meshgrid(x, y):
"""
This function replace np.meshgrid that is not supported by numba
"""
xx = np.empty(shape=(x.size, y.size), dtype=x.dtype)
yy = np.empty(shape=(x.size, y.size), dtype=y.dtype)
for j in range(y.size):
for k in range(x.size):
xx[j, k] = k # change to x[k] if indexing xy
yy[j, k] = j # change to y[j] if indexing xy
return xx, yy
@njit
def calc_orbit(n_points, a, b, n_iter):
"""
This function calculate orbits in a vectorized fashion.
-n_points: lattice of initial conditions, n_points x n_points in [-1,1]x[-1,1]
-a: first parameter of the dynamical system
-b: second parameter of the dynamical system
-n_iter: number of iterations
Return: two ndarrays: x and y coordinates of every point of every orbit.
"""
area = [[-1, 1], [-1, 1]]
x = np.linspace(area[0][0], area[0][1], n_points)
y = np.linspace(area[1][0], area[1][1], n_points)
xx, yy = meshgrid(x, y)
l_cx, l_cy = np.zeros(n_iter * n_points**2), np.zeros(n_iter * n_points**2)
for i in range(n_iter):
xx_new = np.sin(xx**2 - yy**2 + a)
yy_new = np.cos(2 * xx * yy + b)
xx = xx_new
yy = yy_new
l_cx[i * n_points**2 : (i + 1) * n_points**2] = xx.flatten()
l_cy[i * n_points**2 : (i + 1) * n_points**2] = yy.flatten()
return l_cx, l_cy
@wrap_matplotlib()
def plot_frame(n):
l_cx, l_cy = calc_orbit(n_points, a + 0.002 * n, b - 0.001 * n, n)
area = [[-1, 1], [-1, 1]]
h, _, _ = np.histogram2d(l_cx, l_cy, bins=3000, range=area)
fig, ax = plt.subplots(figsize=(10, 10))
fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=None, hspace=None)
ax.imshow(np.log(h + 1), vmin=0, vmax=5, cmap="magma")
plt.xticks([]), plt.yticks([])
return fig
if __name__ == "__main__":
n_points = 500
a, b = 5.48, 4.28
stream(np.arange(1, 100).tolist(), renderer=plot_frame, uri="nice_orbit.mp4")