Skip to content

Instantly share code, notes, and snippets.

@carsonfarmer
Last active August 29, 2015 14:01
Show Gist options
  • Save carsonfarmer/c054595103dbd391217e to your computer and use it in GitHub Desktop.
Save carsonfarmer/c054595103dbd391217e to your computer and use it in GitHub Desktop.
Halton Sequence for Pseudo-random Points

Halton Sequence for Pseudo-random Points

May 18th, 2014 - Carson Farmer

The two point patterns here are the first 256 points from a 2, 3 Halton Sequence (left), and 256 points from a uniform random point process (right).

Halton sequences are often used to generate points in space for numerical methods such as Monte Carlo simulations. Although these sequences are deterministic they are of low discrepancy, which means they appear to be random for many purposes. A particularly useful property of Halton sequences (and some other pseudo-random sequences) is that they have have a better coverage of the underlying space than 'true' random sequences. This is particularly useful for creating things like dot density maps, where we want a random feel without leaving gaps across the space (which may arise with random numbers).

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<style type="text/css">
.random circle {
fill: blue;
}
.halton circle {
fill: green;
}
text {
font-size: 18px;
text-anchor: middle;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var padding = 25,
width = 960,
height = 500;
var n = 256, // number of circles to add
haltonCircles = haltonGenerator(n)
randomCircles = randomGenerator(n)
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
var haltonCircle = svg.append('g')
.attr('class', 'halton')
.attr("transform", "translate(" + padding + "," + padding + ")")
.selectAll("circle")
.data(haltonCircles)
haltonCircle.enter().append("circle")
.attr("cx", function(d) { return d[0] * (width/2-padding*2); })
.attr("cy", function(d) { return d[1] * (height-padding*4); })
.attr("r", 2)
.style("fill-opacity", (Math.random() + .5) / 2)
.transition()
.attr("r", 5);
haltonCircle.enter().append("text")
.text("256 Points from 2, 3 Halton Sequence")
.attr("dx", width/4)
.attr("dy", height-padding-25)
var randomCircle = svg.append('g')
.attr('class', 'random')
.attr("transform", "translate(" + (width/2 + padding) + "," + padding + ")")
.selectAll("circle")
.data(randomCircles)
randomCircle.enter().append("circle")
.attr("cx", function(d) { return d[0] * (width/2-padding*2); })
.attr("cy", function(d) { return d[1] * (height-padding*4); })
.attr("r", 2)
.style("fill-opacity", (Math.random() + .5) / 2)
.transition()
.attr("r", 5);
randomCircle.enter().append("text")
.text("256 Uniform Random Points")
.attr("dx", width/4)
.attr("dy", height-padding-25)
function randomGenerator(numpts) {
var points = [];
for (var i = 0; i < numpts; i++) {
points.push([Math.random(), Math.random()]);
}
return points;
};
// The code comes from:
// https://gist.github.com/bpeck/1889735
// For more info see:
// http://en.wikipedia.org/wiki/Halton_sequence
function halton(index, base) {
var result = 0;
var f = 1 / base;
var i = index;
while(i > 0) {
result = result + f * (i % base);
i = Math.floor(i / base);
f = f / base;
}
return result;
};
function haltonGenerator(numpts, basex, basey) {
// 2, 3 Halton Sequence by default
if (basex == null)
basex = 2;
if (basey == null)
basey = 3;
var points = [];
for (var i = 0; i < numpts; i++) {
points.push([halton(i,basex), halton(i,basey)]);
}
return points;
};
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment