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);