|
//initialize dimensions |
|
var margin = {top: 10, right: 10, bottom: 10, left: 10}, |
|
width = 900 - margin.left - margin.right, |
|
height = 100 - margin.top - margin.bottom |
|
padding = 10; |
|
|
|
//specify a 9-class single-hue sequential color map (colorbrewer2.org) |
|
var colourScale = d3.scale.quantize() |
|
.range(d3.range(9).map(function(d) { return "q" + d + "-9"; })); |
|
|
|
//specify linear scale for time in years |
|
var xScale = d3.scale.linear(); |
|
|
|
//initialize a counter for the number of years |
|
var numYears = 0; |
|
|
|
//load data |
|
d3.csv("indexedstocks.csv", type, function(error, data) { |
|
|
|
//nest the data, faceting by stock name |
|
var names = d3.nest() |
|
.key(function(d) { return d.name; }) |
|
.entries(data); |
|
|
|
//specify the domain of the time scale, from minimum to maximum year |
|
xScale.domain([ |
|
d3.min(names, function(s) { return s.values[0].year; }), |
|
d3.max(names, function(s) { return s.values[s.values.length - 1].year; }) |
|
]); |
|
|
|
//initialize svg container object for each facet |
|
var svg = d3.select("body") |
|
.selectAll("svg") |
|
.data(names) |
|
.enter() |
|
.append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
//group each series into a text label and a series of panels |
|
var series = svg.append("g"); |
|
|
|
//add a label for the stock name to the left of the chart |
|
series.append("text") |
|
.attr("x", padding) |
|
.attr("y", height / 2) |
|
.attr("class", "nameLabel") |
|
.text(function(d) { return d.key}); |
|
|
|
//add a group of tiles containing max, median, and min values |
|
var tileSeries = series.append("g") |
|
.attr("transform", "translate(" + padding + ", " + padding + ")") |
|
.attr("class", "RdSeq9") |
|
.selectAll() |
|
.data(function(d) { |
|
numYears = d.values.length; |
|
return d.values; |
|
}) |
|
.enter(); |
|
|
|
//determine indiviudal panel dimensions based on the number of years |
|
var panelHeight = (height - 2 * padding) / 2; |
|
var panelWidth = (width - 6 * padding) / numYears; |
|
|
|
//specify the range of the time scale to accomodate the width of panels |
|
xScale.range([3 * padding, width - 3 * padding - panelWidth]); |
|
|
|
//map the colour scale to the range of values in the data |
|
colourScale.domain([ |
|
d3.min(data, function(d) { return d.iMinVal; }), |
|
1, |
|
d3.max(data, function(d) { return d.iMaxVal; }) |
|
]); |
|
|
|
//add the tile containing the maximum value for each year |
|
tileSeries.append("rect") |
|
.attr("x", function(d) { |
|
return xScale(d.year); |
|
}) |
|
.attr("width", panelWidth - 1) |
|
.attr("y", 0) |
|
.attr("height", 0.5 * panelHeight - 1) |
|
.attr("class", function(d) { |
|
return colourScale(d.iMaxVal); |
|
}) |
|
.append("title") // tooltip on mouseover |
|
.text(function(d) { |
|
return "Year: " + d.year + "; max: " + Math.round(d.iMaxVal * 100) + "%"; |
|
}); |
|
|
|
centerTile = tileSeries.append("g") |
|
.attr("class", "centerTile"); |
|
|
|
//add the tile containing the median value for each year |
|
centerTile.append("rect") |
|
.attr("x", function(d) { |
|
return xScale(d.year); |
|
}) |
|
.attr("width", panelWidth - 1) |
|
.attr("y", 0.5 * panelHeight) |
|
.attr("height", panelHeight - 1) |
|
.attr("class", function(d) { |
|
return colourScale(d.iMedVal); |
|
}) |
|
.append("title") // tooltip on mouseover |
|
.text(function(d) { |
|
return "Year: " + d.year + "; med: " + Math.round(d.iMedVal * 100) + "%"; |
|
}); |
|
|
|
//add a year label to the median tile |
|
centerTile.append("text") |
|
.attr("x", function(d){ |
|
return xScale(d.year) + 0.5 * panelWidth; |
|
}) |
|
.attr("width", panelWidth) |
|
.attr("height", panelHeight) |
|
.attr("y", panelHeight) |
|
.style("text-anchor", "middle") |
|
.attr("class", "yearLabel") |
|
.text(function(d) { return d.year}) |
|
.append("title") // tooltip on mouseover |
|
.text(function(d) { |
|
return "Year: " + d.year + "; min: " + Math.round(d.iMedVal * 100) + "%"; |
|
}); |
|
|
|
//add the tile and label containing the minimum value for each year |
|
tileSeries.append("rect") |
|
.attr("x", function(d) { |
|
return xScale(d.year); |
|
}) |
|
.attr("width", panelWidth - 1) |
|
.attr("y", 1.5 * panelHeight) |
|
.attr("height", 0.5 * panelHeight - 1) |
|
.attr("class", function(d) { |
|
return colourScale(d.iMinVal); |
|
}) |
|
.append("title") // tooltip on mouseover |
|
.text(function(d) { |
|
return "Year: " + d.year + "; min: " + Math.round(d.iMinVal * 100) + "%"; |
|
}); |
|
|
|
}); |
|
|
|
//coerce data into a numerical format |
|
function type(d) { |
|
d.iMaxVal = +d.iMaxVal; |
|
d.iMedVal = +d.iMedVal; |
|
d.iMinVal = +d.iMinVal; |
|
d.year = +d.year; |
|
return d; |
|
} |