This page was generated from examples/rossler-attractor.ipynb. Interactive online version: (Warning: The interactions will be much laggier on Binder than on your computer.) Binder badge.

Rössler attractor

See https://en.wikipedia.org/wiki/R%C3%B6ssler_attractor

\begin{cases} \frac{dx}{dt} = -y - z \\ \frac{dy}{dt} = x + ay \\ \frac{dz}{dt} = b + z(x-c) \end{cases}
[ ]:
%matplotlib ipympl
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
from scipy.integrate import solve_ivp

import mpl_interactions.ipyplot as iplt

Define function to plot

Projecting on axes

The Rossler attractor is a 3 dimensional system, but as 3D plots are not yet supported by mpl_interactions we will only visualize the x and y components.

Note: Matplotlib supports 3D plots, but mpl_interactions does not yet support them. That makes this a great place to contribute to mpl_interactions if you’re interested in doing so. If you want to have a crack at it feel free to comment on https://github.com/ianhi/mpl-interactions/issues/89 and @ianhi will be happy to help you through the process.

Caching

One thing to note here is that mpl_interactions will cache function calls for a given set of parameters so that the same function isn’t called multiple times if you are plotting it on multiple axes. However, that cache will not persist as the parameters are modified. So here we can build in our own cache to speed up execution

[ ]:
t_span = [0, 500]
t_eval = np.linspace(0, 500, 1550)
x0 = 0
y0 = 0
z0 = 0

cache = {}


def f(a, b, c):
    def deriv(t, cur_pos):
        x, y, z = cur_pos
        dxdt = -y - z
        dydt = x + a * y
        dzdt = b + z * (x - c)
        return [dxdt, dydt, dzdt]

    id_ = (float(a), float(b), float(c))
    if id_ not in cache:
        out = solve_ivp(deriv, t_span, y0=[x0, y0, z0], t_eval=t_eval).y[:2]
        cache[id_] = out
    else:
        out = cache[id_]
    return out.T  # requires shape (N, 2)
[ ]:
fig, ax = plt.subplots()
controls = iplt.plot(
    f,
    ".-",
    a=(0.05, 0.3, 1000),
    b=0.2,
    c=(1, 20),
    parametric=True,
    alpha=0.5,
    play_buttons=True,
    play_button_pos="left",
    ylim="auto",
    xlim="auto",
)

Coloring by time point

When we plot using plot we can’t choose colors for individual points, so we can use the scatter function to color the points by the time point they have.

The only difference to the function we used for plot is that we had to rename the c argument to f as c is reserved by scatter for setting the colors of the points.

[ ]:
# use a different argument for c because `c` is an argument to plt.scatter
out = widgets.Output()
display(out)


def f(a, b, c_):
    def deriv(t, cur_pos):
        x, y, z = cur_pos
        dxdt = -y - z
        dydt = x + a * y
        dzdt = b + z * (x - c_)
        return [dxdt, dydt, dzdt]

    id_ = (float(a), float(b), float(c_))
    if id_ not in cache:
        out = solve_ivp(deriv, t_span, y0=[0, 1, 0], t_eval=t_eval).y[:2]
        cache[id_] = out
    else:
        out = cache[id_]
    return out.T  # requires shape (N, 2)


fig, ax = plt.subplots()
controls = iplt.scatter(
    f,
    a=(0.05, 0.3, 1000),
    b=0.2,
    c_=(1, 20),
    parametric=True,
    alpha=0.5,
    play_buttons=True,
    play_button_pos="left",
    s=8,
    c=t_eval,
)
controls = iplt.plot(
    f,
    "-",
    controls=controls,
    parametric=True,
    alpha=0.5,
    ylim="auto",
    xlim="auto",
)
plt.colorbar().set_label("Time Point")
plt.tight_layout()
[ ]: