Skip to content

Instantly share code, notes, and snippets.

@topologicallytony
Last active December 16, 2016 21:49
Show Gist options
  • Save topologicallytony/134ac99e079e52f4cd7751d879a04a00 to your computer and use it in GitHub Desktop.
Save topologicallytony/134ac99e079e52f4cd7751d879a04a00 to your computer and use it in GitHub Desktop.
Bifurcation Diagram of the Logistic Map

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 after 1,000 iterations This visual is known as the bifrucation diagram of the logistic map

<!DOCTYPE html>
<meta charset="utf-8">
<style>
/*************************************************/
/********************Axis*************************/
/*************************************************/
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script>
//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 = 6000;
//Since the system reaches either a fixed point or a small period for r values < 3.5,
//we don't need to iterate as many times for these numbers
var smallSubset = Math.floor((2.5/3) * (numDataPoints));
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]);
}
//Iterate through 1000 times to get to fixed points/cycles where applicable
for (var j = 0; j < 10000; j++) {
for (var i = 0; i < numDataPoints; i++) {
var x = dataset[i][0];
var y = dataset[i][1];
dataset[i][1] = x * y * (1 - y);
}
}
//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;
for (var j = 0; j < 10; j++) {
for (var i = 0; i < smallSubset; i++) {
var x = dataset_temp[i][0];
var y = dataset_temp[i][1];
dataset_temp[i][1] = x * y * (1 - y);
dataset.push([x,y]);
}
}
for (var j = 0; j < 65; j++) {
for (var i = smallSubset; i < numDataPoints; i++) {
var x = dataset_temp[i][0];
var y = dataset_temp[i][1];
dataset_temp[i][1] = x * y * (1 - y);
dataset.push([x,y]);
}
}
//Create the scales used to map datapoints
var xScale = d3.scale.linear()
.domain([1,4])
.range([padding, w - padding]);
var yScale = d3.scale.linear()
.domain([0,1])
.range([h - padding, padding]);
var xScale_rev = d3.scale.linear()
.domain([padding, w - padding])
.range([1,4]);
//Create a canvas to display the chart on
var svg = d3.select("body")
.append("svg")
.attr("viewBox", "0 0 " + w + " " + h)
//.attr("id", "vis")
//svg.append("g")
// .call(d3.behavior.zoom().scaleExtent([1,8]).on("zoom", zoom));
//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');
//Plot the data
var selected_points = layer2.selectAll(".point")
.data(dataset);
selected_points.enter()
.append("circle")
.attr("r", .5)
.attr("class", "point")
.attr("fill", "#002663")
.attr("transform", function(d) { return "translate(" + xScale(d[0]) + "," + yScale(d[1]) + ")";});
//Show a vertical helper line that moves with mouse
var vertical = layer1.selectAll(".line").data([0]);
vertical.enter()
.append("line")
.attr("x1", padding)
.attr("x2", padding)
.attr("y1", padding)
.attr("y2", h-padding)
.attr("stroke-width", 2)
.attr("stroke", "black")
.attr("opacity", 0.5);
//Display the parameter value associated with vertical line
var text = layer2.selectAll(".text").data([0]);
text.enter()
.append("text")
.attr("x", padding)
.attr("y", 10)
.attr("dy", ".5em")
.attr("font-size", "32px")
.text("r = 0");
//Handle mousemove
svg
.on("mousemove", function(){
mousex = d3.mouse(this);
mousex = mousex[0];
console.log(xScale_rev(mousex).toFixed(2));
//var text = layer2.selectAll(".text").data([0]);
text.text("r = " + xScale_rev(mousex).toFixed(2));
//var vertical = layer1.selectAll(".line").data([0]);
vertical.attr("x1", mousex).attr("x2", mousex);
});
//Define axes
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(4);
//Create axes
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
//allow the user to zoom in on a portion of the viz
//function zoom() {
// svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
//}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment