Skip to content

Instantly share code, notes, and snippets.

@enjalot
Last active February 17, 2016 18:38
Show Gist options
  • Save enjalot/78e3a730e77c677e168c to your computer and use it in GitHub Desktop.
Save enjalot/78e3a730e77c677e168c to your computer and use it in GitHub Desktop.
interviewing.io: mean vs stddev
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/1.8.0/d3-legend.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
svg { width:100%; height: 100% }
path {
fill: none;
stroke-width: 3;
stroke-opacity: 0.4;
}
line.legend {
stroke: #c4c4c4;
stroke-width: 1;
}
g.cell {
cursor: pointer;
}
circle.node {
pointer-events: none;
}
line.link {
stroke: #efefef;
stroke-dasharray: 18 2;
pointer-events: none;
}
</style>
</head>
<body>
<script>
// Feel free to change or delete any of the code you see!
var svg = d3.select("body").append("svg")
var chartg = svg.append("g").attr({
transform: "translate(0, -50)"
})
var legendX = 50;
var legendY = 29;
var linesX = 0;
var linesY = 134;
var squareWidth = 10;
var squareHeight = 10;
d3.json("interviews.json", function(err, interviewees) {
//console.log(interviewees)
function ranges(mean) {
if(mean <= 4 && mean >= 3.5) {
return 4;
} else if(mean < 3.5 && mean >= 2.75) {
return 3;
} else if(mean < 2.75) {
return 2;
}
}
var matches = {};
var meanData = [] ; interviewees.forEach(function(interview, index) {
var mean = d3.mean(interview);
var stddev = d3.deviation(interview);
var points = interview.map(function(score,i) {
return {
score: score,
mean: mean,
index: index
}
})
points.mean = mean;
points.stddev = stddev;
points.index = index;
// we have several interviewees
var key = (Math.floor(mean*1000)/1000) + "::" + (Math.floor(stddev*1000)/1000);
var match = matches[key];
if(!match) matches[key] = 0;
matches[key] += 1;
points.offset = matches[key];
meanData.push(points)
})
var maxMean = d3.max(meanData, function(d) { return d.mean });
//console.log("maxMean", maxMean)
var maxStddev = d3.max(meanData, function(d) { return d.stddev });
//console.log("maxStddev", maxStddev)
var xScale = d3.scale.linear()
.domain([0, maxStddev])
.range([150, 700])
var yScale = d3.scale.linear()
.domain([1, 4])
.range([500, 100])
var colorScale = d3.scale.linear()
.domain([1, 2, 3, 4])
.range(["#ff0f5f", "#e63ba8", "#ba48d9", "#267fd3"])
svg.append("g")
.attr("class", "legendOrdinal")
.attr("transform", "translate(" + [legendX, legendY] + ")");
var legendScale = d3.scale.linear()
.domain([4,3,2,1])
.range(colorScale.range().reverse())
var legendOrdinal = d3.legend.color()
.shapeWidth(40)
.shapeHeight(40)
.shapePadding(94)
.cells(4)
.scale(legendScale);
svg.select(".legendOrdinal")
.call(legendOrdinal);
chartg.selectAll("line.legend").data(d3.range(4).reverse())
.enter().append("line").classed("legend", true)
.attr({
x1: function(d) { return linesX + xScale.range()[0]},
y1: function(d) { return yScale(d) - linesY},
x2: function(d) { return linesX + xScale.range()[1]},
y2: function(d) { return yScale(d) - linesY},
})
var meanSquares = chartg.selectAll("rect.mean")
.data(meanData, function(d) { return d.index})
meanSquares.enter().append("rect").classed("mean", true)
meanSquares.attr({
x: function(d) { return xScale(d.stddev ) + d.offset * (1+squareWidth)},
y: function(d) { return yScale(d.mean) - squareHeight/2 },
width: squareWidth,
height: squareHeight,
fill: function(d) { return colorScale(d.mean)}
}).on("click", function(d) {
console.log("clicked", d);
fade();
unfade(d);
clearForce();
addForceNodes(d);
}).on("mouseover", function(d) {
console.log(d.index, d.mean, d.stddev);
fade();
unfade(d);
clearForce();
addForceNodes(d);
})
.on("mouseout", function(d) {
unfade();
clearForce();
})
chartg.append("text")
.text("deviants")
.attr({
"font-size": "32px",
"font-family": "Open Sans, Helvetica, san-serif",
x: 495,
y: 438,
"paint-order":"stroke",
stroke: "#cfe0e7",
"stroke-width": 8,
"stroke-opacity": 0.3,
"stroke-linecap": "butt",
"stroke-linejoin": "miter",
"cursor":"pointer"
}).on("mouseover", function() {
fade();
clearForce();
chartg.selectAll("rect.mean")
.filter(function(d) { return d.stddev > 0.7072})
.attr({
opacity: 0.6,
fill: function(c) { return colorScale(c.mean)}
})
.each(function(d){
addForceNodes(d);
})
}).on("mouseout", function() {
unfade();
clearForce();
})
legendOrdinal.on("cellover", function(category){
fade();
chartg.selectAll("rect.mean")
.filter(function(d) {
var hasCat = false;
d.forEach(function(i) {
if(i.score == category) hasCat = true;
})
return hasCat;
})
.attr({
opacity: 0.6,
fill: function(c) { return colorScale(c.mean)}
})
.each(function(d){
addForceNodes(d);
})
}).on("cellout", function() {
unfade();
clearForce();
})
function unfade(d) {
var selection = chartg.selectAll("rect.mean")
if(!d) {
selection.attr({
opacity: 1,
fill: function(c) { return colorScale(c.mean)}
})
} else {
selection.filter(function(f) {
if(f === d) {
d3.select(this).attr({
opacity: 0.6,
fill: function(c) { return colorScale(c.mean)}
})
}
})
}
}
function fade() {
chartg.selectAll("rect.mean").attr({
fill: "#b7b7b7"
})
}
var xrange = xScale.range()
var width = Math.abs(xrange[1] - xrange[0]);
var yrange = yScale.range();
var height = Math.abs(yrange[0] - yrange[1]);
var forceg = chartg.append("g")
.attr("transform", "translate(" + [0,0] + ")")
var force = d3.layout.force()
.size([width, height])
.gravity(0.0)
.friction(0.89)
.charge(-5)
.linkStrength(0)
.nodes([])
.links([])
force.start()
force.on("tick", function(e) {
var k = 0.36 * e.alpha
var nodes = force.nodes();
nodes.forEach(function(t,i) {
// console.log(t.x, t.targetX)
t.x += (-t.x + t.targetX) * k;
t.y += (-t.y + t.targetY) * k;
if(t.interviewee){
t.x = t.targetX + squareWidth/2;
t.y = t.targetY;
}
})
forceg.selectAll("circle.node")
.attr({
cx: function(d) { return d.x },
cy: function(d) { return d.y }
})
forceg.selectAll("line.link")
.attr({
x1: function(d) { return d.source.x },
y1: function(d) { return d.source.y },
x2: function(d) { return d.target.x },
y2: function(d) { return d.target.y },
})
})
var removeDelay = 100;
function clearForce() {
forceg.selectAll("circle.node")
//.transition().duration(removeDelay)
//.attr({opacity: 0})
.remove();
forceg.selectAll("line.link")
//.transition().duration(removeDelay)
//.attr({opacity: 0})
.remove();
force.links([])
force.nodes([])
}
function addForceNodes(interviewee) {
var nodes = force.nodes();
var links = force.links();
console.log("links", links)
var x = xScale(interviewee.stddev) + interviewee.offset * (1+squareWidth)
var y = yScale(interviewee.mean)
//console.log("X,Y", x,y)
//generate links between mean "node" and
var source = {
index: interviewee.index,
x: x,
y: y,
px: x,
py: y,
targetX: x,
targetY: y,
mean: interviewee.mean,
stddev: interviewee.stddev,
interviewee: true,
opacity: 0,
}
nodes.push(source)
interviewee.forEach(function(d,i) {
var sx = x + 10 * Math.random() + Math.random();
var sy = y + 10 * Math.random() + Math.random();
var node = {
index: interviewee.index + "-" + i,
px: sx,
py: sy,
x: sx,
y: sy,
targetX: x,
targetY: yScale(+d.score),
mean: interviewee.mean
}
nodes.push(node)
links.push({
index: source.index + "-" + node.index,
source: source,
//source: 0,
target: node
})
})
//console.log("nodes", nodes);
var lines = forceg.selectAll("line.link")
.data(links)
lines.enter().append("line").classed("link", true)
var circles = forceg.selectAll("circle.node")
.data(nodes, function(d) { return d.index })
circles.enter().append("circle").classed("node", true)
circles.attr({
"pointer-events": "none",
r: 4,
opacity: function(d) {
if(d.opacity || d.opacity === 0) return d.opacity;
return 1;
},
fill: function(d) { return colorScale(d.mean)}
})
force.links(links)
force.nodes(nodes);
force.start()
circles.exit().remove();
}
//addForceNodes(meanData[1])
})
</script>
</body>
[[3,3,4],[3,3,3,3,3,3,4,3],[2,3,3,3,3],[3,3],[2,3,3],[4,2,4],[3,2,3,4,3,2],[3,2,4,3,2,3,2,3,4,3,3,2,4,3,4,4,3],[3,4,3,1,4,3,4,3],[4,4,3],[2,3,2],[3,3,4,3,3,4,4,2,3,4,4],[3,2,2],[2,1,3,3,2,3,2,3],[4,3,3,4,4,4],[3,4,4,3,3,3,4,3,4,2,4],[3,4,3,3,4],[3,2,3,3,2],[2,2,3,3,2,2,4,4,2,3,3],[3,3,4,3,4,4,4],[2,3],[3,3,2,3],[2,2],[3,3,3,3,3,3,2,3,3,3,4,3,2],[1,2,3,2,3,2],[1,3,3,2],[2,2,3,3],[4,3],[3,3],[3,2,2,2,3,3,3,2,2],[4,3,3],[4,3,4],[3,3,3,2,2,3,4],[3,3,4,3,2,4,4,3],[2,4,2,3],[3,4,3],[3,3,4,4,3,2,4],[4,4,4,4],[3,3,3],[4,4],[3,2,4,4,4],[3,4],[3,3,2],[4,4,4],[3,3,3,3,3,3],[3,2],[3,3,2],[3,3],[2,2,3,3,3],[3,4,3,3],[3,3],[2,2],[2,2],[3,4,3,3,3],[2,2],[3,4],[4,4,4,4,4],[4,3],[2,3],[2,2,3],[3,2,4],[2,4,3,3],[3,3],[3,3],[2,3],[4,3],[4,3]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment