DynamicalSystems.DynamicalSystems
— ModuleDynamicalSystems.jl is an award-winning Julia software library for nonlinear dynamics and nonlinear timeseries analysis.
To install DynamicalSystems.jl, run import Pkg; Pkg.add("DynamicalSystems")
as a Julia language command. To learn how to use it and see its contents visit the documentation, which you can either find online or build locally by running the docs/make.jl
file.
DynamicalSystems.jl is part of JuliaDynamics, an organization dedicated to creating high quality scientific software.
Highlights
Aspects of DynamicalSystems.jl that make it stand out among other codebases for nonlinear dynamics or nonlinear timeseries analysis are:
- Exceptional documentation. All implemented algorithms provide a high-level scientific description of their functionality in their documentation string as well as references to scientific papers. The documentation features hundreds of tutorials and examples ranging from introductory to expert usage.
- Accessible source code. One of the main priorities of the library is that the source code of (almost) all implementations is small, simple, easy to understand and modify. This increases confidence, reduces bugs, and allows users to become developers without unnecessary effort.
- Open source community project. Built from the ground up entirely on GitHub, DynamicalSystems.jl is 100% open source and based on community contributions. Anyone can be a developer of the library. Everyone is welcomed.
- Extensive content. It aims to cover the entire field of nonlinear dynamics and nonlinear timeseries analysis. It has functionality for complexity measures, delay embeddings, periodic orbits, nonlocal stability analysis, continuation, chaos, fractal dimensions, surrogate testing, recurrence quantification analysis, and much more. Furthermore, all algorithms are "general" and work for any dynamical system applicable. Missing functionality that falls under this wide category of content is welcomed to be part of the library!
- Well tested. All implemented functionality is extensively tested. Each time any change in the code base is done, the extensive test suite is run and checked before merging the change in.
- Extendable. DynamicalSystems.jl is a living, evolving project. New contributions can become part of the library and be accessed by all users in the next release. Most importantly, all parts of the library follow professional standards in software design and implement extendable interfaces so that it is easy to contribute new functionality.
- Active development. Since the start of the project (May 2017) there has been activity every month: new features, bugfixes, and the developer team answers users questions on official Julia language forums.
- Performant. Written entirely in Julia, heavily optimized and parallelized, and taking advantage of some of the best packages within the language, DynamicalSystems.jl is really fast.
Goals
The DynamicalSystems.jl library started as a vision with three main goals; These same goals now are the core pillars guiding development, and are largely the source of where the aforementioned unique highlights stem from.
Goal 1: Accessible and reproducible nonlinear dynamics
The first goal of the library is to make this beautiful field accessible and reproducible.
Accessible means that if you read on some sorts of fancy algorithm online in a scientific article, you should be able to use it instantly. You shouldn't have to put in the work to code it yourself. The authors of the paper already did that. So why should you do it again?! To resolve this problem we developed, and continue to develop, a library that has an incredibly low threshold of entry: contributing to DynamicalSystems.jl and making your code available to all is truly easier than coding your own algorithms from scratch, due to the well thought out and generic interfaces it provides for dynamical systems.
Reproducible means that given some sorts of dynamical systems analysis in a scientific article, you should be able to do exactly the same analysis and get exactly the same results (within some numeric precision) as the article. After all, computers are deterministic constructs. DynamicalSystems.jl allows this by (1) being written in a modern programming language with incredible environment and reproducibility support, (2) being well tested, and (3) by providing thousands of algorithms out of the box, allowing most dynamical systems analysis to be done instantly while implementing only as little new stuff as necessary.
Goal 2: Library in the literal sense
DynamicalSystems.jl is not just a software library. It is also a library in the literal sense: where people go to learn something new (here in particular for nonlinear dynamics). That is why the documentation is of exceptionally high quality: detailed descriptions and explanations of algorithms, with references to the scientific articles articles. It is also partly a reason for the source code to be written as clearly as possible, so that it is examinable by any user.
Goal 3: A general purpose software
The third goal is to fill the missing gap of a high quality general purpose software for nonlinear dynamics which can be easily extended with new functionality. This can be particularly impactful in teaching. You see, it is unfortunately rarely the case that real, runnable code is shown in the classroom, because it is often long and messy. This is especially hurtful for nonlinear dynamics, a field where computer-assisted exploration is critical.
DynamicalSystems.jl provides teachers with a framework capable of demonstrating actual, real-world nonlinear dynamics code and its output, without having to invest the weeks to code the internal infrastructure themselves. Its high level syntax requires writing little code to get lots of meaningful analysis done, while its extensive functionality covers most typical classroom applications.
DynamicalSystems.interactive_cobweb
— Functioninteractive_cobweb(ds::DiscreteDynamicalSystem, prange, O::Int = 3; kwargs...)
Launch an interactive application for exploring cobweb diagrams of 1D discrete dynamical systems. Two slides control the length of the plotted trajectory and the current parameter value. The parameter values are obtained from the given prange
.
In the cobweb plot, higher order iterates of the dynamic rule f
are plotted as well, starting from order 1 all the way to the given order O
. Both the trajectory in the cobweb, as well as any iterate f
can be turned off by using some of the buttons.
Keywords
fkwargs = [(linewidth = 4.0, color = randomcolor()) for i in 1:O]
: plotting keywords for each of the plotted iterates off
trajcolor = :black
: color of the trajectorypname = "p"
: name of the parameter sliderpindex = 1
: parameter indexxmin = 0, xmax = 1
: limits the state of the dynamical system can takeTmax = 1000
: maximum trajectory lengthx0s = range(xmin, xmax; length = 101)
: Possible values for the x0 slider.
DynamicalSystems.interactive_orbitdiagram
— Functioninteractive_orbitdiagram(
ds::DynamicalSystem, p_index, pmin, pmax, i::Int = 1;
u0 = nothing, parname = "p", title = ""
)
Open an interactive application for exploring orbit diagrams (ODs) of discrete time dynamical systems. Requires DynamicalSystems
.
In essense, the function presents the output of orbitdiagram
of the i
th variable of the ds
, and allows interactively zooming into it.
Keywords control the name of the parameter, the initial state (used for any parameter) or whether to add a title above the orbit diagram.
Interaction
The application is separated in the "OD plot" (left) and the "control panel" (right). On the OD plot you can interactively click and drag with the left mouse button to select a region in the OD. This region is then re-computed at a higher resolution.
The options at the control panel are straight-forward, with
n
amount of steps recorded for the orbit diagram (not all are in the zoomed region!)t
transient steps before starting to record stepsd
density of x-axis (the parameter axis)α
alpha value for the plotted points.
Notice that at each update n*t*d
steps are taken. You have to press update
after changing these parameters. Press reset
to bring the OD in the original state (and variable). Pressing back
will go back through the history of your exploration History is stored when the "update" button is pressed or a region is zoomed in.
You can even decide which variable to get the OD for by choosing one of the variables from the wheel! Because the y-axis limits can't be known when changing variable, they reset to the size of the selected variable.
Accessing the data
What is plotted on the application window is a true orbit diagram, not a plotting shorthand. This means that all data are obtainable and usable directly. Internally we always scale the orbit diagram to [0,1]² (to allow Float64
precision even though plotting is Float32
-based). This however means that it is necessary to transform the data in real scale. This is done through the function scaleod
which accepts the 5 arguments returned from the current function:
figure, oddata = interactive_orbitdiagram(...)
ps, us = scaleod(oddata)
DynamicalSystems.interactive_poincaresos
— Functioninteractive_poincaresos(cds, plane, idxs, complete; kwargs...)
Launch an interactive application for exploring a Poincaré surface of section (PSOS) of the continuous dynamical system cds
. Requires DynamicalSystems
.
The plane
can only be the Tuple
type accepted by DynamicalSystems.poincaresos
, i.e. (i, r)
for the i
th variable crossing the value r
. idxs
gives the two indices of the variables to be displayed, since the PSOS plot is always a 2D scatterplot. I.e. idxs = (1, 2)
will plot the 1st versus 2nd variable of the PSOS. It follows that plane[1] ∉ idxs
must be true.
complete
is a three-argument function that completes the new initial state during interactive use, see below.
The function returns: figure, laststate
with the latter being an observable containing the latest initial state
.
Keyword Arguments
direction, rootkw
: Same use as inDynamicalSystems.poincaresos
.tfinal = (1000.0, 10.0^4)
: A 2-element tuple for the range of values for the total integration time (chosen interactively).color
: A function of the system's initial condition, that returns a color to plot the new points with. The color must beRGBf/RGBAf
. A random color is chosen by default.labels = ("u₁" , "u₂")
: Scatter plot labels.scatterkwargs = ()
: Named tuple of keywords passed toscatter
.diffeq = NamedTuple()
: Any extra keyword arguments are passed intoinit
of DiffEq.
Interaction
The application is a standard scatterplot, which shows the PSOS of the system, initially using the system's u0
. Two sliders control the total evolution time and the size of the marker points (which is always in pixels).
Upon clicking within the bounds of the scatter plot your click is transformed into a new initial condition, which is further evolved and its PSOS is computed and then plotted into the scatter plot.
Your click is transformed into a full D
-dimensional initial condition through the function complete
. The first two arguments of the function are the positions of the click on the PSOS. The third argument is the value of the variable the PSOS is defined on. To be more exact, this is how the function is called:
x, y = mouseclick; z = plane[2]
newstate = complete(x, y, z)
The complete
function can throw an error for ill-conditioned x, y, z
. This will be properly handled instead of breaking the application. This newstate
is also given to the function color
that gets a new color for the new points.
DynamicalSystems.interactive_poincaresos_scan
— Functioninteractive_poincaresos_scan(A::StateSpaceSet, j::Int; kwargs...)
interactive_poincaresos_scan(As::Vector{StateSpaceSet}, j::Int; kwargs...)
Launch an interactive application for scanning a Poincare surface of section of A
like a "brain scan", where the plane that defines the section can be arbitrarily moved around via a slider. Return figure, ax3D, ax2D
.
The input dataset must be 3 dimensional, and here the crossing plane is always chosen to be when the j
-th variable of the dataset crosses a predefined value. The slider automatically gets all possible values the j
-th variable can obtain.
If given multiple datasets, the keyword colors
attributes a color to each one, e.g. colors = [JULIADYNAMICS_COLORS[mod1(i, 6)] for i in 1:length(As)]
.
The keywords linekw, scatterkw
are named tuples that are propagated as keyword arguments to the line and scatter plot respectively, while the keyword direction = -1
is propagated to the function DyamicalSystems.poincaresos
.
DynamicalSystems.interactive_trajectory
— Functioninteractive_trajectory(ds::DynamicalSystem [, u0s]; kwargs...) → fig, dsobs
Same as interactive_trajectory_timeseries
, but does not plot any timeseries only the trajectory in a (projected) state space.
DynamicalSystems.interactive_trajectory_timeseries
— Functioninteractive_trajectory_timeseries(ds::DynamicalSystem, fs, [, u0s]; kwargs...) → fig, dsobs
Create a Makie Figure
to visualize trajectories and timeseries of observables of ds
. This Figure
can also be used as an interactive GUI to enable interactive control over parameters and time evolution. It can also be used to create videos, as well as customized animations, see below.
fs
is a Vector
of "indices to observe", i.e., anything that can be given to observe_state
. Each observation index will make a timeseries plot. u0s
is a Vector
of initial conditions. Each is evolved with a unique color and displayed both as a trajectory in state space and as an observed timeseries. Elements of u0
can be either Vector{Real}
encoding a full state or Dict
to partially set a state from current state of ds
(same as in set_state!
).
The trajectories from the initial conditions in u0s
are all evolved and visualized in parallel. By default only the current state of the system is used. u0s
can be anything accepted by a ParallelDynamicalSystem
.
Return
Return fig, dsobs::DynamicalSystemObservable
. fig
is the created Figure
. dsobs
facilities the creation of custom animations and/or interactive applications, see the custom animations section below.
See also interactive_trajectory
.
Interactivity and time stepping keywords
GUI functionality is possible when the plotting backend is GLMakie
. Do using GLMakie; GLMakie.activate!()
to ensure this is the chosen backend.
add_controls = true
: Iftrue
, below the state space axis some buttons for animating the trajectories live are added:reset
: results the parallel trajectories to their initial conditionsrun
: when clicked it evolves the trajectories forwards in time indefinitely. click again to stop the evolution.step
: when clicked it evolves the trajectories forwards in time for the amount of steps chosen by the slider to its right.
add_controls
only concerns the buttons and interactivity added to the created figure.parameter_sliders = nothing
: If given, it must be a dictionary, mapping parameter indices (any valid index that can be given toset_parameter!
) to ranges of parameter values. Each combination of index and range becomes a slider that can be interactively controlled to alter a system parameter on the fly during time evolution. Below the parameter sliders, three buttons are added for GUI usage:update
: when clicked the chosen parameter values are propagated into the systemu.r.s.
: when clicked it is equivalent with clicking in order: "update", "reset", "step".reset p
: when clicked it resets
parameter_sliders
only conserns the buttons and interactivity added to the created figure.parameter_names = Dict(keys(ps) .=> string.(keys(ps)))
: Dictionary mapping parameter keys to labels. Only used ifparameter_sliders
is given.Δt
: Time step of time evolution. Defaults to 1 for discrete time, 0.01 for continuous time systems. For internal simplicity, continuous time dynamical systems are evolved non-adaptively with constant step size equal toΔt
.pause = nothing
: If given, it must be a real number. This number is given to thesleep
function, which is called between each plot update. Useful when time integration is computationally inexpensive and animation proceeds too fast.starting_step = 1
: the starting value of the "step" slider.
Visualization keywords
colors
: The color for each initial condition (and resulting trajectory and timeseries). Needs to be aVector
of equal length asu0s
.tail = 1000
: Length of plotted trajectory (in units ofΔt
).fade = 0.5
: The trajectories in state space are faded towards full transparency. The alpha channel (transparency) scales ast^fade
witht
ranging from 0 to 1 (1 being the end of the trajectory). Usefade = 1.0
for linear fading orfade = 0
for no fading. Current default makes fading progress faster at trajectory start and slower at trajectory end.markersize = 15
: Size of markers of trajectory endpoints. For discrete systems half of that is used for the trajectory tail.plotkwargs = NamedTuple()
: A named tuple of keyword arguments propagated to the state space plot (lines
for continuous,scatter
for discrete systems).plotkwargs
can also be a vector of named tuples, in which case each initial condition gets different arguments.
Statespace trajectory keywords
idxs = 1:min(length(u0s[1]), 3)
: Which variables to plot in a state space trajectory. Any index that can be given toobserve_state
can be given here.statespace_axis = true
: Whether to create and display an axis for the trajectory plot.idxs = 1:min(length(u0s[1]), 3)
: Which variables to plot in a state space trajectory. Any index that can be given toobserve_state
can be given here. If three indices are given, the trajectory plot is also 3D, otherwise 2D.lims
: A tuple of tuples (min, max) for the axis limits. If not given, they are automatically deduced by evolving each ofu0s
1000Δt
units and picking most extreme values (limits are not adjusted by default during the live animations).figure, axis
: both can be named tuples with arbitrary keywords propagated to the generation of theFigure
and state spaceAxis
instances.
Timeseries keywords
linekwargs = NamedTuple()
: Extra keywords propagated to the timeseries plots. Can also be a vector of named tuples, each one for each unique initial condition.timeseries_names
: A vector of strings with length equal tofs
giving names to the y-labels of the timeseries plots.timeseries_ylims
: A vector of 2-tuples for the lower and upper limits of the y-axis of each timeseries plot. If not given it is deduced automatically similarly tolims
.timeunit = 1
: the units of time, if any. Sets the units of the timeseries x-axis.timelabel = "time"
: label of the x-axis of the timeseries plots.
Custom animations
The second return argument dsobs
is a DynamicalSystemObservable
. The trajectories plotted in the main panel are linked to observables that are fields of the dsobs
. Specifically, the field dsobs.state_obserable
is an observable containing the final state of each of the trajectories, i.e., a vector of vectors like u0s
. dsobs.param_observable
is an observable of the system parameters. These observables are triggered by the interactive GUI buttons (the first two when the system is stepped in time, the last one when the parameters are updated). However, these observables, and hence the corresponding plotted trajectories that are map
ed from these observables, can be updated via the formal API of DynamicalSystem
:
step!(dsobs, n::Int = 1)
will step the system for n
steps of Δt
time, and only update the plot on the last step. set_parameter!(dsobs, index, value)
will update the system parameter and then trigger the parameter observable. Lastly, set_state!(dsobs, new_u [, i])
will set the i
-th system state and clear the trajectory plot to the new initial condition.
This information can be used to create custom animations and/or interactive apps. In principle, the only thing a user has to do is create new observables from the existing ones using e.g. the on
function and plot these new observables. Various examples are provided in the online documentation.
DynamicalSystems.scaleod
— Functionscaleod(oddata) -> ps, us
Given the return values of interactive_orbitdiagram
, produce orbit diagram data scaled correctly in data units. Return the data as a vector of parameter values and a vector of corresponding variable values.