Skip to content

Instantly share code, notes, and snippets.

@rouleur
Last active August 29, 2015 14:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rouleur/260c5a9233fff0e8ddaf to your computer and use it in GitHub Desktop.
Save rouleur/260c5a9233fff0e8ddaf to your computer and use it in GitHub Desktop.
Ulam Spiral

###Ulam Spiral with D3.js

Ulam Spiral is a way of visualising prime numbers. We start with 1 in center and continue writing numbers in a rectangular spiral. Above, numbers in yellow are prime numbers. The spiral can be thought to demonstrate prime numbers are not "that random".

For more info about Ulam Spiral you can check the Wikipedia page or this Youtube video

<!DOCTYPE html>
<html>
<head>
<title>Ulam Spiral with D3.js</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.min.js" charset="utf-8"></script>
</head>
<body bgcolor="gray">
<div id="graph" style="width: 960px; height: 500px;margin-left: auto; margin-right: auto;"></div>
</body>
<script>
var width = 960;
var height = 500;
var svg = d3.select("#graph").append("svg")
.attr("width", width)
.attr("height", height);
var dx = 20;
var dy = 20;
x0 = width / 2;
y0 = height / 2;
var size = 100;
function generateBaseArray(n) {
var result = [];
for (var i = 1; i < n; i++) {
result.push(i);
result.push(i);
result.push(-i);
result.push(-i);
}
return result;
}
var cornerCoordsForX = generateBaseArray(size);
var cornerCoordsForY = generateBaseArray(size);
cornerCoordsForX.unshift(0);
cornerCoordsForY.unshift(0, 0);
var Position = function (x, y) {
this.x = x;
this.y = y;
}
var graphData = [];
for (var i = 0; i < size; i++) {
if (graphData.length > 2) {
var last = graphData[graphData.length - 1];
if (last.x > cornerCoordsForX[i]) {
var dif = last.x - cornerCoordsForX[i];
for (var j = 1; j < dif; j++) {
graphData.push(new Position(last.x - j, cornerCoordsForY[i]));
}
}
if (last.x < cornerCoordsForX[i]) {
var dif = last.x - cornerCoordsForX[i];
for (var j = 1; j < -dif; j++) {
graphData.push(new Position(last.x + j, cornerCoordsForY[i]));
}
}
if (last.y > cornerCoordsForY[i]) {
var dif = last.y - cornerCoordsForY[i];
for (var j = 1; j < dif; j++) {
graphData.push(new Position(cornerCoordsForX[i], last.y - j));
}
}
if (last.y < cornerCoordsForY[i]) {
var dif = last.y - cornerCoordsForY[i];
for (var j = 1; j < -dif; j++) {
graphData.push(new Position(cornerCoordsForX[i], last.y + j));
}
}
}
graphData.push(new Position(cornerCoordsForX[i], cornerCoordsForY[i]));
}
var primes = [];
function isPrime(n) {
if (n == 1) return false;
var checkPoint = Math.sqrt(n);
for (var i = 0; primes[i] <= checkPoint; i++) {
if (n % primes[i] == 0) {
return false;
}
}
primes.push(n);
return true;
}
function fontSize(i) {
if (i > 998) {
return "8px";
} else if (i > 98) {
return "9px";
} else if (i > 8) {
return "10px";
} else {
return "11px";
}
}
var text = svg.selectAll("text")
.data(graphData)
.enter()
.append("text");
var textLabels = text
.attr("x", function (d) {
return d.x * dx + width / 2;
})
.attr("y", function (d) {
return d.y * dy + height / 2;
})
.text(function (d, i) {
return i + 1;
})
.attr("text-anchor", "middle")
.attr("font-family", "helvetica")
.attr("font-size", fontSize(i))
.attr("fill", function (d, i) {
if (i + 1 == 1) return "red";
if (isPrime(i + 1)) {
return "yellow";
} else {
return "black";
}
});
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment