Public
Edited
Oct 11, 2021
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function collatz(n, stoppingTime = 0) {
// Base case, n has reached 1.
if (n === 1) {
return stoppingTime;
}

// Recursive case: n is even.
if (n % 2 === 0) {
return collatz(n / 2, stoppingTime + 1);
}

// Recursive case: n is odd.
return collatz(3 * n + 1, stoppingTime + 1);
}
Insert cell
Insert cell
Insert cell
collatzScatterplot = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

// Define scales.
const x = d3
.scaleLinear()
.domain(d3.extent(dataScatterplot, (d) => d.x))
.rangeRound([margin.left, width - margin.right]);

const y = d3
.scaleLinear()
.domain(d3.extent(dataScatterplot, (d) => d.y))
.rangeRound([height - margin.bottom, margin.top]);

// Generate the scatterplot points.
svg
.append("g")
.selectAll("circle")
.data(dataScatterplot)
.join("circle")
.attr("cx", (d) => x(d.x))
.attr("cy", (d) => y(d.y))
.attr("fill", "steelblue")
.attr("r", 3);

// Define axes.
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height - 35})`)
.call(d3.axisBottom(x).tickSizeOuter(0));

xAxis
.append("text")
.attr("x", width - margin.right)
.attr("y", -10)
.attr("fill", "currentColor")
.attr("text-anchor", "end")
.attr("font-size", "0.75rem")
.attr("font-weight", "bold")
.attr("font-family", "'Helvetica Neue', sans-serif")
.text("Starting value (n)");

const yAxis = svg
.append("g")
.attr("transform", `translate(${margin.left - 5}, 0)`)
.call(d3.axisLeft(y).tickSizeOuter(0));

yAxis
.select(".tick:last-of-type text")
.clone()
.attr("x", 10)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.attr("font-size", "0.75rem")
.attr("font-family", "'Helvetica Neue', sans-serif")
.text("Stopping time");

svg.selectAll(".tick line").remove();

return svg.node();
}
Insert cell
Insert cell
collatz(9248)
Insert cell
collatz(27)
Insert cell
Insert cell
Insert cell
Insert cell
collatzHistogram = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const max = d3.max(dataHistogram);

// Generate a threshold for each stopping time value.
const thresholds = [];
for (let i = 0; i <= max; i++) {
thresholds.push(i);
}

// Apply the data to the thresholds.
const bins = d3.bin().thresholds(thresholds)(dataHistogram);

// Define scales.
const x = d3
.scaleLinear()
.domain([bins[0].x0, bins[bins.length - 1].x1])
.range([margin.left, width - margin.right]);

const y = d3
.scaleLinear()
.domain([0, d3.max(bins, (d) => d.length)])
.nice()
.range([height - margin.bottom, margin.top]);

// Generate bars for the histogram.
svg
.append("g")
.attr("fill", "steelblue")
.selectAll("rect")
.data(bins)
.join("rect")
.attr("x", (d) => x(d.x0) + 1)
.attr("width", (d) => Math.max(0, x(d.x1) - x(d.x0) - 1))
.attr("y", (d) => y(d.length))
.attr("height", (d) => y(0) - y(d.length));

// Generate axes.
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height - margin.bottom})`)
.call(
d3
.axisBottom(x)
.ticks(width / 80)
.tickSizeOuter(0)
);

xAxis
.append("text")
.attr("x", width - margin.right)
.attr("y", -15)
.attr("fill", "currentColor")
.attr("font-weight", "bold")
.attr("font-size", "0.75rem")
.attr("font-weight", "bold")
.attr("font-family", "'Helvetica Neue', sans-serif")
.attr("text-anchor", "end")
.text("Stopping time");

const yAxis = svg
.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.call(d3.axisLeft(y).tickSizeOuter(0));

yAxis
.select(".tick:last-of-type text")
.clone()
.attr("x", 10)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.attr("font-size", "0.75rem")
.attr("font-family", "'Helvetica Neue', sans-serif")
.text("Number of starting values (n) in bin");

svg.selectAll(".tick line").remove();

return svg.node();
}
Insert cell
Insert cell
Insert cell
collatzHistogramBin5 = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const max = d3.max(dataHistogram);

// Generate a threshold for each stopping time value.
const thresholds = [];
for (let i = 0; i <= max; i += 5) {
thresholds.push(i);
}

// Apply the data to the thresholds.
const bins = d3.bin().thresholds(thresholds)(dataHistogram);

// Define scales.
const x = d3
.scaleLinear()
.domain([bins[0].x0, bins[bins.length - 1].x1])
.range([margin.left, width - margin.right]);

const y = d3
.scaleLinear()
.domain([0, d3.max(bins, (d) => d.length)])
.nice()
.range([height - margin.bottom, margin.top]);

// Generate bars for the histogram.
svg
.append("g")
.attr("fill", "steelblue")
.selectAll("rect")
.data(bins)
.join("rect")
.attr("x", (d) => x(d.x0) + 1)
.attr("width", (d) => Math.max(0, x(d.x1) - x(d.x0) - 1))
.attr("y", (d) => y(d.length))
.attr("height", (d) => y(0) - y(d.length));

// Generate axes.
const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height - margin.bottom})`)
.call(
d3
.axisBottom(x)
.ticks(width / 80)
.tickSizeOuter(0)
);

xAxis
.append("text")
.attr("x", width - margin.right)
.attr("y", -15)
.attr("fill", "currentColor")
.attr("font-weight", "bold")
.attr("font-size", "0.75rem")
.attr("font-weight", "bold")
.attr("font-family", "'Helvetica Neue', sans-serif")
.attr("text-anchor", "end")
.text("Stopping time");

const yAxis = svg
.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.call(d3.axisLeft(y).tickSizeOuter(0));

yAxis
.select(".tick:last-of-type text")
.clone()
.attr("x", 10)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.attr("font-size", "0.75rem")
.attr("font-family", "'Helvetica Neue', sans-serif")
.text("Number of starting values (n) in bin");

svg.selectAll(".tick line").remove();

return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
dataHailstone = new Array(100).fill().reduce((acc, _, i) => {
const line = [];

let currentN = i + 1;

function collatz(n, iteration) {
line.push({ value: n, iteration: iteration });

if (n === 1) {
return line;
}

if (n % 2 === 0) {
return collatz(n / 2, iteration + 1);
}

return collatz(3 * n + 1, iteration + 1);
}

return [...acc, collatz(currentN, 0)];
}, [])
Insert cell
Insert cell
collatzHailstone = {
replay;
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const x = d3
.scaleLinear()
.domain(d3.extent(dataHailstone.flat().map((d) => d.iteration)))
.range([margin.left, width - margin.right]);

const y = d3
.scaleLinear()
.domain(d3.extent(dataHailstone.flat().map((d) => d.value)))
.range([height - margin.top, margin.bottom]);

const xAxis = svg
.append("g")
.attr("transform", `translate(0, ${height - margin.bottom})`)
.call(
d3
.axisBottom(x)
.ticks(width / 80)
.tickSizeOuter(0)
);

xAxis
.append("text")
.attr("x", width - margin.right)
.attr("y", -15)
.attr("fill", "currentColor")
.attr("font-weight", "bold")
.attr("font-size", "0.75rem")
.attr("font-weight", "bold")
.attr("font-family", "'Helvetica Neue', sans-serif")
.attr("text-anchor", "end")
.text("Iteration Count");

const yAxis = svg
.append("g")
.attr("transform", `translate(${margin.left}, 0)`)
.call(d3.axisLeft(y).tickSizeOuter(0));

yAxis
.select(".tick:last-of-type text")
.clone()
.attr("x", 10)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.attr("font-size", "0.75rem")
.attr("font-family", "'Helvetica Neue', sans-serif")
.text("Computation Value");

svg.selectAll(".tick line").remove();

const paths = dataHailstone.map((datum) => {
const line = d3
.line()
.curve(d3.curveBasis)
.x((d) => x(d.iteration))
.y((d) => y(d.value));

return line(datum);
});

svg
.append("g")
.selectAll(".line")
.remove()
.data(paths)
.join("path")
.attr("class", ".line")
.attr("d", (d) => d)
.attr("stroke", "steelblue")
.attr("fill", "none")
.attr("stroke-miterlimit", "1")
.attr("stroke-dasharray", "0,1")
.call(reveal);

return svg.node();
}
Insert cell
reveal = (path) =>
path.each(function (p, i) {
d3.select(this)
.transition()
.delay(i * 500)
.duration(500)
.attrTween("stroke-dasharray", function () {
const length = this.getTotalLength();
return d3.interpolate(`0,${length}`, `${length},${length}`);
});
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
height = 600
Insert cell
margin = ({ top: 40, left: 60, right: 40, bottom: 40 });
Insert cell
d3 = require('d3@6');
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more