Skip to content

Instantly share code, notes, and snippets.

@lgrammel
Created February 28, 2012 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lgrammel/1935509 to your computer and use it in GitHub Desktop.
Save lgrammel/1935509 to your computer and use it in GitHub Desktop.
Streamgraph Chart
button {
font: 14px Helvetica Neue;
background-color: #222;
background-image: -moz-linear-gradient(top, rgba(255,255,255,.25), rgba(255,255,255,.11));
background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, rgba(255,255,255,.25)),color-stop(1, rgba(255,255,255,.11)));
background-image: -webkit-linear-gradient(rgba(255,255,255,.25), rgba(255,255,255,.11));
color: #fff;
text-rendering: optimizeLegibility;
text-shadow: 0 -1px 1px #222;
padding: 6px 10px 6px 10px;
border: 0;
border-radius: 0;
border-bottom: 1px solid #222;
margin: 0;
-moz-box-shadow: 0 1px 3px #999;
-webkit-box-shadow: 0 1px 3px #999;
}
button.first {
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
button.last {
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
button.active {
background-color: rgb(65,102,133);
}
button:hover {
background-color: steelblue;
}
<!DOCTYPE html>
<html>
<head>
<title>Streamgraph</title>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.js?2.8.0"></script>
<link type="text/css" rel="stylesheet" href="button.css"/>
<script type="text/javascript" src="stream_layers.js"></script>
<script type="text/javascript" src="stream-chart.js"></script>
</head>
<body>
<div id="chart">
<button class="first last" onclick="transition()">
Update
</button><p>
</div>
<script>
var n = 20, // number of layers
m = 200; // number of samples per layer
var data1 = stream_layers(n, m);
var data0 = stream_layers(n, m);
var colors = d3.range(n).map(function() { return d3.interpolateRgb("#aad", "#556")(Math.random()); });
var streamgraph = streamgraphChart()
.margin({top: 10, right: 10, bottom: 10, left: 10})
.color(function(d, i) { return colors[i]; }) // use same colors for both data sets
.transitionDuration(1500);
d3.select("#chart")
.datum(data0)
.call(streamgraph);
function transition() {
d3.select("#chart")
.datum(function() {
var d = data1;
data1 = data0;
return data0 = d;
})
.call(streamgraph);
}
</script>
</body>
</html>
function streamgraphChart() {
var margin = {top: 0, right: 0, bottom: 0, left: 0},
width = 960,
height = 500,
transitionDuration = 1000,
color = function() { return d3.interpolateRgb("#aad", "#556")(Math.random()); };
var streamgraph = d3.layout.stack().offset("wiggle");
function chart(selection) {
selection.each(function(data) {
// Compute the streamgraph.
data = streamgraph(data);
var mx = data[0].length - 1, // assumes that all layers have same # of samples & that there is at least one layer
my = d3.max(data, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y;
});
});
// Select the svg element, if it exists.
var svg = d3.select(this).selectAll("svg").data([data]);
// Otherwise, create the skeletal chart.
var gEnter = svg.enter().append("svg").append("g");
// Update the outer dimensions.
svg .attr("width", width)
.attr("height", height);
// Update the inner dimensions.
var g = svg.select("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Update the streamgraph
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom;
var area = d3.svg.area()
.x(function(d) { return d.x * availableWidth / mx; })
.y0(function(d) { return availableHeight - d.y0 * availableHeight / my; })
.y1(function(d) { return availableHeight - (d.y + d.y0) * availableHeight / my; });
var path = g.selectAll("path").data(data);
path.enter().append("path");
path.exit().remove();
path.style("fill", color).transition().duration(transitionDuration).attr("d", area);
});
}
chart.color = function(_) {
if (!arguments.length) return color;
color = _;
return chart;
};
chart.transitionDuration = function(_) {
if (!arguments.length) return transitionDuration;
transitionDuration = _;
return chart;
};
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
return chart;
}
/* Inspired by Lee Byron's test data generator. */
function stream_layers(n, m, o) {
if (arguments.length < 3) o = 0;
function bump(a) {
var x = 1 / (.1 + Math.random()),
y = 2 * Math.random() - .5,
z = 10 / (.1 + Math.random());
for (var i = 0; i < m; i++) {
var w = (i / m - y) * z;
a[i] += x * Math.exp(-w * w);
}
}
return d3.range(n).map(function() {
var a = [], i;
for (i = 0; i < m; i++) a[i] = o + o * Math.random();
for (i = 0; i < 5; i++) bump(a);
return a.map(stream_index);
});
}
function stream_index(d, i) {
return {x: i, y: Math.max(0, d)};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment