Public
Edited
Mar 6, 2018
4 stars
Insert cell
md`# Chaos 2
This is taking the [logistic equation](https://beta.observablehq.com/@ahojsenn/chaos-example) a little further, building something to look into stable and chaotic regions...
<br>
N(t+1) = &lambda;*N(t)*(1-N(t))
<br>
<div class="plot">
xMouse = <span id="xMouse-value">xxx</span>
yMouse = <span id="yMouse-value">xxx</span>
<br>`
Insert cell
myForm = html`<form>
<input type="range" id="xMin"
min="1.1"
max="3.999"
step="0.001"
value="2.4">
xMin = <span id="xMin-value">2.0</span>
<br>
<input type="range" id="xMax"
min="3.2"
max="4"
step="0.001"
value="4">
xMax = <span id="xMax-value">4.0</span>
</form>`
Insert cell
html`<svg class="chart" height="300"></svg> <svg id="histogram" ></svg>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
var yMax = 1,
yMin = 0,
iterations = 100,
rectSize = 5,
xMin = 1,
xMax = 4;

var data = generateData (xMin, xMax, iterations);
plotBifurcationChart (data);

//
// select and update the slider for xMin
//
d3.select("#xMin")
.on("input", function() {
xMin = (this.value < xMax) ? this.value : xMax*0.9999;
d3.select("#xMin-value").text(+xMin);
data = generateData (xMin, xMax, iterations);
plotBifurcationChart (data);
});

//
// select and update the slider for xMax
//
d3.select("#xMax")
.on("input", function() {
xMax = (this.value > xMin) ? this.value : xMin*1.0001;
d3.select("#xMax-value").text(+xMax);
data = generateData (xMin, xMax, iterations);
plotBifurcationChart (data);
});

//
// get document.width
//
function getDocumentWidth () {
// get document width , this is from the internet...
var width = document.width;
if (width === undefined) {
// if document width fails, e.g., this page http://jblevins.org/projects/markdown-mode/
// then find the biggest element available to grab width
var widthElt = (document.getElementsByTagName('html')[0] ||
document.getElementsByTagName('body')[0] ||
document.querySelector('*'));

// use widthElt’s width or worst-case fallback to the window
width = widthElt ? widthElt.offsetWidth : window.innerWidth;
}
return width;
}

//
// this funditon creates the chaotic data
//
function generateData (xMin, xMax, iterations) {
var myArray = [],
point = {},
lambda = xMin,
y=0.01;
do {
for (var i=0; i<iterations; i++) {
y = lambda * y * (1.0-y);
point = {"x": lambda, "y": y };
myArray.push (point);
}
lambda = lambda*1.0+(xMax-xMin)/iterations;
y=0.01;
} while (lambda < xMax)
return myArray;
}

//
// plot the Bifurkationsgraf
//
function plotBifurcationChart (data) {
var
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 0.85*getDocumentWidth()/2 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;

d3.select("g").remove(); // remove old svg 'g' elements

var chart = d3.select(".chart")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleLinear()
.range([0, width])
.domain([xMin, xMax]);
var y = d3.scaleLinear()
// .domain([0, d3.max(data, function(d) { return d.y; })])
.range([height, 0])
.domain([yMin, d3.max(data, function(d) { return d.y; }) ]);

/*
the axis
*/
var xAxis = g => g
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x))
.call(g => g.select(".domain").remove())
.call(g => g.append("text")
.attr("x", width - margin.right)
.attr("y", -4)
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(data.x))
var yAxis = g => g
.attr("transform", `translate(0,0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.append("text")
.attr("fill", "#000")
.attr("x", 5)
.attr("y", margin.top)
.attr("dy", "0.32em")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))

chart
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", width)
.attr("y", 18)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("lambda");


chart
.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -40)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("y");

/*
the circes
*/
var bar = chart.selectAll("bar")
.data(data)
.enter();
var circle = bar.append("circle")
.attr("class", "crc")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.attr("r", 3 );

/*
the mouse positiion
*/
var chart = d3.select(".chart");
chart.on("mouseout",
function () {
chart.selectAll(".redLine").remove();
})
chart.on("mousemove",
// drawRedLine
function () {
var mx = d3.mouse(this)[0],
my = d3.mouse(this)[1];
chart.selectAll(".redLine").remove();
d3.select("#xMouse-value").text(mx)
d3.select("#yMouse-value").text(my)
//console.log (d3.mouse(this));
chart
.append ("path")
.attr("class", "redLine")
.attr("stroke", "red")
.attr("d", "M "+mx+","+(height+margin.top)+",L "+mx+","+0+" Z");
chart
.append ("text")
.attr("class", "redLine")
.text( Math.round(10000*x.invert(mx-margin.left))/10000 )
.attr("x", mx+2)
.attr("y", 0)
.attr("dy", ".75em")
.attr("fill", "red")
.attr("text-anchor", "left")
.style("font", "12px sans-serif");
var histogram = new Histogram1D ( yMin, yMax, 100);
var tmpx = x.invert(mx-margin.left);
var tmpData = generateData (tmpx, tmpx, 2000);
for (var i = 0; i< tmpData.length; i++) {
//console.log ("filling: "+ tmpData[i].y );
histogram.fill (tmpData[i].y);
}
//histogram.plot();
plotHistogram ( histogram );
}
);
}




//
// plot a Histogram
//
function plotHistogram (histogram) {

//console.log ("in plotHistogram: " + histogram.bins[4]);
var
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 0.85*getDocumentWidth()/2 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;

d3.select("#histogram g").remove(); // remove old svg 'g' elements

var histogramDiv = d3.select("#histogram")
//let histogramDiv = d3.select(DOM.svg(width + margin.left + margin.right, height + margin.top + margin.bottom))
//.attr("id", "histogram")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleLinear()
.range([0, width])
.domain([histogram.xMin, histogram.xMax]);
var y = d3.scaleLinear()
// .domain([0, d3.max(data, function(d) { return d.y; })])
.range([height, 0])
.domain([0, d3.max(histogram.bins) ]);
/*
the axis
*/
var xAxis = g => g
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x))
.call(g => g.select(".domain").remove())
.call(g => g.append("text")
.attr("x", width - margin.right)
.attr("y", -4)
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(data.x))
var yAxis = g => g
.attr("transform", `translate(0,0)`)
.call(d3.axisLeft(y))
.call(g => g.select(".domain").remove())
.call(g => g.append("text")
.attr("fill", "#000")
.attr("x", 5)
.attr("y", margin.top)
.attr("dy", "0.32em")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))

histogramDiv
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", width)
.attr("y", 18)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("distribution of y");;

histogramDiv
.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -40)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("y");

var lineFunction = d3.line()
.x(function (d,i) { return x(i/histogram.nBins); })
.y(function (d,i) { return y(d)});
histogramDiv.append("path")
.attr("d", lineFunction(histogram.bins) )
.attr('stroke', 'blue')
.attr('stroke-width', 2)
.attr('fill', 'none');

// textbox stats
histogramDiv.append("text")
// .attr("class", "axis")
.attr("y", 10)
.attr("x", 10)
.append("tspan")
.text("N: " + histogram.nEntries)
.append("tspan")
.text("underflow: " + histogram.underflow)
.attr("x", 10)
.attr("dy", 10)
.append("tspan")
.text("overflow: " + histogram.overflow)
.attr("x", 10)
.attr("dy", 10)
.append("tspan")
.text("average: " + Math.round (histogram.average*100)/100)
.attr("x", 10)
.attr("dy", 10);

}

}
Insert cell
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more