Skip to content

Instantly share code, notes, and snippets.

@jgoodall
Created September 12, 2013 15:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jgoodall/6539804 to your computer and use it in GitHub Desktop.
Save jgoodall/6539804 to your computer and use it in GitHub Desktop.
intro to d3: scatterplot with transitions
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.circle {
fill: steelblue;
stroke: '#fff';
}
.label {
fill: #777;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var width = 400
, height = 400
, margin = {top: 25, right: 50, bottom: 40, left: 50}
, uid = 0
, datasetSize = 10;
// [0] is uid
// [1] will be plotted on the x axis
// [2] will be plotted on the y axis
// [3] will be used as the radius
var dataset = [];
for (var i = 0 ; i < datasetSize ; i++) {
dataset.push(generateDatum());
}
// set up the scales
var xScale = d3.scale.linear()
.range([0, width])
.domain([0, 100])
.nice();
var yScale = d3.scale.linear()
.range([height, 0])
.domain([0, 100])
.nice();
// set the axes
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom')
.outerTickSize(1);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left')
.outerTickSize(1);
// append the svg to the body of the page and set the width and height
// append a 'g' element to group the circles together and 'translate'
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// draw the axes
var svgXaxis = svg.append('g')
.attr({
'class': 'axis label'
, 'transform': 'translate(0,' + height + ')'
})
.call(xAxis);
svgXaxis.append('text')
.attr({
'class': 'label'
, 'x': width / 2
, 'y': margin.bottom - 4
, 'text-anchor': 'middle'
})
.text('first set of numbers');
// draw Y axis
var svgYaxis = svg.append('g')
.attr({
'class': 'axis label'
})
.call(yAxis);
svgYaxis.append('text')
.attr({
'class': 'label'
, 'transform': 'translate(-290,320)rotate(-90)'
, 'x': margin.left
, 'y': height / 2
, 'text-anchor': 'middle'
})
.text('more numbers');
// draw initial display
update();
// add new data
var count = 0;
var interval = setInterval(function() {
// remove a datum on odd loops
if (count % 2 === 1) {
var indexToRemove = parseInt((Math.random() * dataset.length));
console.log('Removing point ' + indexToRemove + ': ' + dataset[indexToRemove]);
dataset.splice(indexToRemove, 1)
}
// add a new datum
var d = generateDatum();
console.log('Adding new point ' + d);
dataset.push(d);
update();
count++;
if (count >= 50) {
clearInterval(interval);
console.log('Added ' + count + ' points. Done.');
}
}, 1200);
function update () {
// update the scales' domain
xScale.domain([0, d3.max(dataset, function(d) { return d[1]; })]);
yScale.domain([0, d3.max(dataset, function(d) { return d[2]; })]);
// data-join
var dot = svg.selectAll("circle")
.data(dataset, function(d) {return d[0]});
// udpate
dot.transition()
.duration(750)
.attr({
"cx": function(d) { return xScale(d[1]); }
, "cy": function(d) { return yScale(d[2]); }
, "r": function(d) { return d[3] / 2; }
});
// enter
dot.enter().append("circle")
.attr({
"class": "circle"
, "cx": function(d) { return xScale(d[1]); }
, "cy": function(d) { return yScale(d[2]); }
, "r": function(d) { return d[3] / 2; }
})
.style('opacity', 1e-6)
.transition()
.style('fill', 'green')
.style('opacity', 1)
.transition()
.duration(700)
.style('fill', null);
dot.exit().transition()
.style('fill', 'red')
.transition()
.duration(700)
.style('opacity', 1e-6)
.remove();
// update axes
svgXaxis.transition()
.call(xAxis);
svgYaxis.transition()
.call(yAxis);
}
function generateDatum () {
return [
uid++
, parseInt(Math.random() * 400)
, parseInt(Math.random() * 400)
, parseInt((Math.random() * 10) + 10)
];
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment