Skip to content

Instantly share code, notes, and snippets.

@avimoondra
Last active August 29, 2015 14:09
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 avimoondra/ebefde2695cc87dcd093 to your computer and use it in GitHub Desktop.
Save avimoondra/ebefde2695cc87dcd093 to your computer and use it in GitHub Desktop.
Cluster 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;
}
svg .clust_circle {
stroke: #808080;
fill-opacity: 0;
stroke-width: 2px;
}
svg .selected_cluster {
stroke-dasharray: 10 10;
stroke: #F05133;
}
svg .selected_point_fill {
fill: #F05133;
}
svg .selected_point_stroke {
stroke: #F05133;
fill-opacity: 0;
stroke-width: 1px;
}
</style>
<div >
<div id="svgWrapper" >
<svg></svg>
</div>
<div id="panelWrapper">
<div>
<p> Cluster Sampling </p>
<div class="separator"></div>
<p> <b>Step 1.</b> Identify clusters in the data by location.
<button id="button_draw_clusters" type="button" class="btn btn-primary btn-xs"> Identify Clusters </button>
</p>
<p> <b>Step 2.</b> Randomly select 3 clusters to sample from:
<button id="button_select_clusters" type="button" class="btn btn-primary btn-xs disabled"> Select Clusters </button>
</p>
<p> <b>Step 3.</b> Randomly sample 8 cases from each selected cluster, 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 reset_action = 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["clust_cx"]; })
.attr("cy", function(d, i) {
return d["clust_cy"]; })
.attr("r", function(d, i){
return d["r"]; })
.attr("class", function(d, i){
return d["class"]; })
.style("fill", function(d, i){
return d["color"]; });
};
// SVG
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;
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";
yellow = "#F4DC00";
red = "#F05133";
black = "#000000";
gray = "#808080";
colors = [blue, green, black, yellow];
color_names = ["blue","green","black","yellow"];
// generate data
populationSize = 100;
sampleSize = 24;
numClustersToSample = 3;
numSamplesPerCluster = sampleSize / numClustersToSample;
// generate clusters
dataClusters = [];
clusterRadius = 65;
numPointsInCluster = [17,16,12,15,16,15,17,11,21]
clusterCoordsCx = [0.17, 0.19, 0.52, 0.85, 1, 1.22, 1.46, 1.79, 1.82];
clusterCoordsCy = [0.3, 0.75, 0.5, 0.26, 0.73, 0.38, 0.67, 0.25, 0.7];
num_clusters = clusterCoordsCx.length;
var clusterXScale = d3.scale.linear().domain([0, 2]).range([0, svgViewBoxWidth])
for( var i = 0; i < num_clusters; i++){
cluster = {
"cx": parseInt(clusterXScale(clusterCoordsCx[i])),
"cy": parseInt(clusterXScale(clusterCoordsCy[i])),
"r": clusterRadius,
"class": "clust_circle",
"num_points": numPointsInCluster[i],
"id": "clust-" + i
};
dataClusters.push(cluster);
}
dataPoints = [];
var generate_data = function(){
dataPoints = [];
//generate points
for(var i = 0; i < num_clusters; i++){
cluster = dataClusters[i]
for(var j = 0; j < cluster["num_points"]; j++){
randAngle = Math.random() * 2 * Math.PI;
randRadius = Math.random() * (cluster["r"] - 5);
point = {
"clust_cx": randRadius * Math.cos(randAngle) + cluster["cx"],
"clust_cy": randRadius * Math.sin(randAngle) + cluster["cy"],
"color": colors[Math.floor(Math.random()*colors.length)],
"r": pointRadius,
"class": "point_circle " + cluster["id"]
}
dataPoints.push(point);
}
}
};
var sample_without_replacement = 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 draw_clusters = function(){
var clusters = svg.selectAll(".clust_circle")
.data(dataClusters)
.enter()
.append("circle")
clusters.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"]; })
.attr("id", function(d, i){
return d["id"]; });
var text = svg.selectAll("text")
.data(dataClusters)
.enter()
.append("text")
.text(function(d, i) {
return "cluster " + (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");
};
var select_clusters = function(){
var svg = d3.select("svg");
svg.selectAll(".selected_points").remove();
svg.selectAll(".selected_cluster").classed("selected_cluster", false)
var circles = svg.selectAll(".clust_circle")
samples = sample_without_replacement(circles[0], numClustersToSample);
for(var i = 0; i < samples.length; i++){
select_cluster = d3.select(samples[i]);
select_cluster.classed("selected_cluster", true);
}
};
var select_samples = function(){
var svg = d3.select("svg");
svg.selectAll(".selected_point_fill").remove();
svg.selectAll(".selected_point_stroke").remove();
var clusters = svg.selectAll(".selected_cluster")[0];
for(var i = 0; i < clusters.length; i++){
cluster = d3.select(clusters[i])
var points = svg.selectAll("." + cluster.attr("id"))[0]
samples = sample_without_replacement(points, numSamplesPerCluster);
for(var j = 0; j < samples.length; j++){
selected_point = d3.select(samples[j])
svg.append("circle")
.attr("class", "selected_point_fill")
.attr("cx", selected_point.attr("cx"))
.attr("cy", selected_point.attr("cy"))
.attr("r",pointRadius);
svg.append("circle")
.attr("class", "selected_point_stroke")
.attr("cx", selected_point.attr("cx"))
.attr("cy", selected_point.attr("cy"))
.attr("r",pointRadius + 2);
}
}
};
d3.select("#button_draw_clusters").on("click", function(){
draw_clusters(svg);
d3.select("#button_draw_clusters").classed("disabled", true)
d3.select("#button_select_clusters").classed("disabled", false);
});
d3.select("#button_select_clusters").on("click", function(){
select_clusters(svg);
d3.select("#button_select_clusters").classed("disabled", true)
d3.select("#button_resample").classed("disabled", false);
});
d3.select("#button_resample").on("click", function(){
select_samples(svg);
d3.select("#button_resample").classed("disabled", true)
d3.select("#button_reset").classed("disabled", false);
});
d3.select("#button_reset").on("click", function(){
reset_action();
d3.select("#button_reset").classed("disabled", true)
d3.select("#button_draw_clusters").classed("disabled", false);
});
reset_action();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment