|
var WIDTH = 800, // width of the graph |
|
HEIGHT = 550, // height of the graph |
|
MARGINS = {top: 20, right: 20, bottom: 20, left: 60}, // margins around the graph |
|
xRange = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]), // x range function |
|
yRange = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]), // y range function |
|
rRange = d3.scale.linear().range([5, 20]), // radius range function - ensures the radius is between 5 and 20 |
|
colours = [ |
|
"#1f77b4", |
|
"#ff7f0e", |
|
"#2ca02c", |
|
"#d62728", |
|
"#9467bd", |
|
"#8c564b", |
|
"#e377c2", |
|
"#7f7f7f", |
|
"#bcbd22", |
|
"#17becf" |
|
], |
|
currentDataset,// name of the current data set. Used to track when the dataset changes |
|
data, |
|
xAxis = d3.svg.axis().scale(xRange).tickSize(16).tickSubdivide(true), // x axis function |
|
yAxis = d3.svg.axis().scale(yRange).tickSize(10).orient("right").tickSubdivide(true), // y axis function |
|
vis; // visualisation selection |
|
|
|
// runs once when the visualisation loads |
|
function init () { |
|
vis = d3.select("#visualisation"); |
|
|
|
// add in the x axis |
|
vis.append("g") // container element |
|
.attr("class", "x axis") // so we can style it with CSS |
|
.attr("transform", "translate(0," + HEIGHT + ")") // move into position |
|
.call(xAxis); // add to the visualisation |
|
|
|
// add in the y axis |
|
vis.append("g") // container element |
|
.attr("class", "y axis") // so we can style it with CSS |
|
.call(yAxis); // add to the visualisation |
|
|
|
// load data, process it and draw it |
|
d3.csv("errordata.csv", function(data) { |
|
rawData = data; |
|
currentDataset = dataset; |
|
|
|
redraw(); |
|
}); |
|
} |
|
|
|
// this redraws the graph based on the data in the drawingData variable |
|
function redraw () { |
|
var plot = vis.selectAll ("circle").data(rawData), // select the data points and set their data |
|
axes = getAxes (); // object containing the axes we'd like to use (duration, inversions, etc.) |
|
|
|
// add new points if they're needed |
|
plot.enter() |
|
.insert("circle") |
|
.attr("cx", function (d) { return xRange (d[axes.xAxis]); }) |
|
.attr("cy", function (d) { return yRange (d[axes.yAxis]); }) |
|
.style("opacity", .5) |
|
.style("fill", function (d) { return colours[d.site]; }); // set fill colour from the colours array |
|
|
|
// the data domains or desired axes might have changed, so update them all |
|
xRange.domain([ |
|
d3.min(rawData, function (d) { return +d[axes.xAxis]; }), |
|
d3.max(rawData, function (d) { return +d[axes.xAxis]; }) |
|
]); |
|
yRange.domain([ |
|
d3.min(rawData, function (d) { return +d[axes.yAxis]; }), |
|
d3.max(rawData, function (d) { return +d[axes.yAxis]; }) |
|
]); |
|
rRange.domain([ |
|
d3.min(rawData, function (d) { return +d[axes.radiusAxis]; }), |
|
d3.max(rawData, function (d) { return +d[axes.radiusAxis]; }) |
|
]); |
|
|
|
// transition function for the axes |
|
var t = vis.transition().duration(1500).ease("exp-in-out"); |
|
t.select(".x.axis").call(xAxis); |
|
t.select(".y.axis").call(yAxis); |
|
|
|
// transition the points |
|
plot.transition().duration(1500).ease("exp-in-out") |
|
.style("opacity", 0.5) |
|
.style("fill", function (d) { return colours[d.site]; }) // set fill colour from the colours array |
|
.attr("r", function(d) { return rRange (d[axes.radiusAxis]); }) |
|
.attr("cx", function (d) { return xRange (d[axes.xAxis]); }) |
|
.attr("cy", function (d) { return yRange (d[axes.yAxis]); }); |
|
|
|
// remove points if we don't need them anymore |
|
plot.exit() |
|
.transition().duration(1500).ease("exp-in-out") |
|
.attr("cx", function (d) { return xRange (d[axes.xAxis]); }) |
|
.attr("cy", function (d) { return yRange (d[axes.yAxis]); }) |
|
.style("opacity", 0.5) |
|
.attr("r", 0) |
|
.remove(); |
|
} |
|
|
|
// let's kick it all off! |
|
init (); |
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////// |
|
// helper functions - health warning! LOTS of javascript! |
|
////////////////////////////////////////////////////////// |
|
|
|
|
|
|
|
// return the name of the dataset which is currently selected |
|
function getChosenDataset () { |
|
var select = document.getElementById("dataset"); |
|
return select.options[select.selectedIndex].value; |
|
} |
|
|
|
|
|
// return an object containing the currently selected axis choices |
|
function getAxes () { |
|
var x = document.querySelector("#x-axis input:checked").value, |
|
y = document.querySelector("#y-axis input:checked").value, |
|
r = document.querySelector("#r-axis input:checked").value; |
|
return { |
|
xAxis: x, |
|
yAxis: y, |
|
radiusAxis: r |
|
}; |
|
} |
|
|
|
// called every time a form field has changed |
|
function update () { |
|
var dataset = getChosenDataset(), // filename of the chosen dataset csv |
|
rawData; // the data while will be visualised |
|
// if the dataset has changed from last time, load the new csv file |
|
if (dataset != currentDataset) { |
|
d3.csv("errordata.csv", function (data) { |
|
// process new data and store it in the appropriate variables |
|
|
|
|
|
currentDataset = dataset; |
|
rawData = data; |
|
redraw(); |
|
}); |
|
} else { |
|
// process data based on the form fields and store it in the appropriate variables |
|
rawData = data; |
|
redraw(); |
|
} |
|
} |
|
|
|
|
|
// listen to the form fields changing |
|
document.getElementById("dataset").addEventListener ("change", update, false); |
|
document.getElementById("controls").addEventListener ("click", update, false); |
|
document.getElementById("controls").addEventListener ("keyup", update, false); |