Skip to content

Instantly share code, notes, and snippets.

@GerardoFurtado
Last active December 20, 2015 00:38
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 GerardoFurtado/0011d805666b18f92aea to your computer and use it in GitHub Desktop.
Save GerardoFurtado/0011d805666b18f92aea to your computer and use it in GitHub Desktop.
The walk of PI
<!DOCTYPE html>
<html lang="en">
<head>
<link href='https://fonts.googleapis.com/css?family=PT+Serif' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
<meta charset="utf-8">
<title>The Walk of PI</title>
<style type="text/css">
body {
background-color: white;
font-family: 'PT Serif', serif;
}
#container {
width: 1000px;
margin-left: auto;
margin-right: auto;
margin-top: 20px;
padding: 1px 10px 10px 10px;
background-color: white;
box-shadow: 1px 1px 1px 1px #fff;
}
h1 {
font-weight: 300;
color: #5C2751;
font-family: 'Roboto', sans-serif;
font-size: 40px;
margin-bottom: 20px;
margin-top: 30px;
padding-left: 50px;
}
p {
font-size: 15px;
/*width: 1000px;*/
margin-top: 5px;
padding-left: 50px;
padding-right: 50px;
margin-bottom: 5px;
}
.code {
display: inline-block;
font-family: courier;
font-size: 14px;
border: gray solid 1px;
border-radius: 5px;
background-color: whitesmoke;
margin-bottom: 10px;
margin-top: 10px;
margin-left: 50px;
padding-left: 10px;
padding-right: 10px;
padding-top: 5px;
padding-bottom: 5px;
}
a {
color: #5C2751;
}
a:hover {
color: steelblue;
}
.footer {
font-size: 14px;
margin-top: 0px;
}
line:hover {
stroke-width: 3px;
stroke: maroon;
}
circle:hover {
fill: maroon;
}
.button {
border-top: 1px solid #ffffff;
background: #ffffff;
background: -webkit-gradient(linear, left top, left bottom, from(#d4d4d4), to(#ffffff));
background: -webkit-linear-gradient(top, #d4d4d4, #ffffff);
background: -moz-linear-gradient(top, #d4d4d4, #ffffff);
background: -ms-linear-gradient(top, #d4d4d4, #ffffff);
background: -o-linear-gradient(top, #d4d4d4, #ffffff);
padding: 5px 10px;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
color: #262426;
font-size: 14px;
font-family: "PT Sans";
text-decoration: none;
vertical-align: middle;
margin-right: 10px;
margin-bottom: 10px;
margin-top: 10px;
}
.button:hover {
border-top-color: #bfc4c7;
background: #cfd4d7;
color: #000000;
cursor: pointer;
}
.button:active {
border-top-color: #ffffff;
background: #ffffff;
}
.button:focus {
outline: 0;
}
.btn-group {
padding-left: 250px;
}
svg {
background-color: whitesmoke;
margin-left: auto;
margin-right: auto;
display: block;
border: 1px solid gray;
}
</style>
<script type="text/javascript" src="http://d3js.org/d3.v3.js" charset="utf-8"></script>
</head>
<body>
<div id="container">
<h1>The Walk of PI</h1>
<p>This is my humble version of the "Walk of PI" using D3 JavaScript. The "walk of numbers" is a method of visualizing numbers, described <a href="https://www.carma.newcastle.edu.au/jon/numtools.pdf">in this paper</a>. In my version I didn't use billions of digits, or millions of digits: I used only 2216 digits of PI, in base 8 (octal).</p>
<p>Use your mouse or trackpad to zoom and drag the path, and click “reset zoom” to, well, reset zoom. Hover the path to check the digits of PI. When the walk finishes, click “draw again” to restart the walk.</p>
<div class="btn-group" data-toggle="buttons-radio">
<button type="button" id="redraw" class="button">Draw again</button>
<button type="button" id="nozoom" class="button">Reset zoom</button>
</div>
<div id="svganchor"></div>
<br>
<p>What is this “walk of PI”? Imagine that you put a colour marker in a blank canvas. Each digit of PI, in succession, will dictate how you move the marker on the canvas.</p>
<p>This is how I made it:</p>
<p>First, I loaded a string with the digits of PI in base 8, or octal. After that, I created an array with all the digits of PI:</p>
<p class="code">var digitsofpi = pi.split("");</p>
<p> I chose octal because, starting on a given pixel, there are 8 adjoining pixels: up-left, up, up-right, right, down-right, down, down-left and left. So, starting exactly at the centre of my canvas, each digit of PI (in octal) will make the path grow, according to the following rule:</p>
<pre class="code">1 2 3
0 or. 4
7 6 5</pre>
<p>Where <em>or.</em> means “origin”. That is, if the next digit of PI is 1, the path moves up-left. If the next digit is 4, the path moves right. If the next digit is 6, the path moves down, and so on. Given x1 and y1 as initial coordinates and x2 and y2 as final coordinates, this is the code:</p>
<pre class="code">if (digitsofpi[i] == "1") {
x2 = x1 - 1; y2 = y1 - 1;
} else if (digitsofpi[i] == "2") {
x2 = x1; y2 = y1 - 1;
} else if (digitsofpi[i] == "3") {
x2 = x1 + 1; y2 = y1 - 1;
} else if (digitsofpi[i] == "4") {
x2 = x1 + 1; y2 = y1;
} else if (digitsofpi[i] == "5") {
x2 = x1 + 1; y2 = y1 + 1;
} else if (digitsofpi[i] == "6") {
x2 = x1; y2 = y1 + 1;
} else if (digitsofpi[i] == "7") {
x2 = x1 - 1; y2 = y1 + 1;
} else if (digitsofpi[i] == "0") {
x2 = x1 - 1; y2 = y1
} else {
return;
}</pre>
<p>After each line being appended, the final coordinates are the initial coordinates for the next line:</p>
<pre class="code">x1 = x2;
y1 = y2;</pre>
<p>Also, each “move”, that is, each new digit of PI changes the colour of the line according to an RGB rule: red is up, blue is down-left and green is down-right. Using the variables “r”, “g” and “b”:</p>
<p class="code">var color = d3.rgb(r, g, b);</p>
<p>I’m still looking for a source of PI in octal with more than 2 thousand digits. When I find it I’ll update this walk.</p>
<br>
<p class="footer">Created by Gerardo Furtado.</p>
</div>
<script type="text/javascript">
//set up width and height
var w = 500;
var h = 500;
//set scales
var xScale = d3.scale.linear()
.range([0, w])
.domain([170, 330]);
var yScale = d3.scale.linear()
.range([0, h])
.domain([170, 330]);
//this is PI in base 4. This is NOT a number, but a string
var pi = "31103755242102643021514230630505600670163211220111602105147630720020273724616611633104505120207461615002335737124315474647220615460126051557445742415647741152665552434110571102665354611363754336423041351514337553260577727133364015337557343415376655211477226564762202137045437714444503145075471055475604001745612054357602630664440660705272346464426177243751114753740662535107562435331303430571526101025225671732512203560455131553160606523445274460023613506601062414041370312202744305615547073707171671301401641401633117016427300364243732705273701572305131167425713755125300561407145244574725125527121272211414230764024200527121626505252610266551461341501050172147241251032573707135144731756050105433373605212724705272720301437331627037026467036230752772656431554111475343643112340224225414734734364423032645671537422777201554612020623303540116317544152310510371261402736620014567604272567514127266167023043005655450670404342237201647132546120755533771603750410711340550440522204100021516217011247417633274207063204136672266232316062343032572342170152243203226605205732113017516242532423164333567413330115721676227216770120375754524612076131216471536005663154513117501103035042147350303121267637550766045134147342657276700675656610270110071500064422372554055251447323524610661767340606777337344412330043646764153444640050222215541772551511743402330165156262300231066754456507473075564336757617762401526636246073456663405720230001535301522476662011754061057134475410313242214332175557536371542473242316331353166513543366677424217633141124546310050521127536572046767075000467431512772630171200343113445663601456502564271035007722026574715635177366652571601364323003101265520400614400543447454747622776766176436310724572374333144213701707242667776541326124572401731053202522526310755537537510703540246305732203700067701236270536736246761450015207254273370566473365241250754241767774165431631306430475253466453311730273624543107037764327334360043200207643663077220603560453745526605564351533464517443633337021262722434446742277562744160735745552446267706330575423203473446156435710145332154735140035017647577053742176644535573223327220443143525330716132711725501502166435025761622740434361331370716545133617755613737441101";
//creates an array with all digits of PI
var digitsofpi = pi.split("");
//D3 zoom
var zoom = d3.behavior.zoom();
//this will be set to "true" when the walk finishes
var finished;
var svg = d3.select("#svganchor")
.append("svg")
.attr("width", w)
.attr("height", h)
.call(zoom.on("zoom", function () {
svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")")
}))
.append("g");
//the "zoom" button
d3.select("#nozoom").on("click", function () {
svg.attr("transform", "translate(0,0)" + " scale(1)");
zoom.scale(1);
zoom.translate([0, 0])
});
//the "drawn again" button
d3.select("#redraw").on("click", function() {
if (finished == true) {
svg.selectAll("*").remove();
drawn();
}
});
//creates the walk
function drawn() {
//it has not finished
finished = false;
//this circle marks the start
circor = svg.append("circle")
.attr("cy", yScale(250))
.attr("cx", xScale(250))
.attr("r", 200)
.attr("fill", "lavender")
.attr("stroke", "#222222");
circor.transition()
.duration(1000)
.attr("r", 3);
circor.append("title")
.text("This is the origin");
//r, g and b will be used on RGB colors
var r = 125, g = 125, b = 125;
//the origin of the walk
var x1 = 250;
var y1 = 250;
//creating the loop
var maxloops = digitsofpi.length;
var i = -1;
(function loop() {
if (i++ > maxloops) return;
setTimeout(function() {
if (digitsofpi[i] == "1") {
x2 = x1 - 1; y2 = y1 - 1; r = r + 1; g = g - 1;
} else if (digitsofpi[i] == "2") {
y2 = y1 - 1; r = r + 1; b = b - 1; g = g - 1;
} else if (digitsofpi[i] == "3") {
x2 = x1 + 1; y2 = y1 - 1; r = r + 1; b = b - 1;
} else if (digitsofpi[i] == "4") {
x2 = x1 + 1; b = b - 1; g = g + 1;
} else if (digitsofpi[i] == "5") {
x2 = x1 + 1; y2 = y1 + 1; r = r - 1; g = g + 1;
} else if (digitsofpi[i] == "6") {
y2 = y1 + 1; r = r - 1; b = b + 1; g = g + 1;
} else if (digitsofpi[i] == "7") {
x2 = x1 - 1; y2 = y1 + 1; r = r - 1; b = b + 1;
} else if (digitsofpi[i] == "0") {
x2 = x1 - 1; b = b + 1; g = g - 1;
} else {
return;
}
var color = d3.rgb(r, g, b);
var lines = svg.append("line")
.attr("stroke", color)
.attr("x1", xScale(x1))
.attr("y1", yScale(y1))
.attr("x2", xScale(x2))
.attr("y2", yScale(y2))
.append("title")
.text("This is the digit " + (i + 1) + " of PI. It's a number " + digitsofpi[i]);
//the end of a line is the beginning of a new one
x1 = x2;
y1 = y2;
loop();
//time for each loop, in millisec
}, 10);
//when finished, creates another circle
if (i == maxloops) {
circend = svg.append("circle")
.attr("cy", yScale(y2))
.attr("cx", xScale(x2))
.attr("r", 200)
.attr("fill", "lavender")
.attr("stroke", "#222222");
circend.transition()
.duration(1000)
.attr("r", 3);
circend.append("title")
.text("This is the end");
finished = true;
};
//end of loop:
})();
};
drawn();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment