Last active
August 29, 2015 14:09
-
-
Save avimoondra/ebefde2695cc87dcd093 to your computer and use it in GitHub Desktop.
Cluster Sampling
This file contains 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; | |
} | |
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