Citation info: Boeing, G. 2016. "Visual Analysis of Nonlinear Dynamical Systems: Chaos, Fractals, Self-Similarity and the Limits of Prediction." Systems, 4 (4), 37. doi:10.3390/systems4040037.
Pynamical documentation: http://pynamical.readthedocs.org
Run the logistic map once each for 1000 population values evenly spaced between 0 and 1. This gives us the results of the logistic equation (y values) across the entire range of possible population values (x values). The gray diagonal line is just a plot of y=x.
In [1]:
from pynamical import cobweb_plot
import pandas as pd, numpy as np, matplotlib.pyplot as plt, IPython.display as IPdisplay, glob
from PIL import Image
%matplotlib inline
In [2]:
cobweb_plot(r=1.0, )
In [3]:
cobweb_plot(r=2.7)
In [4]:
cobweb_plot(r=3.5)
In [5]:
cobweb_plot(r=3.9)
In [6]:
cobweb_plot(r=2.7, cobweb_x=0.1)
In [7]:
cobweb_plot(r=2.7, cobweb_x=0.5)
In [8]:
cobweb_plot(r=2.7, cobweb_x=0.9)
In [9]:
# configure the animation: 70 rates between 0 and 3.999 plus 15 paused frames each at start and end
save_folder = 'images/cobweb-animate'
gif_filepath = 'images/animated-logistic-cobweb.gif'
start_r = 0
end_r = 3.999
steps = 70
rates = np.linspace(start_r, end_r, steps)
In [10]:
# create a plot for each growth rate
for n, r in enumerate(rates):
filename = '{:03d}'.format(n)
title = 'Logistic Map Cobweb Plot, r={:.2f}'.format(r)
cobweb_plot(r=r, filename=filename, folder=save_folder, dpi=90, title=title, show=False)
plt.close()
In [11]:
# create a tuple of display durations, one for each frame
first_last = 100 #show the first and last frames for 100 ms
standard_duration = 10 #show all other frames for 10 ms
durations = tuple([first_last] + [standard_duration] * (len(rates) - 2) + [first_last])
In [12]:
# load all the static images into a list then save as an animated gif
images = [Image.open(image) for image in glob.glob('{}/*.png'.format(save_folder))]
gif = images[0]
gif.info['duration'] = durations #ms per frame
gif.info['loop'] = 0 #how many times to loop (0=infinite)
gif.save(fp=gif_filepath, format='gif', save_all=True, append_images=images[1:])
In [13]:
# verify that the number of frames in the gif equals the number of image files and durations
Image.open(gif_filepath).n_frames == len(images) == len(durations)
Out[13]:
In [14]:
IPdisplay.Image(url=gif_filepath)
Out[14]: