Welcome to chaoseverywhere’s documentation!¶
This package was made as a project in the software devlopment course. The main goal here is to observe the behaviour of both the Mandelbrot set and the logistic map. And because we mainly learn with examples, detailled explanations of the objects and their construction are presented in the gallery.
Guide¶
How to install chaoseverywhere¶
Install from github¶
In order to install this package, one can simply put in the prompt:
$ pip install git+https://github.com/tanglef/chaoseverywhere
Special dependencies¶
In order to fully use this package, one must have Mayavi installed and ready to use and also the FFMPEG writer.
Mayavi: VTK and PyQt5 (or another supported GUI toolkit for Python 3) are necessary please refer to this tutorial.
FFMPEG: simply run
sudo apt install ffmpeg
if you’re using a UBUNTU distribution.
Tip
If you’re using Windows, you will need to install FFMPEG by downloading the folder of the latest version,
save it where you’d like (usually the root of the disk) and add the path to its bin
folder to the PATH environment variables.
If you’re using Windows 7/8, add a semicolon at the end of the added path.
Once you’re done, you can test your installation by running the plot_bifurcation.py
file in the \examples
directory.
Contacts¶
If you have an improvment to make or point out an error, you can fill out a pull request on Github.
One can also reach us using the emails adress right below :
Sources and some more¶
The mathematics behind and more explainations¶
La suite logistique et le chaos by Daniel Perrin,
Does God play dice by Ian Stewart,
17 equations that changed the world, chapter 16 by Ian Stewart.
Some inspiring videos¶
We sorted these links by increasing difficulty. This in no way means, that one shouldn’t consider to watch them all. They all deal with fractals and the math around them and one can learn a lot (just like us) with those.
The Mandelbrot set - Numberphile with Dr Holly Krieger,
This equation will change how you see the world by Veritasium.
The dark side of the Mandelbrot set by mathologer,
Fractals are typically not self-similar by Grant Sanderson a.k.a 3Blue1Brown
The Mandelbrot set¶
The creation¶
The Mandelbrot set \(\mathcal{M}\) is defined as :
Given the fact that it is a set of points, we can compute it using a class
Python object. Thus, determine which arguments to pass
in order to instantiate one set, and what methods to compute. What a user (you hopefully) might want to ask oneself is:
where should I center the picture of the Mandelbrot set?
do I want the whole set or just a special part? If the latest, what square exactly would I want to look at?
do I need of lot of iterations of the sequence: meaning more time to make, or can I be satisfied with a reasonable number of iterations?
Note
For only aesthetics purposes, we chose not to let the user display a rectangular part of the Mandelbrot set but only a square one.
So, the windows that will be displayed will be a square centered at the point \(a+bi\). The user will input this point separating
the real part and the imaginary part in the two arguments x
and y
. The size of the square is determined by the facteur
argument representing the half-length of the side of the square one’d like to display.
A summary to keep in mind¶
Methods | Output | ||
---|---|---|---|
numpy array | saved video | matplotlib plot | |
anim_puiss_mandel | X | ||
anim_pics_mandel | X | ||
animate_mandel_plt | X | ||
disp_mandel | X | ||
mandel_loop | X | ||
mandel_transform | X | ||
mandelbrot |
X |
The class methods¶
Additional function in the submodule¶
As part of the link with the logistic map, we needed a function that could return a stairs-like data about the different values that would take the map \(z_{n+1}=z_n^2+c\) with different values for \(c\). See the bifurcation video in the gallery for the actual plot.
One can use this function to produce the same plot in the top-right of the video in the bifurcation diagram section of the gallery using the code below.
plt.style.use(['ggplot', 'dark_background'])
data = zip(*chaos.mandel_branch_points(0,-1,50))
ax2 = plt.subplot()
x = np.linspace(-2, 1, 400)
line, = ax2.plot([],[], color='red', alpha=1, lw=4)
line.set_data(data)
courbe, = ax2.plot([], [], color='dodgerblue', alpha=1, lw=2)
courbe.set_data(x, x**2-1)
ax2.plot(x, x, color='orange')
plt.show()
The logistic map¶
Introduced by the biologist Robert May in 1976, the logistic map turned out to be a lot more complex that meets the eye.
Definitions¶
The logistic map is a recursive sequence defined as:
where \(r\in [1,4]\) is the growth ratio and with \(x_0\in[0,1]\). The goal of this module is to be able tu visualize the logistic map, but also to create its bifurcation diagram and link it to the Mandelbrot set.
The bifurcation diagram is a plot of where the logistic map tends to. It shows us that as the growth ratio approaches \(4\), the chaotic behaviour appears.
Summary of the outputs¶
Methods | Output | ||
---|---|---|---|
float | video | matplotlib plot | |
animate_logistic | X | ||
connections | X | ||
logistic | X | ||
logistic_draw | X | ||
bifurcation | X | X | |
logi_branch_points | X | ||
plot_logi_interact | X |
Some other requirements for the project¶
Sparse matrix¶
Sparse matrix are very efficient when we need to use a matrix with a lot of zeros-values. To illustrate its use, we need a function that will randomly spread numbers with a chosen density.
Pixel colors¶
When we use the mandel_loop
function, one can visualize the speed of divergence of the \((z_n)_n\) sequence.
We built an histogram representing each color for the speed of divergence on the \((0,x)\) axis and the associated
number of pixels in a chosen window on the \((0,y)\) axis.
Chaoseverywhere’s gallery !¶
In here, you will find everything you need to create your own Mandelbrot set and visualize the chaos.
Note
Click here to download the full example code
The bifurcation diagram¶
Link to the logistic map¶
It is very easy to build the bifurcation diagram of the logistic map. You only need to iterate the logistic map long enough for a value of \(r\) (\(x_{n+1}=rx_n(1-x_n)\)) and then plot the last point. The goal of iterating the sequence a lot of time is to see where the points are attracted to. If you only need the values of the bifurcation diagram and not the actual plot, only pass the value False to the argument show.
import chaoseverywhere as chaos
chaos.bifurcation(show=True)

An animated visualization¶
The bifurcation diagram surprinsgly has a link to the Mandelbrot set. Indeed, there is a bijection between the growth ratio \(r\) and value (real part) of \(c\) in the Mandelbrot formula.
Another way to look at it is: if we plot the real part of the iterates of the points in the Mandelbrot set, then we get the bifurcation diagram.
Total running time of the script: ( 0 minutes 8.175 seconds)
Note
Click here to download the full example code
Creating the classic Mandelbrot set¶
Some setup¶
import chaoseverywhere as chaos
Classic Mandelbrot¶
First, let’s compute the classic version of the mandelbrot set in black and white. It is well known that the Mandelbrot set is contained in the origin disk of radius 2 \(D((0,0),2)\), so we just iterate the formula :
with \(z_0=0\in\mathbb{C}\).
chaos.Mandelbrot_disp(0,0,2,t_max=150).disp_mandel()

Total running time of the script: ( 0 minutes 0.260 seconds)
Note
Click here to download the full example code
Sparsity over the Mandelbrot set¶
Some setup¶
import matplotlib.pyplot as plt
import chaoseverywhere as chaos
Sparsity¶
The use of projecting non-zeros values over an area to determine its area is very well known (it’s even how most of us learn the Monte-Carlo algorithm to calculate an approximation of pi). Let’s say someone needs to do the same process with the Mandelbrot set. Then, a simple way to graphically overset the two objets is like below.
fig = plt.figure()
mandel = chaos.Mandelbrot_disp(-.5,0,1.5).mandel_loop(go_up=True)
plt.imshow(mandel, cmap='Spectral')
chaos.sparse_matrix(400,400,.02)
plt.show()

Some values¶
It can be estimated that the Mandelbrot set has an area between \(1.50\) and \(1.51\). It was proved by Mitsuhiro Shishikura that the Haussdorf dimension of the boundary of the Mandelbrot set equals \(2\).
Total running time of the script: ( 0 minutes 0.373 seconds)
Note
Click here to download the full example code
An animation of the logistic function¶
The logistic map and… rabbits?¶
A commun example to understand the logistic map is to think of a pattern to simulate a population of rabbits with the most simple conditions in a multiplicativ model. Let’s consider a group made of \(x_n\) rabbits, where \(x_n\) is a percentage of the maximum number of rabbits we can have. Let’s observe them every six months (time they need to be able to produce offsprings). Then at the next observation, if we note \(r\) the growth rate of the population, there will be \(rx_n\) rabbits. However, this modelisation is wrong because it assumes that none of the rabbits died or escaped its cage to go back to the wilderness. So, a way to control this pattern is to multiply \(rx_n\) by \((1-x_n)\), a factor that, when \(x_n\) approaches it’s maximum, tends to \(0\).
Thus the equation of the logistic map is :
Let’s see how the population evolves over time depending on the growth ratio. Let’s begin with a growth ratio of \(2.5\).
import chaoseverywhere as chaos
import matplotlib.pyplot as plt
plt.style.use('ggplot')
chaos.logistic_draw(0.01, 2.5, 100, 100)
hline = plt.axhline(y=1.5/2.5, color='black', ls=':', label=r'$y=\dfrac{2.5-1}{2.5}=0.6$')
plt.legend(handles=[hline])
plt.show()

Evolution in term of r values¶
For \(r\leq 1\), our bunnies die. The sequence tends to \(0\).
For \(r\in [1,3]\), the population oscillates and then stabilizes to the value \(\frac{r-1}{r}\).
For \(r\in [3,3.57]\) the population oscillates between several values, there is no longer one attractor.
For \(r\geq 3.57\) there is almost surely a chaotic design.
Total running time of the script: ( 0 minutes 0.694 seconds)
Note
Click here to download the full example code
Animation of a zoom¶
Some Setup¶
There are multiple ways to animate a zoom with matplotlib. This package use one very close to the one below.
import chaoseverywhere as chaos
import matplotlib.pyplot as plt
import matplotlib.animation as animation
See a self-similar structure¶
The Mandelbrot set is clearly not a self-similar object. But inside it, we can see structures repeating themselves.
plt.figure()
plt.axis('off')
plt.imshow(chaos.Mandelbrot_disp(-1, -.3, 0.4-110/300,
t_max=100,
precision=400).mandelbrot(), cmap='bone')
plt.show()

One way to animate a zoom¶
im_init = chaos.Mandelbrot_disp(-.5,0,1.5)
im_init = im_init.mandelbrot()
fig = plt.figure()
im = plt.imshow(im_init, cmap='bone', animated=True)
ims = []
for i in range(150):
im = plt.imshow(chaos.Mandelbrot_disp(-1, -.3, 0.4-i/300,
t_max=100,
precision=400).mandelbrot(), animated=True, cmap='bone')
ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=50)
plt.show()
This is one way to display the animation. However, one might want a shorter way. And forntunatly, this is what this package provides.
chaos.Mandelbrot_disp(-.5,0,1.5).animate_mandel_plt()
The video¶
This package uses FFMPEG as writer to create and save this animation. Because of the symmetry, we zoomed in on the point \(-1-0.3i\) and we can play with the number of frames to end the animation with a zoom out from the point \(-1+0.3i\).
Total running time of the script: ( 0 minutes 0.189 seconds)
Note
Click here to download the full example code
Convolution and frontier of the Mandelbrot set¶
Convolution with a 2D kernel¶
Before we begin, a reminder of the 2D convolution between two matrix can be useful. In our case, we will use a \(3\times 3\) kernel. So, the convolution of a kernel with a matrix is defined as the sum of the conter-row-wise by row-wise product of the elements ie the last element of the kernel is multiplied by the first of the matrix, the penultimate of the kernel (at the left of the last) is multiplied by the seconde one of the matrix (at the right of the first) and so on from the antepenultimate to the first one. In a formula we have :
There are mutliple ways to get the edges of a shape using this method. We chose to use a kernel with only \(-1\) on its borders and a value \(k_5=8=-\sum_{i=1,\ i\neq 5}^9 k_i\). We also need to pad the image in order to get all the pixels in it, and not forget the borders. Let’s take a look at the result.
import chaoseverywhere as chaos
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import convolve2d
mandel = chaos.Mandelbrot_disp(-.5, 0, 1.5).mandelbrot()
kernel_edge_detect = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]])
pad_mandel = np.pad(mandel, ((1, 1), (1, 1)), "maximum")
bound = convolve2d(pad_mandel, kernel_edge_detect, mode='valid').astype(bool) * mandel
plt.imshow(bound, cmap='bone')
plt.axis('off')
plt.show()

Total running time of the script: ( 0 minutes 0.497 seconds)
Note
Click here to download the full example code
Creating the Mandelbrot Set with colors¶
Some setup¶
import chaoseverywhere as chaos
import matplotlib.pyplot as plt
Colored Mandelbrot¶
The second easiest way to see the Mandelbrot is not only to consider the points which are in the set, but also categorize how fast the others diverge. It is well known that the Mandelbrot set is contained in the origin disk of radius 2 \(D((0,0),2)\), so we just iterate the formula :
with \(z_0=0\in\mathbb{C}\). And the twist here is to change the value of the points whose modulus is beyond 2. Let’s consider that we affect it with the value of the current iteration. For that and because it can be time consuming to calculate the modulus of numbers in an array (mainly because of the square root), we use the formula :
And then, we don’t compare it with 2, but \(2^2\).
mandel = chaos.Mandelbrot_disp(0,0,2,t_max=150).mandel_loop(go_up=False)
fig, ax = plt.subplots()
pict = ax.imshow(mandel, cmap='cool')
fig.colorbar(pict, extend='both')
plt.show()

A little better…¶
The issue here is that chosing the iteration number creates jumps that may be not the smoothest and because \(z_0=0\) and some points take a lot of iterations to make the sequence diverge (the one near the boundary), the constrast is not really visible. In order to correct that, we have a lot of choices, let’s take \(\frac{1}{2+n}\), where \(n\) is the current iteration of the sequence. We can also see that the Mandelbrot set is symmetric with respect to the real axis.
mandel = chaos.Mandelbrot_disp(0,0,2,t_max=150).mandel_loop(go_up=True)
fig, ax = plt.subplots()
pict = ax.imshow(mandel, cmap='cool')
ax.axvline(x=200, color='black')
fig.colorbar(pict, extend='both')
plt.show()

Total running time of the script: ( 0 minutes 0.962 seconds)
Let’s play with the Mandelbrot equation¶
The Mandelbrot set with three dimensions¶
Some setup¶
import chaoseverywhere as chaos
from mayavi import mlab
Is it really a fractal in 3-dimensional fractal ?¶
The Mandelbrot set is defined by its famous equation \(z_{n+1}=z_n^2+c\). Having a 3-dimensional visualization of this set is very complex and to be considered a 3D fractal, we need to keep the fractal part of the object. We often consider the Mandelbulb as the 3-dimensional representation of the Mandelbrot set. However, we can’t make a 3D Mandelbrot set in the way we’d like to be. So in this package you won’t be able to see a Mandelbulb or some bootleg version of that can be found of it. Here we will only use the third dimension to see the speed of divergence of the points.
Construction¶
First, we define the function of the Mandelbrot set \(f(z,c):\mathbb{C}\times\mathbb{C}\longrightarrow\mathbb{C}\) as above.
def transform(z,c):
return(z**2 + c)
Then, we use the Mandelbrot_disp class in this package to create a basis for the set, and then we use mayavi to display our work.
mandel = chaos.Mandelbrot_disp(1.5,0,2.5, precision=600).mandel_transform(FUN=transform)
mlab.figure(size=(800, 800))
mlab.surf(mandel, colormap='bones', warp_scale='auto', vmax=1.5)
mlab.view(elevation=18)
mlab.close()
The Magnet 1 transformation¶
Some setup¶
import chaoseverywhere as chaos
from mayavi import mlab
import os
Transformed Mandelbrot set¶
The Mandelbrot set is defined by its famous equation \(z_{n+1}=z_n^2+c\). Now, what happens if we change that formula.
with \(z_0=0\in\mathbb{C}\).
Construction¶
First, we define the function \(f(z,c):\mathbb{C}\times\mathbb{C}\longrightarrow\mathbb{C}\) as above.
def transform(z,c):
return(((z ** 2 + c -1)/(2*z +c-2))**2)
Then, we use the Mandelbrot_disp class in this package to create a basis for the set, and then we use mayavi to display our work.
mandel = chaos.Mandelbrot_disp(1.5,0,2.5, precision=600).mandel_transform(FUN=transform)
mlab.figure(size=(800, 800))
mlab.surf(mandel, colormap='hot', warp_scale='auto', vmax=1.5)
mlab.view(elevation=180)
mlab.close()
What are we looking at ?¶
This transformation is called the Magnet (1) and represents the way magnets behave under high temperatures. It was discovered by two physicits Yang and Lee who dit not expect to see a fractal in their study.
Changing the power in the equation¶
Some setup¶
import chaoseverywhere as chaos
from mayavi import mlab
An example with a power of 4¶
The Mandelbrot set is defined by its famous equation \(z_{n+1}=z_n^2+c\). But one could rightfully ask : why \(2\) exactly ? So let’s fulfill our curious needs and see what happens if we take \(z_{n+1}=z_n^4+c\) as our equation.
Construction¶
First, we define the function of the Mandelbrot set \(f(z,c):\mathbb{C}\times\mathbb{C}\longrightarrow\mathbb{C}\) as above.
def transform(z,c):
return(z**4 + c)
Then, we use the Mandelbrot_disp class in this package to create a basis for the set, and then we use mayavi to display our work.
mandel = chaos.Mandelbrot_disp(1.5,0,2.5, precision=600).mandel_transform(FUN=transform)
mlab.figure(size=(800, 800))
mlab.surf(mandel, colormap='hot', warp_scale='auto', vmax=1.5)
mlab.view(elevation=18)
mlab.close()
We can clearly see some king of duplicates into three of Mandelbrot sets displaying themselves around the main bulb and allowing for each of them a third of the space to grow.
And for the other powers ?¶
For a power of \(2\), we see one big ramification extending over the real axis. For a power of \(4\) we see three of them. So we can conjecture that for any positive integer \(p\) as the power, we will see \(p-1\) main ramifications around the main bulb. Let’s see if that checks out for the first hundred powers.
One can reproduce this animation using the code below.
chaos.Mandelbrot_disp(0,0,2,t_max=150, precision=500).anim_puiss_mandel(remove=True)