var sk_margin = {t:30, r:20, b:30, l:50 },
w = 600 - sk_margin.l - sk_margin.r,
h = 450 - sk_margin.t - sk_margin.b;
var sk_trans = 1500;
var sk_color = d3.scale.ordinal()
.range(['#880000','#325C74']);
sk_radius=6;
var sk_transparency = d3.scale.sqrt().range([1,1]);
var sk_svg = d3.select("#scatterChart").append("svg")
.attr("width", w + sk_margin.l + sk_margin.r)
.attr("height", h + sk_margin.t + sk_margin.b);
var sk_xAxis = d3.svg.axis()
.ticks(6)
.tickSubdivide(4)
.tickSize(6, 4, 0)
.orient("bottom");
var sk_yAxis = d3.svg.axis()
.ticks(10)
.tickSubdivide(4)
.tickSize(6, 4, 0)
.orient("left");
var plus = d3.format("+");
var comma = d3.format(",");
var percent = d3.format("+%f");
var sk_groups = sk_svg.append("g").attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")");
var scatter_data;
d3.csv("analysis.csv", function(data) {
window.scatter_data=data;
initialize(scatter_data);
});
var guide_data = [{ x_adjust:20, y_adjust:1.99, text:"+99%"},{ x_adjust:20, y_adjust:1.95, text:"+95%"},{ x_adjust:20, y_adjust:1.9, text:"+90%"},{ x_adjust:20, y_adjust:1.8, text:"+80%"},{ x_adjust:20, y_adjust:1.6, text:"+60%"},{ x_adjust:20, y_adjust:1.4, text:"+40%"},{ x_adjust:20, y_adjust:1.2, text:"+20%"},{ x_adjust:30, y_adjust:1, text:"+0%"},{ x_adjust:20, y_adjust:.8, text:"-20%"},{ x_adjust:20, y_adjust:.6, text:"-40%"},{ x_adjust:20, y_adjust:.4, text:"-60%"},{ x_adjust:20, y_adjust:.2, text:"-80%"},{ x_adjust:20, y_adjust:.1, text:"-90%"},{ x_adjust:20, y_adjust:.05, text:"-95%"},{ x_adjust:20, y_adjust:.01, text:"-99%"},];
function scatterplot(data,signal){
data = dataPrepare(data,signal);
if(signal ===1){
var sk_x = d3.scale.sqrt().range([0, w]),
sk_y = d3.scale.sqrt().range([h - sk_margin.b - 10,0]);
sk_x.domain([0, d3.max(data, function(d) { return parseFloat(d.x_plot); })*1.15]);
sk_y.domain([0, d3.max(data, function(d) { return parseFloat(d.y_plot); })*1.1]);
sk_yAxis.scale(sk_y).tickFormat(comma);
}else{
var sk_x = d3.scale.sqrt().range([0, w]),
sk_y = d3.scale.linear().range([h - sk_margin.b - 10,0]);
sk_x.domain([0, d3.max(data, function(d) { return parseFloat(d.x_plot); })*1.15]);
sk_y.domain([-1,1]);
sk_yAxis.scale(sk_y).tickFormat(percent);
}
var sk_expect_max = d3.max(data, function(d) { return parseFloat(d.x_plot); });
sk_xAxis.scale(sk_x);
sk_transparency.domain([d3.min(data, function(d) { return parseFloat(d.x_plot); }),d3.max(data, function(d) { return parseFloat(d.x_plot); })])
guides
.transition().duration(sk_trans)
.attr("class", function(d){return d.y_adjust ===1 ? "trendline guides" :"compline guides"})
.attr('x1',sk_x(0) )
.attr('x2',sk_x(sk_expect_max))
.attr('y1',function(d){return signal===1 ? sk_y(0): sk_y((1-d.y_adjust)*-1) ;} )
.attr('y2',function(d){ return signal===1 ? sk_y(sk_expect_max * d.y_adjust) : sk_y((1-d.y_adjust)*-1) ; });
var guide_text = sk_svg.selectAll(".guide_text")
.data(guide_data);
guide_text.enter().append("text")
.attr("class","guide_text")
.attr("x", function(d){return w+d.x_adjust})
.text(function(d){return d.text;});
guide_text
.transition().duration(sk_trans)
.attr("y", function(d){ return sk_y(sk_expect_max * d.y_adjust)+30; });
sk_svg.selectAll(".guide_text.spare")
.transition().duration(sk_trans)
.attr("y",function(){return signal ===1 ? 10 :-1000 ;});
// style the circles, set their locations based on data
var sk_circles =
sk_groups.selectAll("circle");
sk_circles
.transition().duration(sk_trans)
.attr({
cx: function(d) { return sk_x(+d.x_plot); },
cy: function(d) { return sk_y(+d.y_plot); },
})
.style("fill", function(d) { return sk_color(d.union); })
.style("opacity",function(d){
if(signal ===1){
return 1;
}else{
return sk_transparency(d.x_plot);
} })
;
sk_circles.on("mouseover",mouseOn)
.on("mouseout",mouseOff);
// what to do when we mouse over a bubble
function mouseOn() {
var sk_circle = d3.select(this);
// transition to increase size/opacity of bubble
sk_circle.transition()
.duration(800).style("opacity", 1)
.attr("r", 20).ease("elastic");
// append lines to bubbles that will be used to show the precise data points.
// translate their location based on margins
sk_svg.append("g")
.attr("class", "guide")
.append("line")
.attr("x1", sk_circle.attr("cx"))
.attr("x2", sk_circle.attr("cx"))
.attr("y1", +sk_circle.attr("cy") )
.attr("y2", h-30)
.attr("transform", "translate(50,20)")
.style("stroke", sk_circle.style("fill"))
.transition().delay(200).duration(400).styleTween("opacity",
function() { return d3.interpolate(0, .5); });
sk_svg.append("g")
.data(data)
.attr("class", "guide")
.append("line")
.attr("x1", +sk_circle.attr("cx") )
.attr("x2", 0)
.attr("y1", sk_circle.attr("cy"))
.attr("y2", sk_circle.attr("cy"))
.attr("transform", "translate(50,30)")
.style("stroke", sk_circle.style("fill"))
.transition().delay(200).duration(400).styleTween("opacity",
function() { return d3.interpolate(0, .5); });
// function to move mouseover item to front of SVG stage, in case
// another bubble overlaps it
d3.selection.prototype.moveToFront = function() {
return this.each(function() {
this.parentNode.appendChild(this);
});
};
};
// what happens when we leave a bubble?
function mouseOff() {
var sk_circle = d3.select(this);
// go back to original size and opacity
sk_circle.transition()
.duration(800)
.style("opacity",function(d){
if(scatterClicker ===1){
return 1;
}else{
return sk_transparency(d.x_plot);
} })
.attr("r", sk_radius).ease("elastic");
// fade out guide lines, then remove them
d3.selectAll(".guide").transition().duration(100).styleTween("opacity",
function() { return d3.interpolate(.5, 0); })
.remove()
};
// tooltips (using jQuery plugin tipsy)
sk_circles;
$(".circles").tipsy({
gravity: 's',
html: 'true'
});
xxAxis.transition()
.duration(sk_trans).call(sk_xAxis);
yyAxis.transition()
.duration(sk_trans).call(sk_yAxis);
};
function initialize(scatter_data){
var data=dataPrepare(scatter_data,1);
var sk_circles =
sk_groups.selectAll("circle")
.data(data);
sk_circles.enter().append("circle")
.attr({
class: function(d){return "circles "+d.state;},
r: sk_radius,
id: function(d) { return d.state; },
cy:2000,
})
.append("title")
.attr("class","tipsies")
.text(function(d) { return ''+d.state+'' + '
' +'Actual: '+ comma(d.y_plot)+ '
' +"Expected: "+comma(d.x_plot) +'
'+'Rate: '+ plus(d3.round((1- (+d.perform))*-100,2))+'%'; });
scatterplot(data,1);
}
function dataPrepare(data,signal){
if(signal ===1){
for(d in data){
data[d].x_plot = Math.round(data[d].expected_fatal);
data[d].y_plot = data[d].actual_fatal;
data[d].perform = Math.round(data[d].perform*100)/100;
}
}else{
for(d in data){
data[d].x_plot = Math.round(data[d].expected_fatal);
data[d].y_plot = data[d].perform-1;
data[d].perform = Math.round(data[d].perform*100)/100;
}
}
return data;
}
// draw axes and axis labels
var xxAxis = sk_svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(" + sk_margin.l + "," + (h-10) + ")");
var yyAxis = sk_svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")");
var guides = sk_svg.selectAll(".complines.guides")
.data(guide_data);
guides.enter().append("line")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")");
sk_svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", w + 50)
.attr("y", h - 15)
.text("Expected Deaths");
sk_svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("x", -20)
.attr("y", 55)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Actual Deaths");
sk_svg.append("text")
.text("Below Expected")
.attr("class","scatter_lab")
.attr("x", 280)
.attr("y", 325);
/*sk_svg.append("rect")
.attr("class","rectback")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("x", 100)
.attr("y", 80)
.attr("width",140)
.attr("height",19)
.style({
fill:"white",
opacity:.5
});*/
sk_svg.append("text")
.text("Above Expected")
.attr("class","scatter_lab")
.attr("x", 220)
.attr("y", 90);
sk_svg.append("line")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("class", "trendlinekey")
.attr('x1',0)
.attr('x2',30)
.attr('y1',h-10)
.attr('y2',h-10);
sk_svg.append("text")
.attr("class","chartkey")
.text("Expected workplace deaths based on national averages.")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("x", 32)
.attr("y", h-6);
sk_svg.append("circle")
.attr("class","chartkey")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("cx", 10)
.attr("cy", h+8)
.attr("r",5)
.style("fill","#880000")
.style("stroke","black");
sk_svg.append("circle")
.attr("class","chartkey")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("cx", 140)
.attr("cy", h+8)
.attr("r",5)
.style("fill","#325C74")
.style("stroke","black");
sk_svg.append("text")
.attr("class","chartkey")
.text("Right-to-work state")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("x", 20)
.attr("y", h+12);
sk_svg.append("text")
.attr("class","chartkey")
.text("Closed-shop state")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("x", 150)
.attr("y", h+12);
/*Spares along the top*/
sk_svg.append("rect")
.attr("x",400)
.attr("y",0)
.attr("width",150)
.attr("height",12)
.style("fill","white");
sk_svg.append("text")
.attr("class","guide_text spare")
.text("+20%")
.style("font-size","11px")
.attr("x", w-5);
sk_svg.append("text")
.attr("class","guide_text spare")
.text("+40%")
.style("font-size","11px")
.attr("x", w-40);
sk_svg.append("text")
.attr("class","guide_text spare")
.text("+60%")
.style("font-size","11px")
.attr("x", w-70);
sk_svg.append("text")
.attr("class","guide_text spare")
.text("+99%")
.attr("x", w-115)
.style("font-size","10px");
sk_svg.append("circle")
.attr("cx",463)
.attr("cy",h+20)
.attr("r",5)
.style("fill","#880000")
.style("stroke","black")
.style("stroke-width",1);
sk_svg.append("image")
.attr("xlink:href", "cursor.png")
.attr("x",436)
.attr("y",h+18)
.attr("width",30)
.attr("height",30);
sk_svg.append("text")
.attr("class","chartkey")
.text("Touch for")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("x", 420)
.attr("y", h);
sk_svg.append("text")
.attr("class","chartkey")
.text("more info.")
.attr("transform", "translate(" + sk_margin.l + "," + sk_margin.t + ")")
.attr("x", 422)
.attr("y", h+12);
var scatterClicker =1;
$('.scatterSelect').click(function(){
if(scatterClicker===1){
scatterplot(scatter_data,0);
scatterClicker = 0;
$('.scatterSelect').text("View Totals");
}else{
scatterplot(scatter_data,1);
scatterClicker = 1;
$('.scatterSelect').text("View Rates");
}
} );