Skip to content

Instantly share code, notes, and snippets.

@jgbos
Last active December 15, 2015 08:09
Show Gist options
  • Save jgbos/5228729 to your computer and use it in GitHub Desktop.
Save jgbos/5228729 to your computer and use it in GitHub Desktop.
Chaotic Dynamics

** Note this visualization takes 60s to execute **

Chaotic dynamics can be easily simulated using the Logistic Map. Given the equation:

f(x) = \lambda x (1 - x)

Define the discrete dynamics by:

  • Initialize x0 (animation uses 0.2)
  • Find f(x0) (vertical line)
  • Set new value x1 = f(x0) (horizontal line)
  • Find f(x1) = f(f(x0)) = f^2 (x0) (next vertical line)
  • keep repeat

This visualization looks at these dynamics in two ways:

  • Left plot: Blue line is f(x), orange line is f(x)=x, black line is the discrete dynamics defined above. Horizontal axis is x and the Vertical axis is f(x).
  • Right plot: This is the value of f(x) as we vary \lambda. Horizontal axis is \lambda and Vertical axis is f(x). Note that the Vertical axis is the same for both plots.

As we vary the value of \lambda in the equation above and examine the long term value of f^n(x0) (see plot on left, the x-axis is \lambda), around \lambda = 3 the value goes from converging to a fixed point to going between two numbers (period 2). As we further increase \lambda the period goes from 4, 8, 16, ..., to all over the place (chaos). Every once in awhile you will see it go periodic again, and this number can even be odd (1,3,5,..). The diagram on the left illustrates this behavior and is called the bifurcation diagram. There are many properties for this diagram that are fun to explore.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
fill: #000;
}
.curve {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.line {
fill: none;
stroke: orange;
stroke-width: 1.5px;
}
.chaos {
fill: none;
stroke: #000;
stroke-width: 1.5px;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var margin = {top: 20, right: 40, bottom: 30, left: 50},
w1 = 480 - margin.left - margin.right,
w2 = 480 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
x = d3.range(0,1.001,0.001),
y = [],
bifur = [];
// Unscaled logistic map
x.forEach(function (d){
y.push(d*(1-d));
});
var svg = d3.select("body").append("svg")
.attr("width", w1 + w2 + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
// The Cobweb Map
var g1 = svg
.append("g").attr("class","logistic")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
g1
.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(" + 0 + "," + height + ")");
g1
.append("svg:g")
.attr("class", "y axis");
var xScale = d3.scale.linear().domain([0,1]).range([0, w1]),
yScale = d3.scale.linear().domain([0,1]).range([height, 0]),
xAxis = d3.svg.axis().scale(xScale).orient("bottom"),
yAxis = d3.svg.axis().scale(yScale).orient("left");
g1.select("g.x.axis").call(xAxis);
g1.select("g.y.axis").call(yAxis);
// The Bifurcation Diagram
var g2 = svg.append("g").attr("class","bifur")
.attr("transform","translate(" + (margin.left + margin.right + w1) + "," + margin.top + ")");
g2
.append("svg:g")
.attr("class", "x2 axis")
.attr("transform", "translate(0," + height + ")");
g2
.append("svg:g")
.attr("class", "y2 axis");
var x2Scale = d3.scale.linear().domain([1,4]).range([0, w2]),
y2Scale = yScale,
x2Axis = d3.svg.axis().scale(x2Scale).orient("bottom"),
y2Axis = d3.svg.axis().scale(y2Scale).orient("left");
g2.select("g.x2.axis").call(x2Axis);
g2.select("g.y2.axis").call(y2Axis);
// The Lines
var line = d3.svg.line()
.x(function(d) { return xScale(d); })
.y(function(d) { return yScale(d); });
var curve = d3.svg.line()
.x(function(d,i) { return xScale(x[i]); })
.y(function(d) { return yScale(d); });
var lcurve = g1.selectAll("path.curve").data([y]);
lcurve.enter().append("path")
.attr("class", "curve")
.attr("d", curve);
var xy = g1.selectAll("path.line").data([x]);
xy.enter().append("path")
.attr("class", "line")
.attr("d", line);
var chaos = d3.svg.line()
.x(function(d) { return xScale(d.x); })
.y(function(d) { return yScale(d.y); });
d3.transition()
.duration(60000)
.tween("chaos", function() {
var λ = d3.interpolate(1,4);
return function(k) {
var N = bifur.length-1,
x0 = 0.2,
dynamics = [];
// Redraw logistic map curve
lcurve.attr("d",curve);
// Logistic Map Curve
curve
.y(function(d) { return yScale(λ(k)*d); });
// Calculate the dynamics f(f(f...(x))) = λ*x*(1-x)
var f = [{x: x0, y:0}]
for (var i=1; i<100 ;i++){
var last = f[f.length-1],
fx = λ(k)*last.x*(1-last.x);
f.push({x: last.x, y: fx }) ;
f.push({
x: fx,
y: fx
})
dynamics.push({x:λ(k), y:fx});
if (Math.abs(fx - last.x) < 0.001) break;
}
if (dynamics.length >= 50) dynamics.slice(dynamics.length-50,dynamics.length);
bifur = bifur.concat(dynamics);
// Bifurcation Diagram
var bf = g2.selectAll("circle").data(bifur);
bf.enter().append("circle")
.attr("r",function (d) { return 0.3;})
.attr("cx",function (d) {return x2Scale(d.x);})
.attr("cy",function (d) {return y2Scale(d.y);});
// Cobweb line
var l = g1.selectAll("path.chaos").data([f]);
l.enter().append("path")
.attr("class", "chaos")
.attr("d", chaos);
l.attr("d", chaos);
l.exit().remove();
}
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment