Last active
August 29, 2015 14:09
-
-
Save avimoondra/fc7ad4c6c00b6347aba5 to your computer and use it in GitHub Desktop.
Stratified Sampling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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