A line chart written in D3, based on William Playfair's iconic import-export charts, using data from India's Export Import Data Bank.
Last active
October 31, 2016 16:49
-
-
Save HarryStevens/6fb5a3c76246f542fecede554325cadf to your computer and use it in GitHub Desktop.
Playfair Import-Export Chart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: gpl-3.0 | |
height: 530 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | |
"http://www.w3.org/TR/html4/loose.dtd"> | |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<!-- meta --> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<title></title> | |
<!-- fonts --> | |
<link href="https://fonts.googleapis.com/css?family=IM+Fell+English" rel="stylesheet"> | |
<link href="https://fonts.googleapis.com/css?family=IM+Fell+DW+Pica+SC" rel="stylesheet"> | |
<!-- css --> | |
<link rel="stylesheet" href="styles.css" | |
</head> | |
<body> | |
<div class="title">CHART of all the IMPORTS and EXPORTS to and from INDIA<br/>From the Year 1996 to 2015 by H. Stevens</div> | |
<div class="chart"></div> | |
<div class="title sub">The Divisions at the Bottom, expreſs <b>YEARS</b>, & those on the Right hand, LAKHS of 2015 RUPEES</div> | |
<div class="source left">A D3 chart based on <a href="https://commons.wikimedia.org/wiki/File:1786_Playfair_-_1_Chart_of_all_the_import_and_exports_to_and_from_England_from_the_year_1700_to_1782.jpg">the work of William Playfair</a><br />Source: <a href="http://www.commerce.nic.in/eidb/">Export Import Data Bank, Indian Commerce Department</a></div> | |
<div class="source right">Published as the Act directs. 28.<sup>th</sup> Aug.<sup>st</sup> 2016</div> | |
<!-- js --> | |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="scripts.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// a function to convert all the numbers into numbers | |
function types(d){ | |
// loop through all the years in the data | |
for (var i = 1996;i<2016;i++){ | |
var name = 'y'+i+'to'+(i+1); | |
d[name] = +(d[name]); | |
} | |
return d; | |
} | |
$(document).ready(function(){ | |
// define margins and whatnot | |
var margin = {top: 0, right: 2, bottom: 30, left: 0}, | |
width = 780 - margin.left - margin.right, | |
height = 390 - margin.top - margin.bottom; | |
// time formatter | |
var parseTime = d3.timeParse("%d-%b-%y"); | |
// x scale | |
var x = d3.scaleTime() | |
.range([0,width]); | |
// y scale | |
var y = d3.scaleLinear() | |
.range([height,0]); | |
// x axis | |
var xAxis = d3.axisBottom().scale(x).tickSizeInner(-height).tickSizeOuter(0).tickPadding(8); | |
// y axis | |
var yAxis = d3.axisRight().scale(y).tickSizeInner(-width).tickSizeOuter(0).tickPadding(8); | |
// line for exports | |
var lineExport = d3.line() | |
.x(function(d){ return x(d.date); }) | |
.y(function(d){ return y(d.export); }); | |
// line for imports | |
var lineImport = d3.line() | |
.x(function(d){ return x(d.date); }) | |
.y(function(d){ return y(d.import); }); | |
// areas | |
var areaAboveExport = d3.area() | |
.x(lineExport.x()) | |
.y0(lineExport.y()) | |
.y1(0); | |
var areaBelowExport = d3.area() | |
.x(lineExport.x()) | |
.y0(lineExport.y()) | |
.y1(height); | |
var areaAboveImport = d3.area() | |
.x(lineImport.x()) | |
.y0(lineImport.y()) | |
.y1(0); | |
var areaBelowImport = d3.area() | |
.x(lineImport.x()) | |
.y0(lineImport.y()) | |
.y1(height); | |
// create an svg element, append it to the .chart div, and append a g to it | |
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 + ')'); | |
d3.tsv('total_real.tsv', type, function(error,data){ | |
if (error) throw error; | |
//extent of the x domain | |
//the really enormous numbers are to add padding | |
x.domain([(d3.min(data, function(d){ return d.date-8000000000; })),(d3.max(data, function(d){ return d.date-(-86890000000); }))]); | |
// y domain. setting the max to export now, and adding some padding | |
y.domain([0,(d3.max(data, function(d){ return d.import+d.import*.2; }))]); | |
// append x axis to the svg element | |
svg.append('g') | |
.attr('class', 'x axis') | |
.attr('transform', 'translate(0,' + height +')') | |
.call(xAxis) | |
.append('text') | |
.attr('class','x axis label') | |
.attr('x',width-margin.right) | |
.attr('y',15) | |
.style('text-anchor','end') | |
.text('Years'); | |
// set the first year of the x axis a little to the left | |
$('.x.axis g.tick:first-of-type text').attr('x',8.5); | |
// append y axis to the svg element | |
svg.append('g') | |
.attr('class', 'y axis') | |
.attr('transform','translate(' + width + ',0)') | |
.call(yAxis) | |
.append('text') | |
.attr('x', -34) | |
.attr('y', 6) | |
.attr('dy', '.71em') | |
.attr('class', 'y axis label') | |
.style('text-anchor', 'end') | |
.text('Lakhs'); | |
var bottomY = $('.y.axis .tick:first-of-type text').text(); | |
$('.y.axis .tick:first-of-type text').html(bottomY+' ₹') | |
// y axis ticks placement | |
$('.y.axis .tick text').attr('x',-60).attr('y',-6); | |
// append a path, or a line, to the svg element, for Imports | |
svg.append('defs').append('path') | |
.datum(data) | |
.attr('id', 'lineimports') | |
.attr('class', 'line imports') | |
.attr('transform','translate(0,-2)') | |
.attr('d', lineImport); | |
svg.append('text') | |
.attr('class','line-text') | |
.attr('id','imports-text') | |
.attr('transform','translate(0,-5)') | |
.attr('word-spacing',25) | |
.append('textPath') | |
.attr('xlink:href','#lineimports') | |
.html(' Line Representing Imports into India') | |
svg.append('use') | |
.attr('id', 'exports-line') | |
.attr('xlink:href', '#lineimports'); | |
// append a line that's the same as imports, but just a single line | |
svg.append('path') | |
.datum(data) | |
.attr('class', 'line-thin') | |
.attr('d', lineImport); | |
// append a path, or a line, to the svg element, for EXPORTS | |
svg.append('defs').append('path') | |
.datum(data) | |
.attr('id', 'lineexports') | |
.attr('class', 'line exports') | |
.attr('transform','translate(0,2)') | |
.attr('d', lineExport); | |
svg.append('text') | |
.attr('class','line-text') | |
.attr('id','exports-text') | |
.attr('transform','translate(0,12)') | |
.attr('word-spacing',50) | |
.append('textPath') | |
.attr('xlink:href','#lineexports') | |
.html(' Line Representing Exports'); | |
svg.append('use') | |
.attr('id', 'exports-line') | |
.attr('xlink:href', '#lineexports'); | |
// append a line that's the same as exports, but just a single line | |
svg.append('path') | |
.datum(data) | |
.attr('class', 'line-thin') | |
.attr('d', lineExport); | |
// define areas | |
var defs = svg.append('defs'); | |
defs.append('clipPath') | |
.attr('id','clip-import') | |
.append('path') | |
.datum(data) | |
.attr('d',areaAboveImport); | |
defs.append('clipPath') | |
.attr('id','clip-export') | |
.append('path') | |
.datum(data) | |
.attr('d',areaAboveExport); | |
// IMPORT IS ABOVE EXPORT | |
svg.append('path') | |
.datum(data) | |
.attr('d', areaBelowImport) | |
.attr('class','surplus import') | |
.attr('clip-path', 'url(#clip-export)') | |
svg.append('text') | |
.attr('class','line-text') | |
.attr('id','area-text') | |
.attr('transform','translate(0,30)') | |
.attr('word-spacing',25) | |
.append('textPath') | |
.attr('xlink:href','#lineimports') | |
.html(' BALANCE against INDIA') | |
// EXPORT IS ABOVE IMPORT | |
svg.append('path') | |
.datum(data) | |
.attr('class','surplus export') | |
.attr('d', areaBelowExport) | |
.attr('clip-path', 'url(#clip-import)'); | |
// place the shaded area below the axis lines | |
$('svg g:first-of-type').before($('.import.surplus')).before($('.export.surplus')); | |
});// end tsv | |
// set the data types | |
function type(d) { | |
d.date = parseTime(d.date); | |
d.export = +d.export; | |
d.import = +d.import; | |
return d; | |
} | |
});// end document ready |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
font-family: 'IM Fell English', serif; | |
font-size: 16px; | |
width: 780px; | |
margin: 0 auto; | |
display: table; | |
} | |
/*TITLES*/ | |
.title { | |
margin-top: 20px; | |
width: 100%; | |
text-align: center; | |
font-style: italic; | |
} | |
.title.sub { | |
margin-top: 0px; | |
} | |
.source { | |
font-size: .8em; | |
font-style: italic; | |
} | |
.source.left { | |
float: left; | |
} | |
.source.right { | |
float: right; | |
} | |
/*CHART*/ | |
.chart { | |
margin-top: 20px; | |
border-top: 2px solid #000; | |
} | |
/*LINES*/ | |
.line { | |
fill: none; | |
stroke-width: .2em; | |
} | |
.line-thin { | |
fill: none; | |
stroke-width: .05em; | |
stroke: #000; | |
} | |
.line.exports { | |
stroke: #b13737; | |
} | |
.line.imports { | |
stroke: #e5bd10; | |
} | |
.line-text { | |
font-size: .8em; | |
} | |
#exports-line { | |
fill: none; | |
stroke: #000; | |
} | |
/*AXES*/ | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #888; | |
shape-rendering: crispEdges; | |
} | |
.axis path { | |
stroke: #000; | |
stroke-width: .2em; | |
} | |
.x.axis path { | |
display: none; | |
} | |
.x.axis g.tick:first-of-type line,.y.axis g.tick:first-of-type line { | |
stroke: #000; | |
stroke-width:.2em; | |
} | |
.axis.label { | |
fill: #000; | |
font-size: 1em; | |
font-family: 'IM Fell English', serif; | |
} | |
.tick text { | |
font-family: 'IM Fell English', serif; | |
} | |
/*AREA*/ | |
.surplus { | |
fill-opacity: .5; | |
} | |
.surplus.import { | |
fill: #b3e6ff; | |
} | |
.surplus.export { | |
fill: #fdd8d6; | |
} | |
#area-text { | |
font-family: 'IM Fell DW Pica SC', serif; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
date | export | import | |
---|---|---|---|
1-Apr-96 | 41823925.48 | 48899720.99 | |
1-Apr-97 | 42661639.71 | 50878174.02 | |
1-Apr-98 | 41227180.05 | 52607895.99 | |
1-Apr-99 | 45155981.31 | 60994547.19 | |
1-Apr-00 | 54557029.8 | 61873898.82 | |
1-Apr-01 | 53299582.1 | 62525927.17 | |
1-Apr-02 | 62763768.89 | 73112644 | |
1-Apr-03 | 69527918.09 | 85108515.37 | |
1-Apr-04 | 85577410.99 | 114242714.2 | |
1-Apr-05 | 99499092.78 | 143969139.9 | |
1-Apr-06 | 117214752.5 | 172303793.4 | |
1-Apr-07 | 126581658.9 | 195376157.2 | |
1-Apr-08 | 148813644.7 | 243275092.4 | |
1-Apr-09 | 132748781.3 | 214106480.4 | |
1-Apr-10 | 165996781.9 | 245786174.9 | |
1-Apr-11 | 194972599.5 | 311946610.9 | |
1-Apr-12 | 199386830.7 | 325637758.1 | |
1-Apr-13 | 209551219.2 | 298697729.3 | |
1-Apr-14 | 199116583.3 | 287394090.3 | |
1-Apr-15 | 171461770.1 | 248800746.7 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment