I recently worked on some updates to the MPG tracking page I set up in January. One of my goals was to make the graphs on the page respond to mouseover events by displaying more data. Here’s some sample code for a simplified version of the histogram that now appears on the MPG page, the data is below the code. The code for this example and the entire MPG project is available on github. See also the interactive miles over time graph.
index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <body> <title>MPG Data</title> <style> .d3-tip { line-height: 1; font-weight: bold; padding: 12px; background: rgba(0, 0, 0, 0.8); color: #fff; border-radius: 2px; } .bar rect { fill: steelblue; shape-rendering: crispEdges; } .bar rect:hover{ fill: rgba(0,0,0,.8); } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } </style> <script src="../../mpg/lib/d3.v3.min.js"></script> <!See https://github.com/Caged/d3-tip (d3.tip.js is the index.js file)> <script src="../../mpg/lib/d3.tip.v0.6.3.js"></script> </script> <script> // plot a histogram from mpg data in a .csv file function parser(d) { d.pMPG = +d.MPG; return d; } function mpghist(csvdata) { var binsize = 2; var minbin = 36; var maxbin = 60; var numbins = (maxbin - minbin) / binsize; // whitespace on either side of the bars in units of MPG var binmargin = .2; var margin = {top: 10, right: 30, bottom: 50, left: 60}; var width = 450 - margin.left - margin.right; var height = 250 - margin.top - margin.bottom; // Set the limits of the x axis var xmin = minbin - 1 var xmax = maxbin + 1 histdata = new Array(numbins); for (var i = 0; i < numbins; i++) { histdata[i] = { numfill: 0, meta: "" }; } // Fill histdata with y-axis values and meta data csvdata.forEach(function(d) { var bin = Math.floor((d.pMPG - minbin) / binsize); if ((bin.toString() != "NaN") && (bin < histdata.length)) { histdata[bin].numfill += 1; histdata[bin].meta += "<tr><td>" + d.City + " " + d.State + "</td><td>" + d.pMPG.toFixed(1) + " mpg</td></tr>"; } }); // This scale is for determining the widths of the histogram bars // Must start at 0 or else x(binsize a.k.a dx) will be negative var x = d3.scale.linear() .domain([0, (xmax - xmin)]) .range([0, width]); // Scale for the placement of the bars var x2 = d3.scale.linear() .domain([xmin, xmax]) .range([0, width]); var y = d3.scale.linear() .domain([0, d3.max(histdata, function(d) { return d.numfill; })]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x2) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .ticks(8) .orient("left"); var tip = d3.tip() .attr('class', 'd3-tip') .direction('e') .offset([0, 20]) .html(function(d) { return '<table id="tiptable">' + d.meta + "</table>"; }); // put the graph in the "mpg" div var svg = d3.select("#mpg").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 + ")"); svg.call(tip); // set up the bars var bar = svg.selectAll(".bar") .data(histdata) .enter().append("g") .attr("class", "bar") .attr("transform", function(d, i) { return "translate(" + x2(i * binsize + minbin) + "," + y(d.numfill) + ")"; }) .on('mouseover', tip.show) .on('mouseout', tip.hide); // add rectangles of correct size at correct location bar.append("rect") .attr("x", x(binmargin)) .attr("width", x(binsize - 2 * binmargin)) .attr("height", function(d) { return height - y(d.numfill); }); // add the x axis and x-label svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("text") .attr("class", "xlabel") .attr("text-anchor", "middle") .attr("x", width / 2) .attr("y", height + margin.bottom) .text("MPG"); // add the y axis and y-label svg.append("g") .attr("class", "y axis") .attr("transform", "translate(0,0)") .call(yAxis); svg.append("text") .attr("class", "ylabel") .attr("y", 0 - margin.left) // x and y switched due to rotation .attr("x", 0 - (height / 2)) .attr("dy", "1em") .attr("transform", "rotate(-90)") .style("text-anchor", "middle") .text("# of fill-ups"); } // Read in .csv data and make graph d3.csv("prius_gas.csv", parser, function(error, csvdata) { mpghist(csvdata); }); </script> <div id="mpg" class="graph"></div> </body> </html>
prius_gas.csv
City,State,MPG Berkeley,CA,48.75 Tahoe City,CA,39.45 Meyers,CA,47.05 San Rafael,CA,53.09 Berkeley,CA,45.55 Tehachapi,CA,51.8 Hurricane,UT,52.54 Scipio,UT,49 Ely,NV,48.45 Colfax,CA,52.18 Vacaville,CA,50.7 Roseburg,OR,46.54 Crescent City,CA,47.59 Berkeley,CA,44.03 Berkeley,CA,52.81
D3-tip project: http://labratrevenge.com/d3-tip/