Skip to content

Instantly share code, notes, and snippets.

@dgwyer
Last active October 9, 2017 16:10
Show Gist options
  • Save dgwyer/48c7e7c850b1a023886e66f0059f3e36 to your computer and use it in GitHub Desktop.
Save dgwyer/48c7e7c850b1a023886e66f0059f3e36 to your computer and use it in GitHub Desktop.
d3 scatterplot with tooltips
license: mit
cereal manufacturer calories sugar
Apple_Cinnamon_Cheerios General Mills 110 10
Apple_Jacks Kelloggs 112 14
Cap'n'Crunch Quaker Oats 120 12
Cheerios General Mills 110 1
Cinnamon_Toast_Crunch General Mills 120 9
Cocoa_Puffs General Mills 110 13
Corn_Flakes Kelloggs 100 5
Corn_Pops Kelloggs 111 12
Froot_Loops Kelloggs 110 17
Frosted_Flakes Kelloggs 110 15
Grape-Nuts Post 115 3
Kix General Mills 110 3
Lucky_Charms General Mills 110 12
Raisin_Nut_Bran General Mills 100 8
Rice_Krispies Kelloggs 125 3
Shredded_Wheat Nabisco 80 0
Special_K Kelloggs 110 5
Trix General Mills 110 14
Wheaties General Mills 100 1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>d3 Scatter Plot</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<!-- Styles for our vis -->
<style>
body {
font: 15px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.dot {
stroke: none;
}
.tooltip {
position: absolute;
font-size: 12px;
width: auto;
height: auto;
pointer-events: none;
background-color: white;
}
</style>
</head>
<body>
<div id="vis-container"></div>
<!-- Optionally reference your vis JS file here, or define in a script tag -->
<!-- <script type="text/javascript" src="js/my-vis.js"></script> -->
<script type="text/javascript">
d3.csv('./cereal.csv', function loadCallback(error, data) {
data.forEach(function(d) { // convert strings to numbers
d.calories = +d.calories;
d.sugar = +d.sugar;
});
makeVis(data);
});
var makeVis = function(data) {
// Common pattern for defining vis size and margins
var margin = { top: 20, right: 20, bottom: 30, left: 40 },
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Add the visualization svg canvas to the vis-container <div>
var canvas = d3.select("#vis-container").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 + ")");
// Define our scales
var colorScale = d3.scale.category10();
var xScale = d3.scale.linear()
.domain([ d3.min(data, function(d) { return d.sugar; }) - 1,
d3.max(data, function(d) { return d.sugar; }) + 1 ])
.range([0, width]);
var yScale = d3.scale.linear()
.domain([ d3.min(data, function(d) { return d.calories; }) - 1,
d3.max(data, function(d) { return d.calories; }) + 1 ])
.range([height, 0]); // flip order because y-axis origin is upper LEFT
// Define our axes
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom');
var yAxis = d3.svg.axis()
.scale(yScale)
.orient('left');
// Add x-axis to the canvas
canvas.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")") // move axis to the bottom of the canvas
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width) // x-offset from the xAxis, move label all the way to the right
.attr("y", -6) // y-offset from the xAxis, moves text UPWARD!
.style("text-anchor", "end") // right-justify text
.text("Sugar");
// Add y-axis to the canvas
canvas.append("g")
.attr("class", "y axis") // .orient('left') took care of axis positioning for us
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)") // although axis is rotated, text is not
.attr("y", 15) // y-offset from yAxis, moves text to the RIGHT because it's rotated, and positive y is DOWN
.style("text-anchor", "end")
.text("Calories");
// Add the tooltip container to the vis container
// it's invisible and its position/contents are defined during mouseover
var tooltip = d3.select("#vis-container").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// tooltip mouseover event handler
var tipMouseover = function(d) {
var color = colorScale(d.manufacturer);
var html = d.cereal + "<br/>" +
"<span style='color:" + color + ";'>" + d.manufacturer + "</span><br/>" +
"<b>" + d.sugar + "</b> sugar, <b/>" + d.calories + "</b> calories";
tooltip.html(html)
.style("left", (d3.event.pageX + 15) + "px")
.style("top", (d3.event.pageY - 28) + "px")
.transition()
.duration(200) // ms
.style("opacity", .9) // started as 0!
};
// tooltip mouseout event handler
var tipMouseout = function(d) {
tooltip.transition()
.duration(300) // ms
.style("opacity", 0); // don't care about position!
};
// Add data points!
canvas.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 5.5) // radius size, could map to another data dimension
.attr("cx", function(d) { return xScale( d.sugar ); }) // x position
.attr("cy", function(d) { return yScale( d.calories ); }) // y position
.style("fill", function(d) { return colorScale(d.manufacturer); })
.on("mouseover", tipMouseover)
.on("mouseout", tipMouseout);
};
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment