|
<!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> |