Skip to content

Instantly share code, notes, and snippets.

@tylercraft
Created September 5, 2012 03:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tylercraft/3630001 to your computer and use it in GitHub Desktop.
Save tylercraft/3630001 to your computer and use it in GitHub Desktop.
Multiple Area Charts

Since area charts are pretty common, it’s a great place to start. This example goes over the basics of how to create an infographic with multiple area charts along with a context tool to zoom and pan the data. The data for this chart is electricity consumption per capita and was downloaded from Gapminder.org, which is a great resource if you need some data while learning D3.

Built with D3.js.

Year France Germany Japan UK USA
1960 1321.93705189402 1331.88763810213 1010.89873682505 2095.84804704804 3808.71218956003
1961 1407.7746251272 1412.58400581988 1159.84831071743 2224.21531122768 3931.22123566206
1962 1490.82512902131 1501.11535482585 1223.1967739045 2430.01399572168 4171.48270057575
1963 1590.0828501506 1611.6780110804 1402.9720301029 2637.24851207459 4402.56359581911
1964 1714.97558254034 1739.05332668074 1567.3458540537 2748.98984867848 4670.20662987456
1965 1763.74460554109 1861.48173377197 1663.88949943374 2936.75667194112 4910.74105906754
1966 1863.0217900557 1967.97692622617 1861.2371253529 3025.15874531047 5266.51556776557
1967 1941.01788335452 2038.4728293501 2105.0097565314 3098.61256354737 5531.61268569588
1968 2024.79664837586 2248.15998417223 2328.76782138117 3315.93345057413 5994.92063017548
1969 2210.3554910333 2463.03628512994 2677.56919037329 3532.39677430988 6484.38905253186
1970 2356.30253096265 3268.39047586185 3000.2052901964 3684.31635066149 6572.50133214989
1971 2462.02054323876 3456.72580265725 3219.60824220332 3746.03700001789 6935.0632951782
1972 2625.38549756437 3720.8910992744 3529.70599218442 3862.88959931525 7419.82829668026
1973 2850.06331499128 3964.07158130782 3819.59304145444 4147.21496424124 7869.61913717681
1974 2992.72951678952 4120.31748824183 3718.94670937432 4031.83331139727 7806.42608648891
1975 2990.05104833774 4086.87556271374 3780.64114979096 3995.09771271013 7851.99627972015
1976 3238.98328335028 4429.57903538868 4012.52117393808 4062.55726826317 8254.40363473754
1977 3397.84531103055 4566.93590248909 4142.23803113506 4141.10020078677 8567.50430495961
1978 3619.0599245056 4824.03886072201 4327.00277708568 4214.42484768636 8776.70812570479
1979 3795.2173965358 5009.16902553303 4504.05555002207 4386.93164117522 8882.25880189287
1980 3882.48817114275 5005.7858120953 4394.94234406171 4161.91674823312 8896.12725166684
1981 3887.50584055149 5034.10481821662 4382.87429191797 4077.50594780159 9026.19701717344
1982 3947.02544578883 5014.17444449605 4332.92374467956 3990.01840833243 8660.28093590691
1983 4150.09342173376 5140.38355357423 4569.39141258457 4036.29601411059 8849.57058149731
1984 4310.91386821727 5387.81346660737 4770.22113047863 4077.4769419301 9333.54746976551
1985 4521.14113980868 5568.81475445417 4895.46307020779 4249.91674072734 9449.64006798395
1986 4772.68765016625 5652.40452181497 4887.88806675552 4370.70460449332 9453.57694049204
1987 4963.83605314389 5797.70919919013 5160.97601086728 4499.13740535983 9788.93805873904
1988 5043.03285765552 5863.14215356514 5418.23102509522 4641.01791574725 10173.8520917196
1989 5196.07042356752 5912.26636067019 5731.86029640761 4717.82228783546 10372.6777783044
1990 5327.99054540446 5733.92107653182 6068.82557532234 4774.14523676643 10530.6404608282
1991 5633.4645757229 5693.68334768533 6236.27577330525 4874.62827764038 10940.8605542074
1992 5758.45205314398 5595.77765308725 6265.54953186446 4864.99786637654 10805.8169480821
1993 5769.47171706743 5498.99911443377 6295.2732251244 4931.89201804955 11041.2566855494
1994 5829.254504912 5449.33241763681 6698.02070471279 4884.089836485 11223.9549517654
1995 5897.04768519378 5526.8800625843 6851.677666734 5045.27058717372 11414.1610137845
1996 6095.35457997074 5598.20210574179 6997.50926861091 5278.55242757754 11601.4732967102
1997 6064.5034684768 5631.07021974947 7130.84000945438 5292.65758796561 11632.9298325583
1998 6243.01512223719 5683.85798260775 7158.89584102466 5348.20589497343 11886.0446403098
1999 6343.89472564915 5769.93612556588 7299.54963683255 5444.15617003737 12067.8674619236
2000 6483.02000982526 5883.347409897 7449.8143548532 5535.37692019088 12396.7906585904
2001 6635.27581179864 6020.33095354454 7308.36846444855 5572.06664011866 12127.7031895495
2002 6567.48598444707 6176.02170406116 7421.93744186528 5565.80673850474 12301.6230550666
2003 6787.46961496467 6225.57938009566 7355.06878457305 5595.79813263903 12290.1729012138
2004 6954.75551828867 6306.30284433621 7560.23366919442 5624.75573474266 12358.6313939039
2005 6971.21237642108 6320.98732922009 7677.52481869722 5733.45486492822 12568.1464588055
2006 7014.2731545905 6380.53841133454 7726.48940896551 5681.63315959885 12476.8413915478
2007 6975.51353289138 6400.97752410663 7935.13081654739 5617.74563144234 12706.6291915765
2008 7075.05262208671 6381.52826600432 7569.38685409214 5605.53909240352 12553.9731019715
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script src="http://d3js.org/d3.v2.js"></script>
<style type="text/css">
body {
font: 300 13px "Helvetica Neue", Helvetica;
}
#chart-container {
width: 1000px;
margin: 0 auto 50px auto;
background: rgba(255,255,255,0.5);
box-shadow: 1px 1px 4px rgba(0,0,0,0.2);
padding: 10px 30px;
}
svg {
font-family: 'Lato', Arial, serif;
font-size: 10px;
font-weight: 700;
text-shadow: 0 1px 1px rgba(255,255,255,0.8);
}
text.country-title {
font-size: 20px;
}
text.instructions {
font-size: 16px;
}
g.context g.brush rect.background {
fill: rgba(0,0,0,.1);
}
g.context g.axis path {
stroke-opacity: 0;
}
g.context g.axis line {
stroke-opacity: .1;
}
g.france path.chart {
fill: rgba(127,201,127,0.5);
}
g.germany path.chart {
fill: rgba(127,201,174,0.5);
}
g.japan path.chart {
fill: rgba(127,183,201,0.5);
}
g.uk path.chart {
fill: rgba(127,130,201,0.5);
}
g.usa path.chart {
fill: rgba(171,127,201,0.5);
}
.axis path, .axis line {
fill: none;
stroke: #aaa;
shape-rendering: crispEdges;
}
.brush .extent {
stroke: #f09f8c;
fill-opacity: .125;
shape-rendering: crispEdges;
}
g.context rect.background{
fill: rgb(200,200,255);
visibility: visible !important;
}
</style>
</head>
<body>
<div id="chart-container">
<script type="text/javascript">
var margin = {top: 10, right: 40, bottom: 150, left: 60},
width = 940 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
contextHeight = 50;
contextWidth = width * .5;
var svg = d3.select("#chart-container").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", (height + margin.top + margin.bottom));
d3.csv('data.csv', createChart);
function createChart(data){
var countries = [];
var charts = [];
var maxDataPoint = 0;
/* Loop through first row and get each country
and push it into an array to use later */
for (var prop in data[0]) {
if (data[0].hasOwnProperty(prop)) {
if (prop != 'Year') {
countries.push(prop);
}
}
};
var countriesCount = countries.length;
var startYear = data[0].Year;
var endYear = data[data.length - 1].Year;
var chartHeight = height * (1 / countriesCount);
/* Let's make sure these are all numbers,
we don't want javaScript thinking it's text
Let's also figure out the maximum data point
We'll use this later to set the Y-Axis scale
*/
data.forEach(function(d) {
for (var prop in d) {
if (d.hasOwnProperty(prop)) {
d[prop] = parseFloat(d[prop]);
if (d[prop] > maxDataPoint) {
maxDataPoint = d[prop];
}
}
}
// D3 needs a date object, let's convert it just one time
d.Year = new Date(d.Year,0,1);
});
for(var i = 0; i < countriesCount; i++){
charts.push(new Chart({
data: data.slice(),
id: i,
name: countries[i],
width: width,
height: height * (1 / countriesCount),
maxDataPoint: maxDataPoint,
svg: svg,
margin: margin,
showBottomAxis: (i == countries.length - 1)
}));
}
/* Let's create the context brush that will
let us zoom and pan the chart */
var contextXScale = d3.time.scale()
.range([0, contextWidth])
.domain(charts[0].xScale.domain());
var contextAxis = d3.svg.axis()
.scale(contextXScale)
.tickSize(contextHeight)
.tickPadding(-10)
.orient("bottom");
var contextArea = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return contextXScale(d.date); })
.y0(contextHeight)
.y1(0);
var brush = d3.svg.brush()
.x(contextXScale)
.on("brush", onBrush);
var context = svg.append("g")
.attr("class","context")
.attr("transform", "translate(" + (margin.left + width * .25) + "," + (height + margin.top + chartHeight - 10) + ")");
context.append("g")
.attr("class", "x axis top")
.attr("transform", "translate(0,0)")
.call(contextAxis)
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", 0)
.attr("height", contextHeight);
context.append("text")
.attr("class","instructions")
.attr("transform", "translate(0," + (contextHeight + 20) + ")")
.text('Click and drag above to zoom / pan the data');
function onBrush(){
/* this will return a date range to pass into the chart object */
var b = brush.empty() ? contextXScale.domain() : brush.extent();
for(var i = 0; i < countriesCount; i++){
charts[i].showOnly(b);
}
}
}
function Chart(options){
this.chartData = options.data;
this.width = options.width;
this.height = options.height;
this.maxDataPoint = options.maxDataPoint;
this.svg = options.svg;
this.id = options.id;
this.name = options.name;
this.margin = options.margin;
this.showBottomAxis = options.showBottomAxis;
var localName = this.name;
/* XScale is time based */
this.xScale = d3.time.scale()
.range([0, this.width])
.domain(d3.extent(this.chartData.map(function(d) { return d.Year; })));
/* YScale is linear based on the maxData Point we found earlier */
this.yScale = d3.scale.linear()
.range([this.height,0])
.domain([0,this.maxDataPoint]);
var xS = this.xScale;
var yS = this.yScale;
/*
This is what creates the chart.
There are a number of interpolation options.
'basis' smooths it the most, however, when working with a lot of data, this will slow it down
*/
this.area = d3.svg.area()
.interpolate("basis")
.x(function(d) { return xS(d.Year); })
.y0(this.height)
.y1(function(d) { return yS(d[localName]); });
/*
This isn't required - it simply creates a mask. If this wasn't here,
when we zoom/panned, we'd see the chart go off to the left under the y-axis
*/
this.svg.append("defs").append("clipPath")
.attr("id", "clip-" + this.id)
.append("rect")
.attr("width", this.width)
.attr("height", this.height);
/*
Assign it a class so we can assign a fill color
And position it on the page
*/
this.chartContainer = svg.append("g")
.attr('class',this.name.toLowerCase())
.attr("transform", "translate(" + this.margin.left + "," + (this.margin.top + (this.height * this.id) + (10 * this.id)) + ")");
/* We've created everything, let's actually add it to the page */
this.chartContainer.append("path")
.data([this.chartData])
.attr("class", "chart")
.attr("clip-path", "url(#clip-" + this.id + ")")
.attr("d", this.area);
this.xAxisTop = d3.svg.axis().scale(this.xScale).orient("bottom");
this.xAxisBottom = d3.svg.axis().scale(this.xScale).orient("top");
/* We only want a top axis if it's the first country */
if(this.id == 0){
this.chartContainer.append("g")
.attr("class", "x axis top")
.attr("transform", "translate(0,0)")
.call(this.xAxisTop);
}
/* Only want a bottom axis on the last country */
if(this.showBottomAxis){
this.chartContainer.append("g")
.attr("class", "x axis bottom")
.attr("transform", "translate(0," + this.height + ")")
.call(this.xAxisBottom);
}
this.yAxis = d3.svg.axis().scale(this.yScale).orient("left").ticks(5);
this.chartContainer.append("g")
.attr("class", "y axis")
.attr("transform", "translate(-15,0)")
.call(this.yAxis);
this.chartContainer.append("text")
.attr("class","country-title")
.attr("transform", "translate(15,40)")
.text(this.name);
}
Chart.prototype.showOnly = function(b){
this.xScale.domain(b);
this.chartContainer.select("path").data([this.chartData]).attr("d", this.area);
this.chartContainer.select(".x.axis.top").call(this.xAxisTop);
this.chartContainer.select(".x.axis.bottom").call(this.xAxisBottom);
}
</script>
</div>
</body>
</html>
@reeganlourduraj
Copy link

Hi, I am very impressed with your sample. Is there any option or way to connect with OLAP data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment