Skip to content

Instantly share code, notes, and snippets.

@avimoondra
Last active August 29, 2015 14:09
Show Gist options
  • Save avimoondra/fc7ad4c6c00b6347aba5 to your computer and use it in GitHub Desktop.
Save avimoondra/fc7ad4c6c00b6347aba5 to your computer and use it in GitHub Desktop.
Stratified Sampling
<!DOCTYPE html>
<html lang="en">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="http://d3js.org/d3.v3.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8">
</head>
<body>
<style type="text/css">
#svgWrapper {
display: inline-block;
}
#panelWrapper {
width: 200px;
border: solid #808080 1px;
padding: 10px;
display: inline-block;
position: fixed;
margin-top: 10px;
}
.separator {
margin-bottom: 10px;
height: 1px;
background-color: #808080;
}
</style>
<div>
<div id="svgWrapper">
<svg width="800", height="400"></svg>
</div>
<div id="panelWrapper">
<div>
<p> Stratified Sampling </p>
<div class="separator"></div>
<p> <b>Step 1.</b> Group cases by color into 4 stratum:
<button id="button_strata" type="button" class="btn btn-primary btn-xs"> Stratify </button>
</p>
<p> <b>Step 2.</b> Randomly sample 6 cases from each selected stratum, collecting a total of 24 cases:
<button id="button_resample" type="button" class="btn btn-primary btn-xs disabled"> Sample </button>
</p>
<div class="separator"></div>
<button id="button_reset" class="btn btn-primary btn-xs disabled"> Reset </button>
</div>
</div>
</div>
<script type="text/javascript">
var resetAction = function(){
var svg = d3.select("svg");
generate_data();
svg.selectAll("circle").remove();
svg.selectAll("text").remove();
var circles = svg.selectAll("circle")
.data(dataPoints)
.enter()
.append("circle");
circles.attr("cx", function(d, i) {
return d["randCx"]; })
.attr("cy", function(d, i) {
return d["randCy"]; })
.attr("r", function(d, i){
return d["r"]; })
.attr("class", function(d, i){
return d["class"]; })
.attr("color_name", function(d, i){
return d["color_name"]; })
.style("fill", function(d, i){
return d["color"]; });
};
// buttons
d3.select("#button_strata").on("click", function(){
var svg = d3.select("svg");
strataByColor(svg);
d3.select("#button_strata").classed("disabled", true)
d3.select("#button_resample").classed("disabled", false);
});
d3.select("#button_resample").on("click", function(){
var svg = d3.select("svg");
selectSamples(svg);
d3.select("#button_resample").classed("disabled", true);
d3.select("#button_reset").classed("disabled", false);
});
d3.select("#button_reset").on("click", function(){
resetAction();
d3.select("#button_reset").classed("disabled", true);
d3.select("#button_strata").classed("disabled", false);
});
// SVG
var svg = d3.select("svg")
var svgViewBoxWidth = svg.attr("width")
var svgViewBoxHeight = svg.attr("height")
var svgViewBoxWidth = 800; //internal coordinate system for width, height
var svgViewBoxHeight = 400;
var svgWidth = (848 - 200); // actual width, height
var svgHeight = (svgViewBoxHeight / svgViewBoxWidth) * (svgWidth)
var svg = d3.select("svg")
.attr("width", svgWidth)
.attr("height", svgHeight)
.attr("viewBox","0 0 " + svgViewBoxWidth + " " + svgViewBoxHeight);
pointRadius = 3;
strataRadius = 80;
populationSize = 100;
sampleSize = 24;
var xScale = d3.scale.linear()
.domain([0, svgViewBoxWidth])
.range([pointRadius, svgViewBoxWidth - pointRadius]);
var yScale = d3.scale.linear()
.domain([0, svgViewBoxHeight])
.range([pointRadius, svgViewBoxHeight - pointRadius]);
// colors
blue = "#569BBD";
green = "#4C721D";
black = "#000000";
yellow = "#F4DC00";
colors = [blue, green, black, yellow];
color_names = ["blue","green","black","yellow"];
gray = "#808080";
red = "#F05133";
// generate data
dataStratas = [];
dataPoints = [];
var generate_data = function(){
dataStratas = [];
dataPoints = [];
// generate stratas
for( var i = 0; i < colors.length; i++){
strata = {
"cx": (i * ((svgViewBoxWidth) / colors.length) + strataRadius + 20),
"cy": (svgViewBoxHeight/2),
"r": strataRadius,
"color": colors[i],
"class": "strataCircle"
};
dataStratas.push(strata);
}
//generate points
for(var i = 0; i < populationSize; i++){
index = Math.floor(Math.random()*colors.length);
strata = dataStratas[index]
randAngle = Math.random() * 2 * Math.PI;
randRadius = Math.random() * (strata["r"] - 5);
point = {
"randCx": xScale(Math.random() * svgViewBoxWidth),
"randCy": yScale(Math.random() * svgViewBoxHeight),
"strataCx": randRadius * Math.cos(randAngle) + strata["cx"],
"strataCy": randRadius * Math.sin(randAngle) + strata["cy"],
"color": colors[index],
"color_name": color_names[index],
"r": pointRadius,
"class": "pointCircle"
}
dataPoints.push(point);
}
};
// strata by color
var strataByColor = function(svg){
svg.selectAll(".selectedPointFill").remove();
svg.selectAll(".selectedPointStroke").remove();
svg.selectAll(".pointCircle")
.transition()
.attr("cx", function(d, i) {
return d["strataCx"]; })
.attr("cy", function(d, i) {
return d["strataCy"]; })
var stratas = svg.selectAll(".strataCircle")
.data(dataStratas)
.enter()
.append("circle")
stratas.attr("cx", function(d, i){
return d["cx"]; })
.attr("cy", function(d, i){
return d["cy"]; })
.attr("r", function(d, i){
return d["r"]; })
.attr("class", function(d, i){
return d["class"]; })
.style("fill-opacity", 0)
.style("stroke-width", 2)
.style("stroke", gray);
var text = svg.selectAll("text")
.data(dataStratas)
.enter().append("text")
.text(function(d, i) {
return "Strata " + (i + 1); })
.attr("x", function(d, i){
return d["cx"]; })
.attr("y", function(d, i){
return d["cy"] + d["r"] + 20; })
.attr("font-family", "sans-serif")
.attr("font-size", 15)
.attr("fill", gray)
.attr("text-anchor", "middle");
};
// sample from stratas
var sampleWithoutReplacement = function(arr, num_samples){
samples = []
for(i = 0; i < num_samples; i++){
var index = Math.floor(Math.random()*arr.length);
samples.push(arr.splice(index, 1)[0]);
}
return samples;
}
var selectSamples = function(svg){
svg.selectAll(".selectedPointFill").remove();
svg.selectAll(".selectedPointStroke").remove();
for(var i = 0; i < colors.length; i++){
var circles = svg.selectAll("[color_name=" + color_names[i] + "]");
var samples = sampleWithoutReplacement(circles[0], sampleSize/colors.length);
for(var j = 0; j < samples.length; j++){
selectedPoint = d3.select(samples[j])
svg.append("circle")
.attr("class", "selectedPointFill")
.attr("cx", selectedPoint.attr("cx"))
.attr("cy", selectedPoint.attr("cy"))
.attr("r", pointRadius)
.style("fill", red);
svg.append("circle")
.attr("class", "selectedPointStroke")
.attr("cx", selectedPoint.attr("cx"))
.attr("cy", selectedPoint.attr("cy"))
.attr("r", pointRadius + 2)
.style("fill-opacity",0)
.style("stroke-width",1)
.style("stroke", red);
}
}
};
resetAction();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment