Skip to content

Instantly share code, notes, and snippets.

@galvanic
Last active July 6, 2016 15:59
Show Gist options
  • Select an option

  • Save galvanic/284b254c6fe3a501d8bcc46c95e6f601 to your computer and use it in GitHub Desktop.

Select an option

Save galvanic/284b254c6fe3a501d8bcc46c95e6f601 to your computer and use it in GitHub Desktop.
bar chart for financial data
function TimelineChart() {
// assumptions about the data passed to this chart:
// i.e. dataset of each selection
// list of objects. each object has the following keys:
// chart config
var margin = {top: 20, right: 20, bottom: 20, left: 20}
var width = 960 - margin.left - margin.right
var height = 500 - margin.top - margin.bottom
var chartMiddle = height/2
var offsetFromCentralLine = 4
var xScale = d3.time.scale()
.range([0, width])
var yScale = d3.scale.log()
.range([0, chartMiddle])
function drawChart(selection) {
selection.each(function(dataset, i) {
var wholeChart = this
// update scale domain using dataset metadata
xScale
.domain(d3.extent(dataset, function(d) { return d.date }))
.nice(d3.time.month)
// extent top and bottom must be same for consistency
// so look for the maximum total over the whole period !
var maxTotal = d3.max(dataset, function(d) { return Math.max(Math.abs(d.values.totalNeg), d.values.totalPos) })
yScale
.domain([0.1, maxTotal])
.nice()
//
// Y AXIS
//
// the constructor function for the grid
var yGrid = d3.svg.axis()
.scale(yScale)
.orient('left')
.ticks(1, ',.1')
.innerTickSize(-width)
.outerTickSize(0)
.tickPadding(-width+5)
// the svg items making up the grid
var yGridLines = d3.select(wholeChart)
.append('g')
.classed('y grid', true)
.attr('transform', 'translate(' + margin.left + ',' + (margin.top + chartMiddle + offsetFromCentralLine) + ')')
.call(yGrid)
yGridLines.selectAll('text')
.attr('dy', 0)
.attr('alignment-baseline', 'baseline')
// the svg items making up the grid
var yGridLines = d3.select(wholeChart)
.append('g')
.classed('y grid', true)
.attr('transform', 'translate(' + margin.left + ',' + (margin.top - offsetFromCentralLine) + ')')
.call(yGrid.scale(yScale.copy().range([chartMiddle, 0])))
yGridLines.selectAll('text')
.attr('dy', 0)
.attr('alignment-baseline', 'mathematical')
//
// THE CHART
//
// select chart element(s) (eg. innerchart) if they exist already
var innerchart = d3.select(wholeChart).selectAll('g.innerchart')
.data(function(d) { return [d] })
// otherwise create them and the elements they contain
var innerchartEnter = innerchart.enter()
.append('g')
.classed('innerchart', true)
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
innerchartEnter.append('line')
.attr('x1', 0)
.attr('y1', chartMiddle)
.attr('x2', width)
.attr('y2', chartMiddle)
// update data
var days = innerchart.selectAll('g.day')
.data(function(d) { return d }, function(d) { return d.key })
days.enter()
.append('g')
.classed('day', true)
.attr('transform', function(d) { return 'translate(' + xScale(d.date) + ',' + chartMiddle + ')' })
var negativeTransactions = days.selectAll('rect.transaction.negative')
.data(function(d) { return [d.values.totalNeg] })
negativeTransactions.enter()
.append('rect')
.classed('transaction', true)
.classed('negative', true)
.attr('x', 0)
.attr('y', offsetFromCentralLine)
.attr('width', 2)
.attr('height', 0)
.transition()
.delay(function(d) { return days.data().indexOf(d3.select(this.parentNode).datum()) * 50 })
.duration(1000)
.ease('exp')
.attr('height', function(d) { return (d == 0 ? 0 : yScale(-d)) })
var positiveTransactions = days.selectAll('rect.transaction.positive')
.data(function(d) { return [d.values.totalPos] })
positiveTransactions.enter()
.append('rect')
.classed('transaction', true)
.classed('positive', true)
.attr('x', 0)
.attr('y', -offsetFromCentralLine)
.attr('width', 2)
.attr('height', 0)
.transition()
.delay(function(d) { return days.data().indexOf(d3.select(this.parentNode).datum()) * 50 })
.duration(1000)
.ease('exp')
.attr('height', function(d) { return (d == 0 ? 0 : yScale(d)) })
.attr('y', function(d) { return (d == 0 ? 0 : -yScale(d) -offsetFromCentralLine) })
})
}
return drawChart
}
date value
10/10/2011 -20.00
10/10/2011 -39.84
10/10/2011 -20.00
11/10/2011 -3.25
13/10/2011 -10.00
13/10/2011 -10.00
17/10/2011 -20.00
17/10/2011 -12.40
17/10/2011 -6.99
17/10/2011 -20.00
20/10/2011 -15.00
20/10/2011 -10.00
24/10/2011 -496.20
24/10/2011 -12.40
24/10/2011 -7.00
24/10/2011 -5.19
27/10/2011 -5.00
27/10/2011 -10.93
27/10/2011 -15.00
31/10/2011 -5.00
31/10/2011 -20.00
31/10/2011 -5.57
04/11/2011 -5.00
04/11/2011 -12.40
07/11/2011 -2.20
07/11/2011 -61.89
07/11/2011 -9.78
07/11/2011 -5.25
08/11/2011 -15.51
08/11/2011 -54.85
09/11/2011 -10.00
09/11/2011 -30.00
11/11/2011 -10.58
11/11/2011 -12.40
14/11/2011 -17.00
14/11/2011 -68.00
16/11/2011 -496.20
16/11/2011 -20.00
18/11/2011 32.00
18/11/2011 20.00
18/11/2011 -11.00
21/11/2011 -6.00
21/11/2011 -6.51
21/11/2011 -10.54
21/11/2011 -38.50
22/11/2011 -12.40
25/11/2011 -5.15
28/11/2011 -10.00
28/11/2011 -10.93
28/11/2011 -10.00
28/11/2011 -20.00
30/11/2011 -5.47
30/11/2011 -10.00
02/12/2011 -5.00
05/12/2011 -79.99
05/12/2011 -10.00
05/12/2011 -24.80
05/12/2011 -34.20
08/12/2011 -2.50
09/12/2011 -4.50
09/12/2011 -7.00
12/12/2011 -10.00
12/12/2011 -4.99
12/12/2011 -19.50
12/12/2011 -112.00
15/12/2011 -12.50
15/12/2011 -496.20
19/12/2011 -31.25
19/12/2011 -4.18
19/12/2011 -36.25
19/12/2011 -0.69
19/12/2011 -5.00
28/12/2011 -10.93
30/12/2011 -11.25
03/01/2012 -7.00
09/01/2012 -15.00
09/01/2012 -10.00
09/01/2012 -13.10
11/01/2012 -26.00
16/01/2012 -10.00
18/01/2012 -17.89
19/01/2012 603.00
19/01/2012 35.00
19/01/2012 -50.00
19/01/2012 -38.50
23/01/2012 -4.99
24/01/2012 -10.00
25/01/2012 -2.09
26/01/2012 -30.98
26/01/2012 -10.00
27/01/2012 -10.93
30/01/2012 140.00
30/01/2012 -629.46
30/01/2012 -12.60
02/02/2012 -5.79
06/02/2012 -6.71
07/02/2012 -15.00
08/02/2012 -12.00
13/02/2012 150.00
13/02/2012 -19.99
14/02/2012 -41.05
17/02/2012 -7.40
17/02/2012 -10.00
17/02/2012 -5.20
23/02/2012 600.00
23/02/2012 -38.50
23/02/2012 -10.96
23/02/2012 -20.00
27/02/2012 -506.00
01/03/2012 -5.80
01/03/2012 -20.00
05/03/2012 160.00
05/03/2012 -140.00
05/03/2012 -10.00
05/03/2012 -4.99
06/03/2012 82.00
07/03/2012 -50.00
12/03/2012 -10.00
12/03/2012 -20.00
13/03/2012 -5.00
15/03/2012 -10.00
15/03/2012 -2.90
19/03/2012 600.00
19/03/2012 -516.20
19/03/2012 -12.50
19/03/2012 -15.00
19/03/2012 -2.65
19/03/2012 -20.00
21/03/2012 -20.00
22/03/2012 -10.00
23/03/2012 -9.49
23/03/2012 -24.86
23/03/2012 -8.00
17/04/2012 500.00
17/04/2012 -496.20
26/04/2012 -15.00
27/04/2012 -6.67
27/04/2012 -46.00
30/04/2012 180.00
30/04/2012 -9.16
30/04/2012 -3.50
30/04/2012 -5.11
02/05/2012 -3.74
03/05/2012 -29.32
03/05/2012 -14.99
03/05/2012 -18.00
03/05/2012 -3.50
04/05/2012 -20.00
08/05/2012 -4.49
08/05/2012 -30.00
10/05/2012 -3.25
14/05/2012 160.00
14/05/2012 -20.00
14/05/2012 -52.78
14/05/2012 -30.00
17/05/2012 -3.43
17/05/2012 -5.13
21/05/2012 -6.75
21/05/2012 -20.00
21/05/2012 -10.00
24/05/2012 -6.00
24/05/2012 -5.50
25/05/2012 -8.00
25/05/2012 -15.00
28/05/2012 180.00
28/05/2012 -13.99
28/05/2012 -10.00
28/05/2012 -10.00
28/05/2012 -4.99
01/06/2012 -1.50
06/06/2012 500.00
06/06/2012 -496.20
06/06/2012 -8.98
07/06/2012 -66.70
07/06/2012 -3.50
11/06/2012 -10.00
11/06/2012 -10.50
13/06/2012 -10.00
18/06/2012 500.00
18/06/2012 130.00
18/06/2012 -496.20
18/06/2012 -51.50
19/06/2012 -5.00
19/06/2012 -6.30
19/06/2012 -20.00
22/06/2012 -20.00
25/06/2012 -48.85
26/06/2012 -10.00
27/06/2012 -23.74
29/06/2012 200.00
29/06/2012 -5.34
29/06/2012 -10.00
29/06/2012 -3.50
02/07/2012 -3.50
02/07/2012 -7.50
05/07/2012 -3.50
12/07/2012 -10.00
12/07/2012 -20.00
16/07/2012 700.00
16/07/2012 -496.20
16/07/2012 -187.00
24/07/2012 -67.99
27/07/2012 345.00
30/07/2012 -3.21
20/08/2012 300.00
20/08/2012 -23.61
20/08/2012 -496.20
28/08/2012 -9.06
31/08/2012 575.00
11/09/2012 -90.00
03/10/2012 -4.00
03/01/2012 0.30
05/01/2012 2073.50
19/01/2012 -603.00
30/01/2012 -140.00
13/02/2012 -150.00
23/02/2012 -600.00
05/03/2012 -160.00
19/03/2012 -600.00
02/04/2012 0.48
17/04/2012 -500.00
27/04/2012 2852.50
30/04/2012 -180.00
14/05/2012 -160.00
28/05/2012 -180.00
06/06/2012 -500.00
18/06/2012 -500.00
18/06/2012 -130.00
29/06/2012 -200.00
02/07/2012 0.49
16/07/2012 -700.00
20/08/2012 -300.00
03/09/2012 -199.68
01/10/2012 0.22
01/10/2012 -148.87
<!DOCTYPE html>
<html>
<head>
<title>Visualisation</title>
<link rel='stylesheet' type='text/css' href='style.css'>
<script src='https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js' charset='utf-8'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/chance/1.0.3/chance.min.js' charset='utf-8'></script>
<script src='./chart.js'></script>
<script src='./main.js'></script>
</head>
<body>
<div id='vis'></div>
</body>
</html>
'use strict'
var dataFilepath = 'data.csv'
d3.csv(dataFilepath, cleanCSVdata, drawChart)
//generateData(200, Math.random, drawChart)
function generateData(numDatapoints, seed, callback) {
// GENERATE FAKE DATASET
var chance = new Chance(seed)
var dataset = new Array(numDatapoints)
for (var i = 0; i < numDatapoints; i++) {
dataset[i] = {
date: d3.time.format('%d/%m/%Y').parse(chance.date({string: true, american: false, year: chance.integer({min: 2011, max:2014})}))
, value: chance.floating({min: -1000, max: 1000, fixed: 2})
}
}
document.addEventListener('DOMContentLoaded', function(event) {
callback(dataset)
})
}
function cleanCSVdata(d) {
return {
date: d3.time.format('%d/%m/%Y').parse(d.date)
, value: +d.value
}
}
function drawChart(dataset) {
// PREPARE DATA FOR CHART
// sort by date, order is kept during nesting step
dataset.sort(function(a, b) { return a.date - b.date })
var balanceByDay = d3.nest()
.key(function(d) { return d.date.toDateString() })
.rollup(function(values) {
// get the highest number out of the sum of the positive numbers
// and the sum of the negative numbers
var negativeTransactions = values.filter(function(d) { return d.value < 0 })
var positiveTransactions = values.filter(function(d) { return d.value > 0 })
return {
transactions: values
, negTransactions: negativeTransactions
, posTransactions: positiveTransactions
, totalNeg: d3.sum(negativeTransactions.map(function(d) { return d.value }))
, totalPos: d3.sum(positiveTransactions.map(function(d) { return d.value }))
}
})
.entries(dataset)
balanceByDay.forEach(function(d) { d.date = d.values.transactions[0].date })
// DRAW THE CHART
var svg = d3.select('div#vis')
.append('svg')
.attr('width', 960)
.attr('height', 500)
function draw(dataset) {
// draw chart
var timelines = svg.selectAll('g.timelinechart')
.data(dataset)
timelines.enter()
.append('g')
.classed('timelinechart', true)
timelines
.call(TimelineChart())
timelines.exit()
.remove()
}
draw([balanceByDay])
}
div#vis {
width: 960px;
margin: 0px auto;
}
g.innerchart > line {
stroke: orange;
}
rect.transaction {
fill: grey;
}
rect.transaction.negative {
fill: red;
}
rect.transaction.positive {
fill: green;
}
.grid {
opacity: 0.3;
}
.grid .tick {
stroke: lightgrey;
}
.grid text {
stroke: black;
font-family: monospace;
font-size: 0.9em;
}
.grid path {
stroke-width: 0;
}
.grid .tick:first-child {
display: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment