Skip to content

Instantly share code, notes, and snippets.

@topologicallytony
Last active January 8, 2017 01:34
Show Gist options
  • Save topologicallytony/f95a2c9f89c387409707eba0c5602844 to your computer and use it in GitHub Desktop.
Save topologicallytony/f95a2c9f89c387409707eba0c5602844 to your computer and use it in GitHub Desktop.
Animated Logistic Map Bifurcation Diagram

Simulates the long term behavior of the logistic map, xn+1 = rxn(1-xn).
x-axis varies the parameter r, y-axis shows the value of the function This visual is known as the bifrucation diagram of the logistic map Every click iterates the function one time I like this version because it gives you a better sense for the actual behavior of the function and the cycles it creates.
Try double or quadruple clicking to see which points remain fixed (i.e. what points are a part of 2 or 4 cycles) This the transitions also give you a sense of how a point in a cycle gets moved to the next point in the cycle

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Animated Logistic Map Bifurcation Diagram</title>
<!-- D3.js -->
<script src="https://d3js.org/d3.v4.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<style type="text/css">
.point {
r: 2;
fill: steelblue;
}
</style>
</head>
<body>
<div>
Click to Iterate
</div>
<script type="text/javascript">
//Width and height of the visualization. Smaller numbers will zoom in, larger numbers zoom out
var w = 3000;
var h = 1500;
//padding creates a buffer of white space around the chart to make it a little easier to look at
var padding = 150;
//Generate Base Dataset
//This will hold the final simulated data
var dataset = [];
//This is used for holding an individual iteration
var dataset_temp = [];
//How finely to partition [1,4]
var numDataPoints = 5000;
//Generate a random sample of the space
for (var i = 0; i < numDataPoints; i++) {
//Partition [1,4] into 4000 buckets
var x = ((i * 3) / (numDataPoints - 1)) + 1;
//Initialize the input as random numbers. This will iterate over time, so it doesn't matter what it holds
var y = Math.random();
dataset.push([x, y]);
dataset_temp.push([x, y]);
}
var xScale = d3.scaleLinear()
.domain([1, 4])
.range([padding, w - padding]);
var yScale = d3.scaleLinear()
.domain([0, 1])
.range([h - padding, padding]);
//Create a canvas to display the chart on
var svg = d3.select("body")
.append("svg")
.attr("viewBox", "0 0 " + w + " " + h)
//Make the background of the canvas white
svg.append("rect")
.attr("width", "100%")
.attr("height", "100%")
.attr("fill", "#fff");
//Create group elements to layer the svg
//This is an easy way to make sure things you want on top are on top, and things you want behind stay behind
var layer1 = svg.append('g');
var layer2 = svg.append('g');
function iterate(numRecords) {
//Load the dataset with a simulation of 64 calls to the logistic map
//This will pick up on any cycles <=64 or display chaotic behavior
dataset_temp = dataset;
dataset = [];
for (var j = 0; j < numRecords; j++) {
for (var i = 0; i < numDataPoints; i++) {
var x = dataset_temp[i][0];
var y = dataset_temp[i][1];
var y_new = x * y * (1 - y);
dataset_temp[i][1] = y_new;
dataset.push([x, y_new]);
}
}
}
function display() {
//Plot the data
var selected_points = layer2.selectAll(".point")
.data(dataset, function(d, i) {
return i;
});
selected_points.transition().duration(2500).delay(5)
.attr("transform", function(d) {
return "translate(" + xScale(d[0]) + "," + yScale(d[1]) + ")";
})
selected_points.enter()
.append("circle")
.attr("class", "point")
.attr("transform", function(d) {
return "translate(" + xScale(d[0]) + "," + yScale(d[1]) + ")";
});
selected_points.exit().remove();
var text = layer2.selectAll(".text").data([it_no]);
text.text(it_no);
text.enter()
.append("text")
.attr("x", padding)
.attr("y", 30)
.attr("dy", ".5em")
.attr("font-size", "64px")
.text("0")
.attr("class", "text");
}
display();
var it_no = 0;
// on click transition states
function update() {
it_no++;
dataset = dataset_temp;
iterate(1);
display();
}
d3.select("body")
.on("click", update);
d3.select("body")
.on("touchstart", update);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment