Skip to content

Instantly share code, notes, and snippets.

@PMeinshausen
Created August 21, 2013 16:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PMeinshausen/6296411 to your computer and use it in GitHub Desktop.
Save PMeinshausen/6296411 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://d3js.org/d3.v2.js"></script>
<style type="text/css">
svg {
font-family: "Helvetica Neue", Helvetica;
}
.line {
fill: none;
stroke: #000;
stroke-width: 2px;
}
</style>
</head>
<body>
<script type="text/javascript">
var m = [20, 20, 30, 20],
w = 960 - m[1] - m[3],
h = 500 - m[0] - m[2];
var x,
y,
duration = 1500,
delay = 500;
var color = d3.scale.category10();
var svg = d3.select("body").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
var stocks,
symbols;
// A line generator, for the dark stroke.
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
// A line generator, for the dark stroke.
var axis = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(h);
// A area generator, for the dark stroke.
var area = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y1(function(d) { return y(d.price); });
d3.csv("stocks.csv", function(data) {
var parse = d3.time.format("%b %Y").parse;
// Nest stock values by symbol.
symbols = d3.nest()
.key(function(d) { return d.symbol; })
.entries(stocks = data);
// 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; });
s.maxPrice = d3.max(s.values, function(d) { return d.price; });
s.sumPrice = d3.sum(s.values, function(d) { return d.price; });
});
// Sort by maximum price, descending.
symbols.sort(function(a, b) { return b.maxPrice - a.maxPrice; });
var g = svg.selectAll("g")
.data(symbols)
.enter().append("svg:g")
.attr("class", "symbol");
setTimeout(lines, duration);
});
function lines() {
x = d3.time.scale().range([0, w - 60]);
y = d3.scale.linear().range([h / 4 - 20, 0]);
// 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(".symbol")
.attr("transform", function(d, i) { return "translate(0," + (i * h / 4 + 10) + ")"; });
g.each(function(d) {
var e = d3.select(this);
e.append("svg:path")
.attr("class", "line");
e.append("svg:circle")
.attr("r", 5)
.style("fill", function(d) { return color(d.key); })
.style("stroke", "#000")
.style("stroke-width", "2px");
e.append("svg:text")
.attr("x", 12)
.attr("dy", ".31em")
.text(d.key);
});
function draw(k) {
g.each(function(d) {
var e = d3.select(this);
y.domain([0, d.maxPrice]);
e.select("path")
.attr("d", function(d) { return line(d.values.slice(0, k + 1)); });
e.selectAll("circle, text")
.data(function(d) { return [d.values[k], d.values[k]]; })
.attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.price) + ")"; });
});
}
var k = 1, n = symbols[0].values.length;
d3.timer(function() {
draw(k);
if ((k += 2) >= n - 1) {
draw(n - 1);
setTimeout(horizons, 500);
return true;
}
});
}
function horizons() {
svg.insert("svg:defs", ".symbol")
.append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", w)
.attr("height", h / 4 - 20);
var color = d3.scale.ordinal()
.range(["#c6dbef", "#9ecae1", "#6baed6"]);
var g = svg.selectAll(".symbol")
.attr("clip-path", "url(#clip)");
area
.y0(h / 4 - 20);
g.select("circle").transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (-h / 4) + ")"; })
.remove();
g.select("text").transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + (w - 60) + "," + (h / 4 - 20) + ")"; })
.attr("dy", "0em");
g.each(function(d) {
y.domain([0, d.maxPrice]);
d3.select(this).selectAll(".area")
.data(d3.range(3))
.enter().insert("svg:path", ".line")
.attr("class", "area")
.attr("transform", function(d) { return "translate(0," + (d * (h / 4 - 20)) + ")"; })
.attr("d", area(d.values))
.style("fill", function(d, i) { return color(i); })
.style("fill-opacity", 1e-6);
y.domain([0, d.maxPrice / 3]);
d3.select(this).selectAll(".line").transition()
.duration(duration)
.attr("d", line(d.values))
.style("stroke-opacity", 1e-6);
d3.select(this).selectAll(".area").transition()
.duration(duration)
.style("fill-opacity", 1)
.attr("d", area(d.values))
.each("end", function() { d3.select(this).style("fill-opacity", null); });
});
setTimeout(areas, duration + delay);
}
function areas() {
var g = svg.selectAll(".symbol");
axis
.y(h / 4 - 21);
g.select(".line")
.attr("d", function(d) { return axis(d.values); });
g.each(function(d) {
y.domain([0, d.maxPrice]);
d3.select(this).select(".line").transition()
.duration(duration)
.style("stroke-opacity", 1)
.each("end", function() { d3.select(this).style("stroke-opacity", null); });
d3.select(this).selectAll(".area")
.filter(function(d, i) { return i; })
.transition()
.duration(duration)
.style("fill-opacity", 1e-6)
.attr("d", area(d.values))
.remove();
d3.select(this).selectAll(".area")
.filter(function(d, i) { return !i; })
.transition()
.duration(duration)
.style("fill", color(d.key))
.attr("d", area(d.values));
});
svg.select("defs").transition()
.duration(duration)
.remove();
g.transition()
.duration(duration)
.each("end", function() { d3.select(this).attr("clip-path", null); });
setTimeout(stackedArea, duration + delay);
}
function stackedArea() {
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse");
stack(symbols);
y
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
.range([h, 0]);
line
.y(function(d) { return y(d.price0); });
area
.y0(function(d) { return y(d.price0); })
.y1(function(d) { return y(d.price0 + d.price); });
var t = svg.selectAll(".symbol").transition()
.duration(duration)
.attr("transform", "translate(0,0)")
.each("end", function() { d3.select(this).attr("transform", null); });
t.select("path.area")
.attr("d", function(d) { return area(d.values); });
t.select("path.line")
.style("stroke-opacity", function(d, i) { return i < 3 ? 1e-6 : 1; })
.attr("d", function(d) { return line(d.values); });
t.select("text")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
setTimeout(streamgraph, duration + delay);
}
function streamgraph() {
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse")
.offset("wiggle");
stack(symbols);
line
.y(function(d) { return y(d.price0); });
var t = svg.selectAll(".symbol").transition()
.duration(duration);
t.select("path.area")
.attr("d", function(d) { return area(d.values); });
t.select("path.line")
.style("stroke-opacity", 1e-6)
.attr("d", function(d) { return line(d.values); });
t.select("text")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
setTimeout(overlappingArea, duration + delay);
}
function overlappingArea() {
var g = svg.selectAll(".symbol");
line
.y(function(d) { return y(d.price0 + d.price); });
g.select(".line")
.attr("d", function(d) { return line(d.values); });
y
.domain([0, d3.max(symbols.map(function(d) { return d.maxPrice; }))])
.range([h, 0]);
area
.y0(h)
.y1(function(d) { return y(d.price); });
line
.y(function(d) { return y(d.price); });
var t = g.transition()
.duration(duration);
t.select(".line")
.style("stroke-opacity", 1)
.attr("d", function(d) { return line(d.values); });
t.select(".area")
.style("fill-opacity", .5)
.attr("d", function(d) { return area(d.values); });
t.select("text")
.attr("dy", ".31em")
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price) + ")"; });
svg.append("svg:line")
.attr("class", "line")
.attr("x1", 0)
.attr("x2", w - 60)
.attr("y1", h)
.attr("y2", h)
.style("stroke-opacity", 1e-6)
.transition()
.duration(duration)
.style("stroke-opacity", 1);
setTimeout(groupedBar, duration + delay);
}
function groupedBar() {
x = d3.scale.ordinal()
.domain(symbols[0].values.map(function(d) { return d.date; }))
.rangeBands([0, w - 60], .1);
var x1 = d3.scale.ordinal()
.domain(symbols.map(function(d) { return d.key; }))
.rangeBands([0, x.rangeBand()]);
var g = svg.selectAll(".symbol");
var t = g.transition()
.duration(duration);
t.select(".line")
.style("stroke-opacity", 1e-6)
.remove();
t.select(".area")
.style("fill-opacity", 1e-6)
.remove();
g.each(function(p, j) {
d3.select(this).selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("svg:rect")
.attr("x", function(d) { return x(d.date) + x1(p.key); })
.attr("y", function(d) { return y(d.price); })
.attr("width", x1.rangeBand())
.attr("height", function(d) { return h - y(d.price); })
.style("fill", color(p.key))
.style("fill-opacity", 1e-6)
.transition()
.duration(duration)
.style("fill-opacity", 1);
});
setTimeout(stackedBar, duration + delay);
}
function stackedBar() {
x.rangeRoundBands([0, w - 60], .1);
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; })
.order("reverse");
var g = svg.selectAll(".symbol");
stack(symbols);
y
.domain([0, d3.max(symbols[0].values.map(function(d) { return d.price + d.price0; }))])
.range([h, 0]);
var t = g.transition()
.duration(duration / 2);
t.select("text")
.delay(symbols[0].values.length * 10)
.attr("transform", function(d) { d = d.values[d.values.length - 1]; return "translate(" + (w - 60) + "," + y(d.price / 2 + d.price0) + ")"; });
t.selectAll("rect")
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d.price0 + d.price); })
.attr("height", function(d) { return h - y(d.price); })
.each("end", function() {
d3.select(this)
.style("stroke", "#fff")
.style("stroke-opacity", 1e-6)
.transition()
.duration(duration / 2)
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.style("stroke-opacity", 1);
});
setTimeout(transposeBar, duration + symbols[0].values.length * 10 + delay);
}
function transposeBar() {
x
.domain(symbols.map(function(d) { return d.key; }))
.rangeRoundBands([0, w], .2);
y
.domain([0, d3.max(symbols.map(function(d) { return d3.sum(d.values.map(function(d) { return d.price; })); }))]);
var stack = d3.layout.stack()
.x(function(d, i) { return i; })
.y(function(d) { return d.price; })
.out(function(d, y0, y) { d.price0 = y0; });
stack(d3.zip.apply(null, symbols.map(function(d) { return d.values; }))); // transpose!
var g = svg.selectAll(".symbol");
var t = g.transition()
.duration(duration / 2);
t.selectAll("rect")
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d.price0 + d.price) - 1; })
.attr("height", function(d) { return h - y(d.price) + 1; })
.attr("x", function(d) { return x(d.symbol); })
.attr("width", x.rangeBand())
.style("stroke-opacity", 1e-6);
t.select("text")
.attr("x", 0)
.attr("transform", function(d) { return "translate(" + (x(d.key) + x.rangeBand() / 2) + "," + h + ")"; })
.attr("dy", "1.31em")
.each("end", function() { d3.select(this).attr("x", null).attr("text-anchor", "middle"); });
svg.select("line").transition()
.duration(duration)
.attr("x2", w);
setTimeout(donut, duration / 2 + symbols[0].values.length * 10 + delay);
}
function donut() {
var g = svg.selectAll(".symbol");
g.selectAll("rect").remove();
var pie = d3.layout.pie()
.value(function(d) { return d.sumPrice; });
var arc = d3.svg.arc();
g.append("svg:path")
.style("fill", function(d) { return color(d.key); })
.data(function() { return pie(symbols); })
.transition()
.duration(duration)
.tween("arc", arcTween);
g.select("text").transition()
.duration(duration)
.attr("dy", ".31em");
svg.select("line").transition()
.duration(duration)
.attr("y1", 2 * h)
.attr("y2", 2 * h)
.remove();
function arcTween(d) {
var path = d3.select(this),
text = d3.select(this.parentNode.appendChild(this.previousSibling)),
x0 = x(d.data.key),
y0 = h - y(d.data.sumPrice);
return function(t) {
var r = h / 2 / Math.min(1, t + 1e-3),
a = Math.cos(t * Math.PI / 2),
xx = (-r + (a) * (x0 + x.rangeBand()) + (1 - a) * (w + h) / 2),
yy = ((a) * h + (1 - a) * h / 2),
f = {
innerRadius: r - x.rangeBand() / (2 - a),
outerRadius: r,
startAngle: a * (Math.PI / 2 - y0 / r) + (1 - a) * d.startAngle,
endAngle: a * (Math.PI / 2) + (1 - a) * d.endAngle
};
path.attr("transform", "translate(" + xx + "," + yy + ")");
path.attr("d", arc(f));
text.attr("transform", "translate(" + arc.centroid(f) + ")translate(" + xx + "," + yy + ")rotate(" + ((f.startAngle + f.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
};
}
setTimeout(donutExplode, duration + delay);
}
function donutExplode() {
var r0a = h / 2 - x.rangeBand() / 2,
r1a = h / 2,
r0b = 2 * h - x.rangeBand() / 2,
r1b = 2 * h,
arc = d3.svg.arc();
svg.selectAll(".symbol path")
.each(transitionExplode);
function transitionExplode(d, i) {
d.innerRadius = r0a;
d.outerRadius = r1a;
d3.select(this).transition()
.duration(duration / 2)
.tween("arc", tweenArc({
innerRadius: r0b,
outerRadius: r1b
}));
}
function tweenArc(b) {
return function(a) {
var path = d3.select(this),
text = d3.select(this.nextSibling),
i = d3.interpolate(a, b);
for (var key in b) a[key] = b[key]; // update data
return function(t) {
var a = i(t);
path.attr("d", arc(a));
text.attr("transform", "translate(" + arc.centroid(a) + ")translate(" + w / 2 + "," + h / 2 +")rotate(" + ((a.startAngle + a.endAngle) / 2 + 3 * Math.PI / 2) * 180 / Math.PI + ")");
};
}
}
setTimeout(function() {
svg.selectAll("*").remove();
svg.selectAll("g").data(symbols).enter().append("svg:g").attr("class", "symbol");
lines();
}, duration);
}
</script>
</body>
</html>
symbol date price
CHI Apr 2010 126.8659963002
CHI May 2010 126.8659963002
CHI Jun 2010 126.8659963002
CHI Jul 2010 126.8659963002
CHI Aug 2010 126.8659963002
CHI Sep 2010 126.8659963002
CHI Oct 2010 126.8659963002
CHI Nov 2010 126.8659963002
CHI Dec 2010 173.5797005788
CHI Jan 2011 188.2889592831
CHI Feb 2011 188.2889592831
CHI Mar 2010 188.2889592831
CHI Apr 2011 207.226549606
CHI May 2011 233.0311911067
CHI Jun 2011 270.6258297059
CHI Jul 2011 294.0399938883
CHI Aug 2011 431.8010990262
CHI Sep 2011 1037.2307429256
CHI Oct 2011 1081.0350248906
CHI Nov 2011 1140.5741342059
CHI Dec 2011 1178.1274376776
CHI Jan 2012 1220.9153724328
CHI Feb 2012 1265.2391945055
CHI Mar 2012 1290.6412613104
CHI Apr 2012 1313.1776854442
CHI May 2012 1350.4821529597
CHI Jun 2012 1402.782779644
CHI Jul 2012 1407.5101674627
CHI Aug 2012 1429.1396275043
CHI Sep 2012 1483.5178369498
CHI Oct 2012 1529.5571373459
CHI Nov 2012 1553.7779422689
CHI Dec 2012 1553.7779422689
CHI Jan 2013 1589.0081418409
CHI Feb 2013 1604.0095802682
CHI Mar 2013 1652.893796028
CHI Apr 2013 1685.9906940205
CHI May 2013 1685.9906940205
CHI Jun 2013 1689.1687478509
CHI Jul 2013 1698.8100911148
NYC Apr 2010 0
NYC May 2010 0
NYC Jun 2010 0
NYC Jul 2010 0
NYC Aug 2010 0
NYC Sep 2010 0
NYC Oct 2010 0
NYC Nov 2010 8.0743376941
NYC Dec 2010 0
NYC Jan 2011 0
NYC Feb 2011 0
NYC Mar 2010 0
NYC Apr 2011 0
NYC May 2011 0
NYC Jun 2011 0
NYC Jul 2011 150.7730612956
NYC Aug 2011 432.4193866625
NYC Sep 2011 1126.8123844596
NYC Oct 2011 2328.9158406868
NYC Nov 2011 2328.9158406868
NYC Dec 2011 2338.5255610232
NYC Jan 2012 2338.5255610232
NYC Feb 2012 2338.5255610232
NYC Mar 2012 2338.5255610232
NYC Apr 2012 2338.5255610232
NYC May 2012 2338.5255610232
NYC Jun 2012 2338.5255610232
NYC Jul 2012 2338.5255610232
NYC Aug 2012 2338.5255610232
NYC Sep 2012 2338.5255610232
NYC Oct 2012 2338.5255610232
NYC Nov 2012 2338.5255610232
NYC Dec 2012 2338.5255610232
NYC Jan 2013 2338.5255610232
NYC Feb 2013 2338.5255610232
NYC Mar 2013 2338.5255610232
NYC Apr 2013 2338.5255610232
NYC May 2013 2338.5255610232
NYC Jun 2013 2338.5255610232
NYC Jul 2013 2338.5255610232
SF Apr 2010 0
SF May 2010 0
SF Jun 2010 0
SF Jul 2010 0
SF Aug 2010 0
SF Sep 2010 0
SF Oct 2010 0
SF Nov 2010 0
SF Dec 2010 0
SF Jan 2011 0
SF Feb 2011 0
SF Mar 2010 0
SF Apr 2011 0
SF May 2011 0
SF Jun 2011 0
SF Jul 2011 0
SF Aug 2011 0
SF Sep 2011 19.7863809641
SF Oct 2011 33.3985273135
SF Nov 2011 174.1379504399
SF Dec 2011 174.1379504399
SF Jan 2012 235.62949807
SF Feb 2012 245.9697232739
SF Mar 2012 276.1265852729
SF Apr 2012 473.8054557427
SF May 2012 487.7369584002
SF Jun 2012 509.8198424182
SF Jul 2012 526.5949030994
SF Aug 2012 547.807575113
SF Sep 2012 678.1710490137
SF Oct 2012 678.1710490137
SF Nov 2012 698.7855290866
SF Dec 2012 698.7855290866
SF Jan 2013 705.3479731803
SF Feb 2013 713.5144734995
SF Mar 2013 722.5739909817
SF Apr 2013 755.8330690876
SF May 2013 806.6117933518
SF Jun 2013 829.9099846588
SF Jul 2013 842.7536336337
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment