Built with blockbuilder.org
Created
October 17, 2019 15:47
-
-
Save ShlomoAbraham/4bf81967c7863d6f355c20ece50856b4 to your computer and use it in GitHub Desktop.
fresh block
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: mit |
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> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v2.min.js"></script> | |
<style> | |
.axis path, .axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.line { | |
fill: none; | |
stroke-width: 1.5px; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var perfdata = new Array(); | |
var margin = {top: 20, right: 60, bottom: 60, left: 60}, | |
width = 1000 - margin.right - margin.left, | |
height = 500 - margin.top - margin.bottom; | |
var x = d3.time.scale() | |
.range([0, width - 60]); | |
var y = d3.scale.linear() | |
.range([height - 20, 0]); | |
var duration = 1500, | |
delay = 500; | |
var color = d3.scale.category10(); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.right + margin.left) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var parse = d3.time.format("%m/%d/%Y").parse, format = d3.time.format("%Y"), | |
perfdata = new Array(); | |
var data = { | |
"cDataSet":[ { | |
"date":"12/31/2000", | |
"portfolio":"5.31", | |
"sp500":"9.56" | |
}, | |
{ | |
"date":"12/31/2001", | |
"portfolio":"1.30", | |
"sp500":"6.42" | |
}, | |
{ | |
"date":"12/31/2002", | |
"portfolio":"-6.71", | |
"sp500":"-1.43" | |
}, | |
{ | |
"date":"12/31/2003", | |
"portfolio":"-8.45", | |
"sp500":"1.80" | |
}, | |
{ | |
"date":"12/31/2004", | |
"portfolio":"-5.68", | |
"sp500":"-0.93" | |
}, | |
{ | |
"date":"12/31/2005", | |
"portfolio":"-3.71", | |
"sp500":"-8.07" | |
}, | |
{ | |
"date":"12/31/2006", | |
"portfolio":"9.92", | |
"sp500":"-0.241" | |
}, | |
{ | |
"date":"12/31/2007", | |
"portfolio":"1.16", | |
"sp500":"-9.70" | |
}, | |
{ | |
"date":"12/31/2008", | |
"portfolio":"7.22", | |
"sp500":"9.64" | |
}, | |
{ | |
"date":"12/31/2009", | |
"portfolio":"-6.34", | |
"sp500":"-7.29" | |
}, | |
{ | |
"date":"12/31/2010", | |
"portfolio":"-8.99", | |
"sp500":"-2.66" | |
}, | |
{ | |
"date":"12/31/2011", | |
"portfolio":"4.36", | |
"sp500":"-2.92" | |
} | |
] | |
} | |
</script> | |
<script> | |
var inc = 0; | |
data = data.cDataSet; | |
var cumul = new Array(); | |
for (key in data[0]) { | |
if ( key != "date" ) { | |
cumul[key] = 1; | |
firstdate = parse(data[0].date); | |
firstdate.setFullYear(firstdate.getFullYear()-1); | |
perfdata[inc] = { date: firstdate, perf : 0, cumul : cumul[key], symbol : key }; | |
inc = inc + 1; | |
} | |
} | |
data.forEach( function(d) { | |
for (key in d) { | |
if ( key != "date" ) { | |
cumul[key] = cumul[key] * (1 + parseFloat(d[key]) / 100); | |
perfdata[inc] = { date: parse(d.date) , perf : parseFloat(d[key]), cumul : cumul[key], symbol : key }; | |
inc = inc + 1; | |
} | |
}; | |
}); | |
//if we want to filter only some set of what is there | |
//stocks = perfdata.filter(function(d) { return d.symbol in filter; }); | |
// Nest stock values by symbol. | |
symbols = d3.nest() | |
.key(function(d) { return d.symbol; }) | |
.entries(perfdata); | |
// Parse dates and numbers. We assume values are sorted by date. | |
// Also compute the maximum price per symbol, needed for the y-domain. | |
//symbols.forEach(function(s) { | |
// s.values.forEach(function(d) { d.date = parse(d.date); d.price = +d.price; }); | |
//}); | |
// Sort by maximum price, descending. | |
//symbols.sort(function(a, b) { return b.maxPrice - a.maxPrice; }); | |
// Compute the minimum and maximum date across symbols. | |
x.domain([ | |
d3.min(symbols, function(d) { return d.values[0].date; }), | |
d3.max(symbols, function(d) { return d.values[d.values.length - 1].date; }) | |
]); | |
var g = svg.selectAll("g") | |
.data(symbols) | |
.enter().append("g") | |
.attr("class", "symbol"); | |
groupedBar(); | |
setTimeout(clearBar, duration + delay); | |
function clearBar() { | |
svg.selectAll("text").transition() | |
.duration(duration/2) | |
.remove(); | |
svg.selectAll(".y.axis").transition() | |
.duration(duration/2) | |
.remove(); | |
svg.selectAll("rect").transition() | |
.duration(duration) | |
.style("fill-opacity", 1e-6) | |
.remove(); | |
} | |
setTimeout(cumulLine, duration * 2 + delay); | |
function groupedBar() { | |
x = d3.scale.ordinal() | |
.domain(symbols[0].values.map(function(d) { return d.date; })) | |
.rangeBands([0, width - 60], .1); | |
var x1 = d3.scale.ordinal() | |
.domain(symbols.map(function(d) { return d.key; })) | |
.rangeBands([0, x.rangeBand()]); | |
var y0 = Math.max(Math.abs(d3.min(symbols.map(function(d) { return d3.min(d.values.map(function(d) { return d.perf; })); }))), d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.perf; })); }))); | |
y | |
.domain([-y0, y0]) | |
//.domain([d3.min(symbols.map(function(d) { return d3.min(d.values.map(function(d) { return d.perf; })); })), d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.perf; })); }))]) | |
.range([height, 0]) | |
.nice(); | |
var yAxis = d3.svg.axis().scale(y).orient("left"); | |
svg.selectAll(".labels") | |
.data(symbols[0].values.map(function(d) { return d.date; })) | |
.enter().append("text") | |
.attr("class", "labels") | |
.attr("text-anchor", "middle") | |
.attr("x", function(d,i) { return x(i) + x.rangeBand() / 2 ; }) | |
.attr("y", height / 2 + 15) | |
.text(function(d) {return format(d) }) | |
.style("fill-opacity", 1); | |
var g = svg.selectAll(".symbol"); | |
var t = g.transition() | |
.duration(duration); | |
//got working with lots of help but this section particularly dedicated to http://stackoverflow.com/questions/10127402/bar-chart-with-negative-values | |
g.each(function(p, j) { | |
d3.select(this).selectAll("rect") | |
.data(function(d) { return d.values; }) | |
.enter().append("rect") | |
.attr("x", function(d) { return x(d.date) + x1(p.key); }) | |
.attr("y", function(d, i) { return y(Math.max(0, d.perf)); }) | |
//.attr("y", function(d) { return y(d.perf); }) | |
.attr("width", x1.rangeBand()) | |
.attr("height", function(d, i) { return Math.abs(y(d.perf) - y(0)); }) | |
//.attr("height", function(d) { return height - y(d.perf); }) | |
.style("fill", color(p.key)) | |
.style("fill-opacity", 1e-6) | |
.transition() | |
.duration(duration) | |
.style("fill-opacity", 1); | |
d3.select(this).selectAll("text") | |
.data(function(d) { return d.values; }) | |
.enter().append("text") | |
.attr("x", function(d) { return x(d.date) + x1(p.key) + x1.rangeBand() / 2 ; }) | |
.attr("y", function(d, i) { return y(d.perf) ; }) | |
.attr("text-anchor", "middle") | |
.text(function(d) { return d.perf; }) | |
.style("fill-opacity", 1e-6) | |
.transition() | |
.duration(duration) | |
.style("fill-opacity", 1); | |
}); | |
//svg.append("g") | |
// .attr("class", "x axis") | |
// .call(d3.svg.axis().scale(x).orient("bottom")); | |
svg.append("g") | |
.attr("class", "y axis") | |
.call(yAxis); | |
// .attr("y1", 0) | |
// .attr("y2", height); | |
} | |
function cumulLine() { | |
x = d3.time.scale() | |
.domain([perfdata[0].date, perfdata[perfdata.length - 1].date]) | |
.range([0,width]) | |
var y0 = d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.cumul; })); })); | |
y | |
.domain([d3.min(symbols.map(function(d) { return d3.min(d.values.map(function(d) { return d.cumul; })); })), | |
d3.max(symbols.map(function(d) { return d3.max(d.values.map(function(d) { return d.cumul; })); }))]) | |
.range([height, 0]) | |
.nice(); | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.ticks(d3.time.years, 1) | |
.tickSubdivide(data.length-1) | |
.tickValues([parse("12/31/1999"),parse("12/31/2011")]) | |
.tickFormat(d3.time.format("%b %Y")); | |
var yAxis = d3.svg.axis().scale(y).orient("left"); | |
// Add the x-axis. | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + y(1) + ")") | |
.call(xAxis); | |
// Add the y-axis. | |
svg.append("g") | |
.attr("class", "y axis") | |
//.attr("transform", "translate(" + width + ",0)") | |
.call(yAxis); | |
var line = d3.svg.line() | |
.x(function (d) {return x(d.date);}) | |
.y(function (d) {return y(d.cumul);}); | |
var g = svg.selectAll(".symbol"); | |
g.each(function(p) { | |
var thispath = d3.select(this) | |
.append("path") | |
.attr("class", "line") | |
.style("stroke", color(p.key)); | |
var k = 0, n = symbols[0].values.length; | |
d3.timer( function() { | |
thispath | |
.transition() | |
.attr("d", function() { return line(p.values.slice(0, k + 1)); }); | |
k = k + 1; | |
if (k == n) return true; | |
}); | |
d3.select(this).selectAll(".dot") | |
.data(function(d) { return d.values; }) | |
.enter().append("circle") | |
.attr("class", "dot") | |
.attr("cx", line.x()) | |
.attr("cy", line.y()) | |
.attr("r", 3.5) | |
.style("fill", color(p.key)); | |
}) | |
}; | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment