Skip to content

Instantly share code, notes, and snippets.

@ndobie
Last active March 12, 2016 05:20
Show Gist options
  • Save ndobie/436327fa73730ecb02db to your computer and use it in GitHub Desktop.
Save ndobie/436327fa73730ecb02db to your computer and use it in GitHub Desktop.
D3 Table with Chart and Data Download
license: mit
border: no
height: 600
scrolling: no

This employs D3's ability to make line charts with D3's ability to parse HTML tables.

periodyear period cpi
2007 1 202.416
2007 2 203.499
2007 3 205.352
2007 4 206.686
2007 5 207.949
2007 6 208.352
2007 7 208.299
2007 8 207.917
2007 9 208.49
2007 10 208.936
2007 11 210.177
2007 12 210.036
2008 1 211.08
2008 2 211.693
2008 3 213.528
2008 4 214.823
2008 5 216.632
2008 6 218.815
2008 7 219.964
2008 8 219.086
2008 9 218.783
2008 10 216.573
2008 11 212.425
2008 12 210.228
2009 1 211.143
2009 2 212.193
2009 3 212.709
2009 4 213.24
2009 5 213.856
2009 6 215.693
2009 7 215.351
2009 8 215.834
2009 9 215.969
2009 10 216.177
2009 11 216.33
2009 12 215.949
2010 1 216.687
2010 2 216.741
2010 3 217.631
2010 4 218.009
2010 5 218.178
2010 6 217.965
2010 7 218.011
2010 8 218.312
2010 9 218.439
2010 10 218.711
2010 11 218.803
2010 12 219.179
2011 1 220.223
2011 2 221.309
2011 3 223.467
2011 4 224.906
2011 5 225.964
2011 6 225.722
2011 7 225.922
2011 8 226.545
2011 9 226.889
2011 10 226.421
2011 11 226.23
2011 12 225.672
2012 1 226.665
2012 2 227.663
2012 3 229.392
2012 4 230.085
2012 5 229.815
2012 6 229.478
2012 7 229.104
2012 8 230.379
2012 9 231.407
2012 10 231.317
2012 11 230.221
2012 12 229.601
2013 1 230.28
2013 2 232.166
2013 3 232.773
2013 4 232.531
2013 5 232.945
2013 6 233.504
2013 7 233.596
2013 8 233.877
2013 9 234.149
2013 10 233.546
2013 11 233.069
2013 12 233.049
2014 1 233.916
2014 2 234.781
2014 3 236.293
2014 4 237.072
2014 5 237.9
2014 6 238.343
2014 7 238.25
2014 8 237.852
2014 9 238.031
2014 10 237.433
2014 11 236.151
2014 12 234.812
2015 1 233.707
2015 2 234.722
2015 3 236.119
2015 4 236.599
2015 5 237.805
2015 6 238.638
2015 7 238.654
2015 8 238.316
2015 9 237.945
2015 10 237.838
2015 11 237.336
2015 12 236.525
2016 1 236.916
c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12
<b>January</b> 202.416 211.080 211.143 216.687 220.223 226.665 230.280 233.916 233.707 236.916 0.2
<b>February</b> 203.499 211.693 212.193 216.741 221.309 227.663 232.166 234.781 234.722
<b>March</b> 205.352 213.528 212.709 217.631 223.467 229.392 232.773 236.293 236.119
<b>April</b> 206.686 214.823 213.240 218.009 224.906 230.085 232.531 237.072 236.599
<b>May</b> 207.949 216.632 213.856 218.178 225.964 229.815 232.945 237.900 237.805
<b>June</b> 208.352 218.815 215.693 217.965 225.722 229.478 233.504 238.343 238.638
<b>July</b> 208.299 219.964 215.351 218.011 225.922 229.104 233.596 238.250 238.654
<b>August</b> 207.917 219.086 215.834 218.312 226.545 230.379 233.877 237.852 238.316
<b>September</b> 208.490 218.783 215.969 218.439 226.889 231.407 234.149 238.031 237.945
<b>October</b> 208.936 216.573 216.177 218.711 226.421 231.317 233.546 237.433 237.838
<b>November</b> 210.177 212.425 216.330 218.803 226.230 230.221 233.069 236.151 237.336
<b>December</b> 210.036 210.228 215.949 219.179 225.672 229.601 233.049 234.812 236.525
&nbsp;
<b>Annual Avg.</b> 207.342 215.303 214.537 218.056 224.939 229.594 232.957 236.736 237.017
&nbsp;
<b>Y/Y % Chg.</b> 2.8 3.8 -0.4 1.6 3.2 2.1 1.5 1.6 0.1
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<style type="text/css">
h3 {
text-align: center;
padding-top: 0;
}
h4 {
text-align: center;
padding-top: 0;
}
svg {
font-family: sans-serif;
font-size: 0.75em;
position: relative;
}
path {
stroke: steelblue;
stroke-width: 2px;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: black;
stroke-width: 1;
shape-rendering: crispEdges;
}
@import url('//fonts.googleapis.com/css?family=Lato:400,400italic,700,700italic');
body {
font-family: 'Lato', Arial, Helvetica, sans-serif;
font-size: 16px;
}
.source {
font-size: 0.625em;
color: grey;
line-height: 80%;
}
.prepaired {
font-size: 0.625em;
color: grey;
line-height: 80%;
}
.update {
font-size: 0.625em;
color: grey;
line-height: 80%;
}
.notes {
font-size: 0.625em;
color: grey;
line-height: 80%;
}
a {
color: dimgray;
}
th {
text-align: right;
font-weight: bold;
}
#cpi {
text-align: right;
padding-right: 2px;
margin-right: 3px;
width: 100%;
font-size: .8em;
}
h2 {
margin-top: 0;
}
td:nth-child(6) {
margin-right: 5px;
}
td:nth-child(1) {
width: 85px;
}
td:nth-child(12) {
width:95px;
}
@media print {
.noprint {
display: none !important;
}
a:link:after, a:visited:after {
display: none;
content: "";
}
}
</style>
</head>
<body>
<div style="align-items:flex-start; width:100%;" class="container">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#home">Consumer Price Index</a></li>
<li><a data-toggle="tab" href="#menu1">Chart</a></li>
<li><a href="http://data.bls.gov/cgi-bin/surveymost?bls" target="_blank">Download</a></li>
</ul>
<div class="tab-content" style="background-color:lightgrey; stroke-width:1px; stroke:dimgray; border-radius: 0 0 0.625em 0.625em; padding:4px;">
<div id="home" style="margin-right:5px;" class="tab-pane fade in active">
<h3>All items, U.S. city average (base period: 1982-1984=100)</h3>
<table id="cpi"></table>
<br /><span class="source">Source: U.S. Dept. of Labor, Bureau of Labor Statistics.</span>
<br /><span class="prepaired">Table prepared by UNM Bureau of Business and Economic Research</span>
<br /><span class="update">Last Revised: 01/20/2016, Next update: 03/08/2016</span>
</div>
<div id="menu1" style="margin-right:5px;" class="tab-pane fade">
<span id="ieString"></span>
<div id="chart" style="background:white"></div>
<br /><span class="source">Source: U.S. Dept. of Labor, Bureau of Labor Statistics.</span>
<br /><span class="prepaired">Table prepared by UNM Bureau of Business and Economic Research</span>
<br /><span class="update">Last Revised: 01/20/2016, Next update: 03/08/2016</span>
</div>
</div>
</div>
<script>
// Set the dimensions of the canvas / graph
var margin = { top: 10, right: 60, bottom: 30, left: 50 }
, width = 910
, width = width - margin.left - margin.right
, height = 400 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format( "%m/%d/%Y" ).parse;
bisectDate = d3.bisector( function ( d ) { return d.date; } ).left;
// Set the ranges
var x = d3.time.scale().range( [0, width] );
var y = d3.scale.linear().range( [height, 0] );
// Define the axes
var xAxis = d3.svg.axis().scale( x )
.orient( "bottom" )
.ticks( d3.time.year, 1 );
var yAxis = d3.svg.axis().scale( y )
.orient( "left" ).ticks( 10 );
// Adds the svg canvas
var svg = d3.select( "#chart" )
.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 + ")" );
var rSvg = svg.append( "g" );
var lineSvg = svg.append( "g" );
var focus = svg.append( "g" )
.style( "display", "none" );
d3.csv( "cpi.csv", function ( error, data ) {
data.forEach( function ( d ) {
d.dateP = d.period + "/01/" + d.periodyear
d.date = parseDate( d.dateP );
return d;
} );
valueline = d3.svg.line()
.x( function ( d ) { return x( d.date ); } )
.y( function ( d ) { return y( d.cpi ); } );
// Scale the range of the data
x.domain( d3.extent( data, function ( d ) { return d.date; } ) );
y.domain( [180, 250] );
//Makes the shaded recession rectangle
rSvg.append( 'rect' )
.attr( "class", "recessionRect" )
.attr( "x", x( parseDate( "12/01/2007" ) ) )
.attr( "width", x( parseDate( "06/01/2009" ) ) - x( parseDate( "12/01/2007" ) ) )
.attr( "y", y( 250 ) )
.attr( "height", y( 180 ) - y( 250 ) )
.style( "fill", "lightgrey" )
.style( "fill-opacity", 0.7 );
// draw the lines
var lines = lineSvg.selectAll( ".line" ).data( data ).attr( "class", "line" )
// transition from previous paths to new paths
lines.transition().duration( 1500 )
.attr( "d", valueline( data ) );
// exit
lines.exit().remove();
// append the rectangle to capture mouse
svg.append( "rect" )
.attr( "width", width )
.attr( "height", height )
.attr( "class", "mouseEventRect" )
.style( "fill", "none" )
.style( "pointer-events", "all" )
.on( "mouseover", function () {
focus.style( "display", null );
} )
.on( "mouseout", function () {
focus.style( "display", "none" );
} )
.on( "mousemove", mousemove );
if ( svg.selectAll( ".y.axis" )[0].length < 1 ) {//checks if an axis exists yet so the below only fires on page load or resize
// Add the valueline path for inital page
lineSvg.append( "path" )
.attr( "class", "line" )
.attr( "d", valueline( data ) );
// Add the X Axis
svg.append( "g" )
.attr( "class", "x axis" )
.attr( "transform", "translate(0," + height + ")" )
.call( xAxis );
// Add the Y Axis
svg.append( "g" )
.attr( "class", "y axis" )
.call( yAxis )
.append( "text" )
.attr( "class", "label" )
.attr( "transform", "rotate(-90)" )
.attr( "y", 5 )//-30
.attr( "x", -5 )//-350
.attr( "dy", ".71em" )
.style( "text-anchor", "end" )
.text( "Consumer Price Index (100 = 1982-84)" );
// append the circle at the intersection
focus.append( "circle" )
.attr( "class", "y" )
.style( "fill", "none" )
.style( "stroke", "red" )
.attr( "r", 5 );
// place the value at the intersection
focus.append( "text" )
.attr( "class", "y1" )
.style( "stroke", "white" )
.style( "stroke-width", "3.5px" )
.style( "opacity", 0.8 )
.attr( "dx", 8 )
.attr( "dy", "-.3em" );
focus.append( "text" )
.attr( "class", "y2" )
.attr( "dx", 8 )
.attr( "dy", "-.3em" );
};
function mousemove() {
ms_ie = false,
ua = window.navigator.userAgent,
old_ie = ua.indexOf( 'MSIE ' ),
new_ie = ua.indexOf( 'Trident/' );
if ( ( old_ie > -1 ) || ( new_ie > -1 ) ) {
ms_ie = true;
}
if ( ms_ie ) {
//IE specific code goes here
var x0 = x.invert( d3.mouse( this )[0] ),
i = bisectDate( data, x0, 1 ),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
document.getElementById( 'ieString' ).innerHTML = ( '(' + d.period + '/' + d.periodyear + ', ' + ( d.cpi ) + ")" );
focus.select( "circle.y" )
.attr( "transform",
"translate(" + x( d.date ) + "," + y( d.cpi ) + ")" );
} else {
var x0 = x.invert( d3.mouse( this )[0] ),
i = bisectDate( data, x0, 1 ),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.select( "text.y1" )
.html( '(' + d.period + '/' + d.periodyear + ', ' + ( d.cpi ) + ")" )
.attr( "transform", "translate(" + ( x( d.date ) - 55 ) + "," + ( y( d.cpi ) - 8 ) + ")" );
focus.select( "text.y2" )
.html( '(' + d.period + '/' + d.periodyear + ', ' + ( d.cpi ) + ")" )
.attr( "transform", "translate(" + ( x( d.date ) - 55 ) + "," + ( y( d.cpi ) - 8 ) + ")" );
focus.select( "circle.y" )
.attr( "transform",
"translate(" + x( d.date ) + "," + y( d.cpi ) + ")" );
};
};
} );
function formatMoney( num ) {
return num.toString().replace( /(\d)(?=(\d{3})+(?!\d))/g, "$1," )
};
window.addEventListener( 'resize', function () {
"use strict";
window.location.reload();
} );
d3.csv( "cpi_tab.csv", function ( data ) {
function tabulate( data, columns ) {
var table = d3.select( "#cpi" ),
columnNames = ["Month", "2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015","2016", "% Chg. from year prev."],
thead = table.append( "thead" ),
tbody = table.append( "tbody" );
// append the header row
thead.append( "tr" )
.selectAll( "th" )
.data( columnNames )
.enter()
.append( "th" )
.text( function ( columnNames ) { return columnNames; } );
// create a row for each object in the data
var rows = tbody.selectAll( "tr" )
.data( data )
.enter()
.append( "tr" );
// create a cell in each row for each column
var cells = rows.selectAll( "td" )
.data( function ( row ) {
return columns.map( function ( column ) {
return { column: column, value: row[column] };
} );
} )
.enter()
.append( "td" )
.attr( "style", "font-family: 'Lato'" )
.attr("style", "padding: 2px;")
.html( function ( d ) {
return d.value;
} );
return table;
};
var peopleTable = tabulate( data, ["c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "c10", "c11", "c12"] )
function formatMoney( num ) {
return num.toString().replace( /(\d)(?=(\d{3})+(?!\d))/g, "$1," )
};
} );
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment